Skip to main content

Submit L2 Block

The "block" operation submits the result + proof of a new block for a Layer 2 blockchain deployed on Bitcoin.

Parameters

  • p: "l2o-a" (The ordinal protocol, which is "l2o-a")
  • op: "Block" (The operation id, which is "Block")
  • l2id: A unique unsigned 32bit number that identifies the layer 2 which has already been deployed
    • Note: The l2id 0 is reserved for representing the Bitcoin Layer 1 blockchain
    • Note: if an incoming block operation specifies an l2id which has not been deployed, then the incoming block operation is NOOP
  • bitcoin_block_number: The bitcoin block number which the L2 is currently synced to (must be greater than the previous block proof)
  • bitcoin_block_hash: The block hash of the Bitcoin block at height bitcoin_block_number
  • l2_block_number: The current block number of the L2 (must be 1 more than the previous block proof)
  • public_key: The public key which is used to verify the next block proof's signature
    • Note: if public_key is set to the empty string "" or "0" then the next block proof's signature is ignored
  • start_state_root: The state root of the L2 before the incoming L2 block was executed (the previous L2 block's end_state_root)
  • end_state_root: The state root of the L2 after the incoming L2 block was executed
  • deposit_state_root: The Merkle Root of L2's BRC-21 deposit tree as of the bitcoin block specified by bitcoin_block_number
  • start_withdrawal_state_root: The Merkle Root of L2's BRC-21 withdrawal tree at the start L2 block specified by l2_block_number
  • end_withdrawal_state_root: The Merkle Root of L2's BRC-21 withdrawal tree at the end L2 block specified by l2_block_number
  • superchain_root: The Merkle Root of the Superchain merkle state tree hashed with the hash_function configured when the L2 was deployed at block bitcoin_block_number
  • proof: A zero knowledge proof of the L2's block with a single public input which is the hash (using to the hash_function configured when the L2 was deployed) of the following parameters concatenated:
    • l2_block_number
    • bitcoin_block_hash
    • public_key
    • start_state_root
    • end_state_root
    • deposit_state_root
    • start_withdrawal_state_root
    • end_withdrawal_state_root
    • superchain_root
  • signature: A schnorr signature of the sha256 hash of the proof, checked against the previous block proofs public key
    • if the previous block proof's public key was "0" or an empty string, the signature is ignored

Block Verification Logic

  1. Check if the L2 ID is deployed/valid (if the id is invalid or does not exist, the operation is a NOOP)
  2. Fetch the following parameters from the L2's deployment configuration:
  • last_l2_block_number
  • last_bitcoin_block_number
  • last_end_state_root
  • last_end_withdrawal_state_root
  • last_public_key
  • proof_type
  • hash_function
  • verifier_data
  1. Validate the JSON payload, ensuring to range check the inputs based on the proof_type's field
  2. Ensure that l2_block_number == (last_l2_block_number + 1)
  3. Ensure that bitcoin_block_number > last_bitcoin_block_number
  4. Ensure that start_state_root == last_end_state_root
  5. Ensure that start_withdrawal_state_root == last_end_withdrawal_state_root
  6. Compute the expected public input by hashing the following parameters using hash_function and ensuring it equals the public input of the proof:
  • l2_block_number
  • bitcoin_block_hash
  • public_key
  • start_state_root
  • end_state_root
  • deposit_state_root
  • start_withdrawal_state_root
  • end_withdrawal_state_root
  • superchain_root
  1. Fetch the block hash at bitcoin_block_number and ensure it is equal to bitcoin_block_hash
  2. Fetch the BRC-21 deposit state root at block bitcoin_block_number and ensure it equals deposit_state_root
  3. Fetch the super chain root of the super chain state merkle tree hashed with hash_function at bitcoin_block_number and ensure it equals superchain_root
  4. If the last_public_key is not null or 0, hash the proof and check the signature
  5. Verify the zero knowledge proof using verifier_data
  6. Update the L2's database record (see psuedo-code below):
l2_state.last_bitcoin_block_number = bitcoin_block_number;
l2_state.last_l2_block_number = l2_block_number;
l2_state.last_public_key = public_key;
l2_state.last_end_state_root = end_state_root;
l2_state.last_end_withdrawal_state_root = end_withdrawal_state_root;
  1. Update the Superchain merkle tree leaf at index l2id, setting the value of the leaf to last_end_state_root

Pseudo Schema

{
"p": "l2o-a",
"op": "Block",
"l2id": 1, // replace with your l2 id
"bitcoin_block_number": 999, //replace with your bitcoin block number
"bitcoin_block_hash": "<bitcoin block hash at bitcoin_block_number>",
"l2_block_number": 1337, // replace with your L2 blockchain's block number
"public_key": "<the schnorr public key that must sign your next block proof, 0 if no signature is required>",
"start_state_root": "<the start state root for your L2's block>",
"end_state_root": "<the end state root for your L2's block>",
"deposit_state_root": "<the root of the deposit tree for your L2 at block >",
"start_withdrawal_state_root": "<proof type>",
"end_withdrawal_state_root": "<proof type>",
"proof": {
"...": "<block zero knowledge proof for this L2 block>"
},
"superchain_root": "<super chain state merkle root>",
"signature": "<schnorr signature of proof with public inputs>"
}