Skip to content

Instantly share code, notes, and snippets.

@tpmccallum
Last active April 13, 2019 03:33
Show Gist options
  • Save tpmccallum/b91a982f980ffb7b51076b58b35516ac to your computer and use it in GitHub Desktop.
Save tpmccallum/b91a982f980ffb7b51076b58b35516ac to your computer and use it in GitHub Desktop.
A design patter which allows big integers to be deconstructed into much smaller data types

Update: This idea has been moved to this GitHub repo for further development

A design pattern to deconstruct (big) blockchain integers such as uint256

This is a design which can be implemented in any language which supports modulo arithmetic and exponentiation (i.e. Python and even Solidity).

Function logic(psuedo code) to obtain any digit[s] from a uint256

((_value % (10 ** _position)) - (_value % (10 ** (_position - _size)))) / (10 ** (_position - _size));

Here are the descriptions for the pattern's arguments

Function arguments(inputs)

  • _value is the big integer (uint256) which has a range from 0 to 2**256-1
  • _position is the single digit position (from within _value) from where you would like to begin the extraction
  • _size is the amount of digits which you would like to extract from _value

Here is an example of the pattern, written in solidity

contract uintTool {
    function getInt(uint256 _value, uint256 _position, uint256 _size) public pure returns(uint256){
        uint256 a = ((_value % (10 ** _position)) - (_value % (10 ** (_position - _size)))) / (10 ** (_position - _size));
        return a;
    }
}

Example input/output part I

Using previous _value example of 1011022033044055066:

  • _position 19 and _size 1 will return 1

At present, this design only extracts based on position and size This is useful for extracting specific characters/digits from the value, as demonstrated in the following section. This creates an opportunity to potentially use uint256 in new ways.

Example input/output part II

This section is just used to exercise the design pattern's abilities to retrieve values from a big integer. For example, using the following fictitious value (_value = 20190404002345671103045555602345605676) the following points are true:

  • _position 2 and _size 2 will return 76
  • _position 15 and _size 3 will return 555
  • _position 38 and _size 4 will return 2019
  • _position 34 and _size 2 will return 04
  • _position 32 and _size 2 will return 04
  • _position 38 and _size 19 will return the left half (2019040400234567110) of this particular _value
  • _position 19 and _size 19 will return the right half (3045555602345605676) of this particular _value

Converting currency units

The next stage of development is to enable the code to derive (from wie) any of the official Ethereum currency units (Grand, Ether, Finney, Szabo, Shannon)[1].

Why this is useful

Some systems, like search-engine/indexing software solutions (which are built using programming languages that do not support blockchain big integer data types) are only able to store these big integers as strings. Deconstructing the big integer values into smaller data types, allows the values to be stored as integers (not strings). This is useful because integers respond to logical operators and arithmetic.

The following code converts a big integer like uint256 to a smaller, but explicit, currency unit (Ether, Finney, Szabo). This allows big integers to be broken down into smaller integers so that they can then be stored as smaller data types & used in other systems which only support these smaller data types. For example deconstructing a blockchain uint256 to be stored in a Rust u64 variable or perhaps a C++ unsigned short int.

pragma lity ^1.2.7;

contract uintTool {
    event logWholeEther(uint256 wholeEther);
    event logWholeFinney(uint256 wholeFinney);
    event logWholeSzabo(uint256 wholeSzabo);
    
    function getInt(uint256 _value, uint256 _position) private pure returns(uint256){
        uint256 a = (_value / (10 ** _position));
        return a;
    }
    function getWholeMega(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 24);
        emit logWholeEther(result);
    }
    function getWholeGrand(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 21);
        emit logWholeEther(result);
    }
    function getWholeEther(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 18);
        emit logWholeEther(result);
    }
    function getWholeFinney(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 15);
        emit logWholeFinney(result);
    }
    function getWholeSzabo(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 12);
        emit logWholeSzabo(result);
    }
    function getWholeShannon(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 9);
        emit logWholeSzabo(result);
    }
        function getWholeLovelace(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 6);
        emit logWholeSzabo(result);
    }
    function getWholeBabbage(uint256 _wholeValue) public{
        uint256 result = getInt(_wholeValue, 3);
        emit logWholeSzabo(result);
    }

}

Results

As per the official denomination exponents [1] the following statements are true.

  • Passing in 100000000000000000000 to getWholeEther returns 100
  • Passing in 100000000000000000000 to getWholeFinney returns 100000
  • Passing in 100000000000000000000 to getWholeSzabo returns 100000000

Disclaimer

This is an experimental design pattern which has not been thoroughly tested. The above code will require validation and testing at time of implementation (including range (out of range), leading zero's, min, max, overflow and more). Use at your own risk.

References

[1] https://github.com/ethereumbook/ethereumbook/blob/develop/02intro.asciidoc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment