Skip to content

Instantly share code, notes, and snippets.

@Elyx0
Created September 4, 2022 05:42
Show Gist options
  • Select an option

  • Save Elyx0/e6bdf24434fe99169c68ac97f1443504 to your computer and use it in GitHub Desktop.

Select an option

Save Elyx0/e6bdf24434fe99169c68ac97f1443504 to your computer and use it in GitHub Desktop.

Revisions

  1. Elyx0 created this gist Sep 4, 2022.
    7 changes: 7 additions & 0 deletions ByteCode
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    forge inspect ./src/StateReceiverFlatten.sol:StateReceiver bytecode

    0x608060405234801561001057600080fd5b506109ac806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806319494a17146100465780633434735f146100e15780635407ca671461012b575b600080fd5b6100c76004803603604081101561005c57600080fd5b81019080803590602001909291908035906020019064010000000081111561008357600080fd5b82018360208201111561009557600080fd5b803590602001918460018302840111640100000000831117156100b757600080fd5b9091929391929390505050610149565b604051808215151515815260200191505060405180910390f35b6100e961047a565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610133610492565b6040518082815260200191505060405180910390f35b600073fffffffffffffffffffffffffffffffffffffffe73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610200576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f4e6f742053797374656d2041646465737321000000000000000000000000000081525060200191505060405180910390fd5b606061025761025285858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610498565b6104c6565b905060006102788260008151811061026b57fe5b60200260200101516105a3565b905080600160005401146102f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f537461746549647320617265206e6f742073657175656e7469616c000000000081525060200191505060405180910390fd5b600080815480929190600101919050555060006103248360018151811061031757fe5b6020026020010151610614565b905060606103458460028151811061033857fe5b6020026020010151610637565b9050610350826106c3565b1561046f576000624c4b409050606084836040516024018083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156103aa57808201518184015260208101905061038f565b50505050905090810190601f1680156103d75780820380516001836020036101000a031916815260200191505b5093505050506040516020818303038152906040527f26c53bea000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050905060008082516020840160008887f1965050505b505050509392505050565b73fffffffffffffffffffffffffffffffffffffffe81565b60005481565b6104a0610943565b600060208301905060405180604001604052808451815260200182815250915050919050565b60606104d1826106dc565b6104da57600080fd5b60006104e58361072a565b905060608160405190808252806020026020018201604052801561052357816020015b61051061095d565b8152602001906001900390816105085790505b5090506000610535856020015161079b565b8560200151019050600080600090505b848110156105965761055683610824565b915060405180604001604052808381526020018481525084828151811061057957fe5b602002602001018190525081830192508080600101915050610545565b5082945050505050919050565b60008082600001511180156105bd57506021826000015111155b6105c657600080fd5b60006105d5836020015161079b565b9050600081846000015103905060008083866020015101905080519150602083101561060857826020036101000a820491505b81945050505050919050565b6000601582600001511461062757600080fd5b610630826105a3565b9050919050565b6060600082600001511161064a57600080fd5b6000610659836020015161079b565b905060008184600001510390506060816040519080825280601f01601f19166020018201604052801561069b5781602001600182028038833980820191505090505b50905060008160200190506106b78487602001510182856108dc565b81945050505050919050565b600080823b905060008163ffffffff1611915050919050565b600080826000015114156106f35760009050610725565b60008083602001519050805160001a915060c060ff168260ff16101561071e57600092505050610725565b6001925050505b919050565b600080826000015114156107415760009050610796565b60008090506000610755846020015161079b565b84602001510190506000846000015185602001510190505b8082101561078f5761077e82610824565b82019150828060010193505061076d565b8293505050505b919050565b600080825160001a9050608060ff168110156107bb57600091505061081f565b60b860ff168110806107e0575060c060ff1681101580156107df575060f860ff1681105b5b156107ef57600191505061081f565b60c060ff1681101561080f5760018060b80360ff1682030191505061081f565b60018060f80360ff168203019150505b919050565b6000806000835160001a9050608060ff1681101561084557600191506108d2565b60b860ff16811015610862576001608060ff1682030191506108d1565b60c060ff168110156108925760b78103600185019450806020036101000a855104600182018101935050506108d0565b60f860ff168110156108af57600160c060ff1682030191506108cf565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b60008114156108ea5761093e565b5b602060ff16811061091a5782518252602060ff1683019250602060ff1682019150602060ff16810390506108eb565b6000600182602060ff16036101000a03905080198451168184511681811785525050505b505050565b604051806040016040528060008152602001600081525090565b60405180604001604052806000815260200160008152509056fea265627a7a72315820baa9fb8d83ea311f6aa22cd2ab6a90f17bc1727bfd05a8fc4eee871ad932956264736f6c63430005110032
    0x608060405234801561001057600080fd5b506109ac806100206000396000f3fe <- too much.

    Almost same than : https://polygonscan.com/address/0x0000000000000000000000000000000000001001#code

    365 changes: 365 additions & 0 deletions StateReceiverFlatten.sol
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,365 @@
    // Current bytecode at: https://polygonscan.com/address/0x0000000000000000000000000000000000001001#code
    // Source: https://github.com/maticnetwork/genesis-contracts/tree/b16a181613862ff475acafb25eb1d3a5c1dde261

    pragma solidity ^0.5.11;


    library RLPReader {
    uint8 constant STRING_SHORT_START = 0x80;
    uint8 constant STRING_LONG_START = 0xb8;
    uint8 constant LIST_SHORT_START = 0xc0;
    uint8 constant LIST_LONG_START = 0xf8;
    uint8 constant WORD_SIZE = 32;

    struct RLPItem {
    uint len;
    uint memPtr;
    }

    struct Iterator {
    RLPItem item; // Item that's being iterated over.
    uint nextPtr; // Position of the next item in the list.
    }

    /*
    * @dev Returns the next element in the iteration. Reverts if it has not next element.
    * @param self The iterator.
    * @return The next element in the iteration.
    */
    function next(Iterator memory self) internal pure returns (RLPItem memory) {
    require(hasNext(self));

    uint ptr = self.nextPtr;
    uint itemLength = _itemLength(ptr);
    self.nextPtr = ptr + itemLength;

    return RLPItem(itemLength, ptr);
    }

    /*
    * @dev Returns true if the iteration has more elements.
    * @param self The iterator.
    * @return true if the iteration has more elements.
    */
    function hasNext(Iterator memory self) internal pure returns (bool) {
    RLPItem memory item = self.item;
    return self.nextPtr < item.memPtr + item.len;
    }

    /*
    * @param item RLP encoded bytes
    */
    function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) {
    uint memPtr;
    assembly {
    memPtr := add(item, 0x20)
    }

    return RLPItem(item.length, memPtr);
    }

    /*
    * @dev Create an iterator. Reverts if item is not a list.
    * @param self The RLP item.
    * @return An 'Iterator' over the item.
    */
    function iterator(RLPItem memory self) internal pure returns (Iterator memory) {
    require(isList(self));

    uint ptr = self.memPtr + _payloadOffset(self.memPtr);
    return Iterator(self, ptr);
    }

    /*
    * @param item RLP encoded bytes
    */
    function rlpLen(RLPItem memory item) internal pure returns (uint) {
    return item.len;
    }

    /*
    * @param item RLP encoded bytes
    */
    function payloadLen(RLPItem memory item) internal pure returns (uint) {
    return item.len - _payloadOffset(item.memPtr);
    }

    /*
    * @param item RLP encoded list in bytes
    */
    function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) {
    require(isList(item));

    uint items = numItems(item);
    RLPItem[] memory result = new RLPItem[](items);

    uint memPtr = item.memPtr + _payloadOffset(item.memPtr);
    uint dataLen;
    for (uint i = 0; i < items; i++) {
    dataLen = _itemLength(memPtr);
    result[i] = RLPItem(dataLen, memPtr);
    memPtr = memPtr + dataLen;
    }

    return result;
    }

    // @return indicator whether encoded payload is a list. negate this function call for isData.
    function isList(RLPItem memory item) internal pure returns (bool) {
    if (item.len == 0) return false;

    uint8 byte0;
    uint memPtr = item.memPtr;
    assembly {
    byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < LIST_SHORT_START)
    return false;
    return true;
    }

    /** RLPItem conversions into data types **/

    // @returns raw rlp encoding in bytes
    function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) {
    bytes memory result = new bytes(item.len);
    if (result.length == 0) return result;

    uint ptr;
    assembly {
    ptr := add(0x20, result)
    }

    copy(item.memPtr, ptr, item.len);
    return result;
    }

    // any non-zero byte is considered true
    function toBoolean(RLPItem memory item) internal pure returns (bool) {
    require(item.len == 1);
    uint result;
    uint memPtr = item.memPtr;
    assembly {
    result := byte(0, mload(memPtr))
    }

    return result == 0 ? false : true;
    }

    function toAddress(RLPItem memory item) internal pure returns (address) {
    // 1 byte for the length prefix
    require(item.len == 21);

    return address(toUint(item));
    }

    function toUint(RLPItem memory item) internal pure returns (uint) {
    require(item.len > 0 && item.len <= 33);

    uint offset = _payloadOffset(item.memPtr);
    uint len = item.len - offset;

    uint result;
    uint memPtr = item.memPtr + offset;
    assembly {
    result := mload(memPtr)

    // shfit to the correct location if neccesary
    if lt(len, 32) {
    result := div(result, exp(256, sub(32, len)))
    }
    }

    return result;
    }

    // enforces 32 byte length
    function toUintStrict(RLPItem memory item) internal pure returns (uint) {
    // one byte prefix
    require(item.len == 33);

    uint result;
    uint memPtr = item.memPtr + 1;
    assembly {
    result := mload(memPtr)
    }

    return result;
    }

    function toBytes(RLPItem memory item) internal pure returns (bytes memory) {
    require(item.len > 0);

    uint offset = _payloadOffset(item.memPtr);
    uint len = item.len - offset; // data length
    bytes memory result = new bytes(len);

    uint destPtr;
    assembly {
    destPtr := add(0x20, result)
    }

    copy(item.memPtr + offset, destPtr, len);
    return result;
    }

    /*
    * Private Helpers
    */

    // @return number of payload items inside an encoded list.
    function numItems(RLPItem memory item) private pure returns (uint) {
    if (item.len == 0) return 0;

    uint count = 0;
    uint currPtr = item.memPtr + _payloadOffset(item.memPtr);
    uint endPtr = item.memPtr + item.len;
    while (currPtr < endPtr) {
    currPtr = currPtr + _itemLength(currPtr); // skip over an item
    count++;
    }

    return count;
    }

    // @return entire rlp item byte length
    function _itemLength(uint memPtr) private pure returns (uint) {
    uint itemLen;
    uint byte0;
    assembly {
    byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < STRING_SHORT_START)
    itemLen = 1;

    else if (byte0 < STRING_LONG_START)
    itemLen = byte0 - STRING_SHORT_START + 1;

    else if (byte0 < LIST_SHORT_START) {
    assembly {
    let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is
    memPtr := add(memPtr, 1) // skip over the first byte

    /* 32 byte word size */
    let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
    itemLen := add(dataLen, add(byteLen, 1))
    }
    }

    else if (byte0 < LIST_LONG_START) {
    itemLen = byte0 - LIST_SHORT_START + 1;
    }

    else {
    assembly {
    let byteLen := sub(byte0, 0xf7)
    memPtr := add(memPtr, 1)

    let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
    itemLen := add(dataLen, add(byteLen, 1))
    }
    }

    return itemLen;
    }

    // @return number of bytes until the data
    function _payloadOffset(uint memPtr) private pure returns (uint) {
    uint byte0;
    assembly {
    byte0 := byte(0, mload(memPtr))
    }

    if (byte0 < STRING_SHORT_START)
    return 0;
    else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START))
    return 1;
    else if (byte0 < LIST_SHORT_START) // being explicit
    return byte0 - (STRING_LONG_START - 1) + 1;
    else
    return byte0 - (LIST_LONG_START - 1) + 1;
    }

    /*
    * @param src Pointer to source
    * @param dest Pointer to destination
    * @param len Amount of memory to copy from the source
    */
    function copy(uint src, uint dest, uint len) private pure {
    if (len == 0) return;

    // copy as many word sizes as possible
    for (; len >= WORD_SIZE; len -= WORD_SIZE) {
    assembly {
    mstore(dest, mload(src))
    }

    src += WORD_SIZE;
    dest += WORD_SIZE;
    }

    // left over bytes. Mask is used to remove unwanted bytes from the word
    uint mask = 256 ** (WORD_SIZE - len) - 1;
    assembly {
    let srcpart := and(mload(src), not(mask)) // zero out src
    let destpart := and(mload(dest), mask) // retrieve the bytes
    mstore(dest, or(destpart, srcpart))
    }
    }
    }

    contract System {
    address public constant SYSTEM_ADDRESS = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE;

    modifier onlySystem() {
    require(msg.sender == SYSTEM_ADDRESS, "Not System Addess!");
    _;
    }
    }

    // IStateReceiver represents interface to receive state
    interface IStateReceiver {
    function onStateReceive(uint256 stateId, bytes calldata data) external;
    }

    contract StateReceiver is System {
    using RLPReader for bytes;
    using RLPReader for RLPReader.RLPItem;

    uint256 public lastStateId;

    function commitState(uint256 syncTime, bytes calldata recordBytes) onlySystem external returns(bool success) {
    // parse state data
    RLPReader.RLPItem[] memory dataList = recordBytes.toRlpItem().toList();
    uint256 stateId = dataList[0].toUint();
    require(
    lastStateId + 1 == stateId,
    "StateIds are not sequential"
    );
    lastStateId++;

    address receiver = dataList[1].toAddress();
    bytes memory stateData = dataList[2].toBytes();
    // notify state receiver contract, in a non-revert manner
    if (isContract(receiver)) {
    uint256 txGas = 5000000;
    bytes memory data = abi.encodeWithSignature("onStateReceive(uint256,bytes)", stateId, stateData);
    // solium-disable-next-line security/no-inline-assembly
    assembly {
    success := call(txGas, receiver, 0, add(data, 0x20), mload(data), 0, 0)
    }
    }
    }

    // check if address is contract
    function isContract(address _addr) private view returns (bool){
    uint32 size;
    assembly {
    size := extcodesize(_addr)
    }
    return (size > 0);
    }
    }