OffchainLabs / arbitrum-tutorials

Get started developing on Arbitrum
452 stars 278 forks source link

L2 block verification in assertion - enhance to use storageProofs #122

Open johnwhitton opened 1 month ago

johnwhitton commented 1 month ago

Overview

Thanks for your work here and excellent tutorials. We are looking to create a storageProof showing that the Arbitrum block.number for a Node is valid. This is similar to the l2-block-verification-in-assertion tutorial

However instead of relying on event messaging we need to prove the underlying values on chain using a secureMerkleTrie.

We were hoping that the Arbitrum block.number or block.hash would be stored against the node. However it appears that instead the closest we have is stateHash using the following values,

Question

Can you help us provide information as to where we can source the following fields

Or suggest an alternate approach to generating a storageProof linking the Node to it's Arbitrum Block Number.

Additional information

Sample data taken from this tenderly transaction

assertion = {
  "beforeState":{
    "globalState":{
        "bytes32Vals":["0xd9bab719a5f76ab63cf812bdf2f5a4be0d02b4ace8e4d92f18046c3f2912f5c5",
"0xa93a9bf66a781d701ff647c4786c0972dc4b4423fe8215b96c0962d9cc35567c"],
"u64Vals":653111,0]
  },
  "machineStatus":1
},
"afterState":{"globalState":{
  "bytes32Vals":
    ["0x17304244fc1e89f12d4a8b9f9dccac8f856f492babc0cc2b573b4bad73bfab41",
    "0x7a10019bc1e5caefe0e2ff1d63bf82fcc1b96a08b488d49d7a52ea057890c73e"],
  "u64Vals":[653147,235]
  },
  "machineStatus":1},
"numBlocks":14375},
 expectedNodeHash = 0x7572df8afe056a39e1e4b97552809ad508ebf45b4e89c85a115b43fd6aedbf8b, prevNodeInboxMaxCount = 653111)

which are calculated in createNewNode using the following logic

            memoryFrame.node = NodeLib.createNode(
                RollupLib.stateHash(assertion.afterState, memoryFrame.currentInboxSize),
                RollupLib.challengeRootHash(
                    memoryFrame.executionHash,
                    block.number,
                    wasmModuleRoot
                ),
                RollupLib.confirmHash(assertion),
                prevNodeNum,
                memoryFrame.deadlineBlock,
                newNodeHash
            );

Which calls

  function stateHash(ExecutionState calldata execState, uint256 inboxMaxCount)
        internal
        pure
        returns (bytes32)
    {
        return
            keccak256(
                abi.encodePacked(
                    execState.globalState.hash(),
                    inboxMaxCount,
                    execState.machineStatus
                )
            );
    }

This means in order to prove this storageSlot we will need to manually calculate the stateHash using all the input values from the Assertion. Specifically we need

struct Assertion {
    ExecutionState beforeState;
    ExecutionState afterState;
    uint64 numBlocks;
}

which uses

struct ExecutionState {
    GlobalState globalState;
    MachineStatus machineStatus;
}

and

struct GlobalState {
    bytes32[2] bytes32Vals;
    uint64[2] u64Vals;
}

and

enum MachineStatus {
    RUNNING,
    FINISHED,
    ERRORED,
    TOO_FAR
}

Arbitrum Rollup Admin Storage

Following is the storage for the proxied implementation contract from Sepolia.

To retrieve this use the command cast storage 0x2Bd2fB395888B799f736E10728dA5C46b83B87Cf --rpc-url https://eth-sepolia.g.alchemy.com/v2/<alchemky-key> -e <etherscan-key>

Name Type Slot Offset Bytes Value Hex Value Contract
_initialized bool 0 0 1 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_initializing bool 0 1 1 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
__gap uint256[50] 1 0 1600 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_paused bool 51 0 1 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
__gap uint256[49] 52 0 1568 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
confirmPeriodBlocks uint64 101 0 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
extraChallengeTimeBlocks uint64 101 8 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
chainId uint256 102 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
baseStake uint256 103 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
wasmModuleRoot bytes32 104 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
inbox contract IInbox 105 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
bridge contract IBridge 106 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
outbox contract IOutbox 107 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
sequencerInbox contract ISequencerInbox 108 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
rollupEventInbox contract IRollupEventInbox 109 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
challengeManager contract IChallengeManager 110 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
validatorUtils address 111 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
validatorWalletCreator address 112 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
loserStakeEscrow address 113 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
stakeToken address 114 0 20 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
minimumAssertionPeriod uint256 115 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
isValidator mapping(address => bool) 116 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_latestConfirmed uint64 117 0 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_firstUnresolvedNode uint64 117 8 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_latestNodeCreated uint64 117 16 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_lastStakeBlock uint64 117 24 8 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_nodes mapping(uint64 => struct Node) 118 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_nodeStakers mapping(uint64 => mapping(address => bool)) 119 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_stakerList address[] 120 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_stakerMap mapping(address => struct IRollupCore.Staker) 121 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_zombies struct RollupCore.Zombie[] 122 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_withdrawableFunds mapping(address => uint256) 123 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
totalWithdrawableFunds uint256 124 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
rollupDeploymentBlock uint256 125 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
validatorWhitelistDisabled bool 126 0 1 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
_nodeCreatedAtArbSysBlock mapping(uint64 => uint256) 127 0 32 0 0x0000000000000000000000000000000000000000000000000000000000000000 src/rollup/RollupAdminLogic.sol:RollupAdminLogic
johnwhitton commented 1 month ago

Any update on this?

Jason-W123 commented 1 month ago

Hey, do you need to prove block number or block hash? If, just block hash, you can get assertion, it related inboxMsgCount and the node number off chain, then upload them on chain via this contract interface example:

function verify(Assertion calldata assertion, uint256 inboxMsgCount, uint256 nodeNumber) public returns(bool){}

You can implement this method by:

  1. Get node from the rollup contract by nodeNumber.
  2. Hash assertion and inboxMsgCount. You can use RollupLib to do this: https://github.com/OffchainLabs/nitro-contracts/blob/main/src/rollup/RollupLib.sol#L21
  3. Then compare the statehash of the node you got from step one with the result from the step 2.

If you want to verify the block number, you can translate inboxMsgCount to the l2 block number by add the l2 genesis number, currently arb1 is 22207817 but note the translation between inboxMsgCount and l2 block number might be changed in the future.

Also the roots on outbox contains blockhash: https://github.com/OffchainLabs/nitro-contracts/blob/main/src/bridge/AbsOutbox.sol#L105