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
- Note: The l2id
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 heightbitcoin_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
- Note: if public_key is set to the empty string
start_state_root
: The state root of the L2 before the incoming L2 block was executed (the previous L2 block'send_state_root
)end_state_root
: The state root of the L2 after the incoming L2 block was executeddeposit_state_root
: The Merkle Root of L2's BRC-21 deposit tree as of the bitcoin block specified bybitcoin_block_number
start_withdrawal_state_root
: The Merkle Root of L2's BRC-21 withdrawal tree at the start L2 block specified byl2_block_number
end_withdrawal_state_root
: The Merkle Root of L2's BRC-21 withdrawal tree at the end L2 block specified byl2_block_number
superchain_root
: The Merkle Root of the Superchain merkle state tree hashed with thehash_function
configured when the L2 was deployed at blockbitcoin_block_number
proof
: A zero knowledge proof of the L2's block with a single public input which is the hash (using to thehash_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
- Check if the L2 ID is deployed/valid (if the id is invalid or does not exist, the operation is a NOOP)
- 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
- Validate the JSON payload, ensuring to range check the inputs based on the
proof_type
's field - Ensure that
l2_block_number == (last_l2_block_number + 1)
- Ensure that
bitcoin_block_number > last_bitcoin_block_number
- Ensure that
start_state_root == last_end_state_root
- Ensure that
start_withdrawal_state_root == last_end_withdrawal_state_root
- 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
- Fetch the block hash at
bitcoin_block_number
and ensure it is equal tobitcoin_block_hash
- Fetch the BRC-21 deposit state root at block
bitcoin_block_number
and ensure it equalsdeposit_state_root
- Fetch the super chain root of the super chain state merkle tree hashed with
hash_function
atbitcoin_block_number
and ensure it equalssuperchain_root
- If the
last_public_key
is not null or 0, hash the proof and check the signature - Verify the zero knowledge proof using
verifier_data
- 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;
- Update the Superchain merkle tree leaf at index
l2id
, setting the value of the leaf tolast_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>"
}