From 1de3746bb691e2e26e9f5c7a90b4437d4433cd48 Mon Sep 17 00:00:00 2001 From: Miranda Wood Date: Mon, 1 Jul 2024 11:39:09 +0100 Subject: [PATCH] feat: wonky rollups (#7189) ### Wonky Rollups See full write up [here](https://hackmd.io/@aztec-network/ByROkLKIC). This PR eliminates the need to pad empty transactions in a rollup, so we can run the fewest rollup circuits required for a block. Main changes are: - Implementing a greedy-filled wonky tree in `sol` (`computeUnbalancedRoot`) and `ts` (`unbalanced_tree.ts`, and `getTxsEffectHash`) - thanks to @alexghr for the idea and help on this! - Using this tree to calculate `txsEffectHash`, `outHash`, and gather membership paths for consuming messages in the `outHash` tree - `ContentCommitment.txTreeHeight` -> `.numTxs` as we have variable height (`numTxs` may also not be required, as we gather the number from the txs effect calculation anyway) - Merge rollups can now take in one base and one merge rollup as input - `orchestrator.ts` now forms a wonky tree (`proving-state.ts -> findMergeLevel`) instead of a balanced tree with padding when constructing the rollup circuits and enqueuing proofs - We *only* pad blocks if we have less than 2 transactions, since a root rollup still needs 2 inputs --- The tree greedy fills txs from L to R in a rollup structure e.g. 5 txs looks like: ``` // root // / \ // merge base // / \ // merge merge // / \ / \ // base base base base ``` ...and 7 txs looks like: ``` // root // / \ // merge3 merge5 // / \ / \ // merge1 merge2 merge4 base // / \ / \ / \ // base base base base base base ``` Eliminates the need to use padding txs and circuits. E.g. previously, 5txs would have: ``` // // root // / \ // merge merge // / \ / \ // merge merge merge merge // / \ / \ / \ / \ // base base base base base ``` Processing 3 extra txs and => base circuits, and 3 extra merge circuits. To recalulate a wonky tree from the number of txs in a block, simply decompose it into powers of 2 to find the subtree sizes. Calculate the roots of these subtrees and hash from right to left. A full example in the write up. --- docs/docs/protocol-specs/logs/index.md | 150 +------ .../protocol-specs/rollup-circuits/index.md | 10 +- .../rollup-circuits/merge-rollup.md | 7 +- .../rollup-circuits/root-rollup.md | 7 +- .../state/tree-implementations.md | 6 + docs/docs/protocol-specs/state/wonky-tree.md | 422 ++++++++++++++++++ docs/sidebars.js | 1 + l1-contracts/src/core/Rollup.sol | 9 +- .../core/interfaces/messagebridge/IOutbox.sol | 2 +- l1-contracts/src/core/libraries/Errors.sol | 3 +- l1-contracts/src/core/libraries/HeaderLib.sol | 8 +- l1-contracts/src/core/libraries/MerkleLib.sol | 60 +++ .../core/libraries/decoders/TxsDecoder.sol | 50 ++- .../src/core/messagebridge/Outbox.sol | 33 +- l1-contracts/test/Rollup.t.sol | 6 +- l1-contracts/test/decoders/Base.sol | 2 +- l1-contracts/test/decoders/Decoders.t.sol | 26 +- .../decoders/helpers/TxsDecoderHelper.sol | 9 + l1-contracts/test/fixtures/empty_block_0.json | 12 +- l1-contracts/test/fixtures/empty_block_1.json | 16 +- l1-contracts/test/fixtures/mixed_block_0.json | 12 +- l1-contracts/test/fixtures/mixed_block_1.json | 16 +- .../test/merkle/UnbalancedMerkle.t.sol | 199 +++++++++ .../base_or_merge_rollup_public_inputs.nr | 12 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 6 +- .../crates/rollup-lib/src/components.nr | 37 +- .../src/merge/merge_rollup_inputs.nr | 53 ++- .../rollup-lib/src/root/root_rollup_inputs.nr | 5 +- .../src/tests/previous_rollup_data.nr | 4 +- .../crates/types/src/content_commitment.nr | 12 +- .../aztec-node/src/aztec-node/server.ts | 28 +- yarn-project/circuit-types/src/body.ts | 76 ++-- .../src/structs/content_commitment.ts | 8 +- .../base_or_merge_rollup_public_inputs.ts | 10 +- .../circuits.js/src/tests/factories.ts | 2 +- .../composed/integration_l1_publisher.test.ts | 3 +- yarn-project/merkle-tree/src/index.ts | 1 + .../merkle-tree/src/unbalanced_tree.test.ts | 273 +++++++++++ .../merkle-tree/src/unbalanced_tree.ts | 239 ++++++++++ .../src/type_conversion.ts | 8 +- .../src/orchestrator/orchestrator.ts | 35 +- .../orchestrator/orchestrator_errors.test.ts | 16 +- .../orchestrator_failures.test.ts | 9 +- .../orchestrator_mixed_blocks.test.ts | 3 +- .../orchestrator_mixed_blocks_2.test.ts | 62 +-- .../orchestrator_single_blocks.test.ts | 13 +- .../src/orchestrator/proving-state.ts | 26 ++ .../src/sequencer/sequencer.ts | 4 +- 48 files changed, 1543 insertions(+), 468 deletions(-) create mode 100644 docs/docs/protocol-specs/state/wonky-tree.md create mode 100644 l1-contracts/test/merkle/UnbalancedMerkle.t.sol create mode 100644 yarn-project/merkle-tree/src/unbalanced_tree.test.ts create mode 100644 yarn-project/merkle-tree/src/unbalanced_tree.ts diff --git a/docs/docs/protocol-specs/logs/index.md b/docs/docs/protocol-specs/logs/index.md index 1d442184e4f..1f98711bd1e 100644 --- a/docs/docs/protocol-specs/logs/index.md +++ b/docs/docs/protocol-specs/logs/index.md @@ -53,161 +53,27 @@ A function can emit an arbitrary number of logs, provided they don't exceed the -To minimize the on-chain verification data size, protocol circuits aggregate log hashes. The end result is a single hash within the root rollup proof, encompassing all logs of the same type. +To minimize the on-chain verification data size, protocol circuits aggregate log hashes. The end result is a single hash within the base rollup proof, encompassing all logs of the same type. Each protocol circuit outputs two values for each log type: - _`accumulated_logs_hash`_: A hash representing all logs. - _`accumulated_logs_length`_: The total length of all log preimages. +Both the `accumulated_logs_hash` and `accumulated_logs_length` for each type are included in the base rollup's `txs_effect_hash`. When rolling up to merge and root circuits, the two input proof's `txs_effect_hash`es are hashed together to form the new value of `txs_effect_hash`. + +When publishing a block on L1, the raw logs of each type and their lengths are provided (**Availability**), hashed and accumulated into each respective `accumulated_logs_hash` and `accumulated_logs_length`, then included in the on-chain recalculation of `txs_effect_hash`. If this value doesn't match the one from the rollup circuits, the block will not be valid (**Immutability**). + + For private and public kernel circuits, beyond aggregating logs from a function call, they ensure that the contract's address emitting the logs is linked to the _logs_hash_. For more details, refer to the "Hashing" sections in [Unencrypted Log](#hashing-1), [Encrypted Log](#hashing-2), and [Encrypted Note Preimage](#hashing-3). -### Encoding - -1. The encoded logs data of a transaction is a flattened array of all logs data within the transaction: - - _`tx_logs_data = [number_of_logs, ...log_data_0, ...log_data_1, ...]`_ - - The format of _log_data_ varies based on the log type. For specifics, see the "Encoding" sections in [Unencrypted Log](#encoding-1), [Encrypted Log](#encoding-2), and [Encrypted Note Preimage](#encoding-3). - -2. The encoded logs data of a block is a flatten array of a collection of the above _tx_logs_data_, with hints facilitating hashing replay in a binary tree structure: - - _`block_logs_data = [number_of_branches, number_of_transactions, ...tx_logs_data_0, ...tx_logs_data_1, ...]`_ - - - _number_of_transactions_ is the number of leaves in the left-most branch, restricted to either _1_ or _2_. - - _number_of_branches_ is the depth of the parent node of the left-most leaf. - -Here is a step-by-step example to construct the _`block_logs_data`_: - -1. A rollup, _R01_, merges two transactions: _tx0_ containing _tx_logs_data_0_, and _tx1_ containing _tx_logs_data_1_: - - ```mermaid - flowchart BT - tx0((tx0)) - tx1((tx1)) - R01((R01)) - tx0 --- R01 - tx1 --- R01 - ``` - - _block_logs_data_: _`[0, 2, ...tx_logs_data_0, ...tx_logs_data_1]`_ - - Where _0_ is the depth of the node _R01_, and _2_ is the number of aggregated _tx_logs_data_ of _R01_. - -2. Another rollup, _R23_, merges two transactions: _tx3_ containing _tx_logs_data_3_, and _tx2_ without any logs: - - ```mermaid - flowchart BT - tx2((tx2)) - tx3((tx3)) - R23((R23)) - tx2 -. no logs .- R23 - tx3 --- R23 - ``` - - _block_logs_data_: _`[0, 1, ...tx_logs_data_3]`_ - - Here, the number of aggregated _tx_logs_data_ is _1_. - -3. A rollup, _RA_, merges the two rollups _R01_ and _R23_: - - ```mermaid - flowchart BT - tx0((tx0)) - tx1((tx1)) - R01((R01)) - tx0 --- R01 - tx1 --- R01 - tx2((tx2)) - tx3((tx3)) - R23((R23)) - tx2 -.- R23 - tx3 --- R23 - RA((RA)) - R01 --- RA - R23 --- RA - ``` - - _block_logs_data_: _`[1, 2, ...tx_logs_data_0, ...tx_logs_data_1, 0, 1, ...tx_logs_data_3]`_ - - The result is the _block_logs_data_ of _R01_ concatenated with the _block_logs_data_ of _R23_, with the _number_of_branches_ of _R01_ incremented by _1_. The updated value of _number_of_branches_ (_0 + 1_) is also the depth of the node _R01_. - -4. A rollup, _RB_, merges the above rollup _RA_ and another rollup _R45_: - - ```mermaid - flowchart BT - tx0((tx0)) - tx1((tx1)) - R01((R01)) - tx0 --- R01 - tx1 --- R01 - tx2((tx2)) - tx3((tx3)) - R23((R23)) - tx2 -.- R23 - tx3 --- R23 - RA((RA)) - R01 --- RA - R23 --- RA - tx4((tx4)) - tx5((tx5)) - R45((R45)) - tx4 --- R45 - tx5 --- R45 - RB((RB)) - RA --- RB - R45 --- RB - ``` - - _block_logs_data_: _`[2, 2, ...tx_logs_data_0, ...tx_logs_data_1, 0, 1, ...tx_logs_data_3, 0, 2, ...tx_logs_data_4, ...tx_logs_data_5]`_ - - The result is the concatenation of the _block_logs_data_ from both rollups, with the _number_of_branches_ of the left-side rollup, _RA_, incremented by _1_. - -### Verification - -Upon receiving a proof and its encoded logs data, the entity can ensure the correctness of the provided _block_logs_data_ by verifying that the _accumulated_logs_hash_ in the proof can be derived from it: - -```js -const accumulated_logs_hash = compute_accumulated_logs_hash(block_logs_data); -assert(accumulated_logs_hash == proof.accumulated_logs_hash); -assert(block_logs_data.accumulated_logs_length == proof.accumulated_logs_length); - -function compute_accumulated_logs_hash(logs_data) { - const number_of_branches = logs_data.read_u32(); - - const number_of_transactions = logs_data.read_u32(); - let res = hash_tx_logs_data(logs_data); - if number_of_transactions == 2 { - res = hash(res, hash_tx_logs_data(logs_data)); - } - - for (let i = 0; i < number_of_branches; ++i) { - const res_right = compute_accumulated_logs_hash(logs_data); - res = hash(res, res_right); - } - - return res; -} - -function hash_tx_logs_data(logs_data) { - const number_of_logs = logs_data.read_u32(); - let res = hash_log_data(logs_data); - for (let i = 1; i < number_of_logs; ++i) { - const log_hash = hash_log_data(logs_data); - res = hash(res, log_hash); - } - return res; -} -``` - -The _accumulated_logs_length_ in _block_logs_data_ is computed during the processing of each _logs_data_ within _hash_log_data()_. The implementation of _hash_log_data_ varies depending on the type of the logs being processed. Refer to the "Verification" sections in [Unencrypted Log](#verification-1), [Encrypted Log](#verification-2), and [Encrypted Note Preimage](#verification-3) for details. - ## Unencrypted Log Unencrypted logs are used to communicate public information out of smart contracts. They can be emitted from both public and private functions. diff --git a/docs/docs/protocol-specs/rollup-circuits/index.md b/docs/docs/protocol-specs/rollup-circuits/index.md index 1e2523f2719..d85df805dd2 100644 --- a/docs/docs/protocol-specs/rollup-circuits/index.md +++ b/docs/docs/protocol-specs/rollup-circuits/index.md @@ -19,9 +19,9 @@ Note that we have two different types of "merger" circuits, depending on what th For transactions we have: - The `merge` rollup - - Merges two `base` rollup proofs OR two `merge` rollup proofs + - Merges two rollup proofs of either `base` or `merge` and constructs outputs for further proving - The `root` rollup - - Merges two `merge` rollup proofs + - Merges two rollup proofs of either `base` or `merge` and constructs outputs for L1 And for the message parity we have: @@ -30,7 +30,7 @@ And for the message parity we have: - The `base_parity` circuit - Merges `N` l1 to l2 messages in a subtree -In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. +In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. Exactly how many layers and what combination of `base` and/or `merge` circuits are consumed is based on filling a [wonky tree](../state/tree-implementations.md#wonky-merkle-trees) with N transactions. Circles mark the different types of proofs, while squares mark the different circuit types. ```mermaid @@ -465,7 +465,7 @@ Furthermore, the `OutHash` is a computed from a subset of the data in `TxsHash` Since we strive to minimize the compute requirements to prove blocks, we amortize the commitment cost across the full tree. We can do so by building merkle trees of partial "commitments", whose roots are ultimately computed in the final root rollup circuit. -Below, we outline the `TxsHash` merkle tree that is based on the `TxEffect`s and a `OutHash` which is based on the `l2_to_l1_msgs` (cross-chain messages) for each transaction. +Below, we outline the `TxsHash` merkle tree that is based on the `TxEffect`s and a `OutHash` which is based on the `l2_to_l1_msgs` (cross-chain messages) for each transaction, with four transactions in this rollup. While the `TxsHash` implicitly includes the `OutHash` we need it separately such that it can be passed to the `Outbox` for consumption by the portals with minimal work. ```mermaid @@ -588,6 +588,8 @@ graph BT While the `TxsHash` merely require the data to be published and known to L1, the `InHash` and `OutHash` needs to be computable on L1 as well. This reason require them to be efficiently computable on L1 while still being non-horrible inside a snark - leading us to rely on SHA256. + + The L2 to L1 messages from each transaction form a variable height tree. In the diagram above, transactions 0 and 3 have four messages, so require a tree with two layers, whereas the others only have two messages and so require a single layer tree. The base rollup calculates the root of this tree and passes it as the to the next layer. Merge rollups simply hash both of these roots together and pass it up as the `OutHash`. ## Next Steps diff --git a/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md b/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md index f1ebdce1245..5d8ce56943f 100644 --- a/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md @@ -82,13 +82,12 @@ def MergeRollupCircuit( assert left.public_inputs.constants == right.public_inputs.constants assert left.public_inputs.end == right.public_inputs.start - assert left.public_inputs.type == right.public_inputs.type - assert left.public_inputs.height_in_block_tree == right.public_inputs.height_in_block_tree + assert left.public_inputs.num_txs >= right.public_inputs.num_txs return BaseOrMergeRollupPublicInputs( type=1, - height_in_block_tree=left.public_inputs.height_in_block_tree + 1, - txs_hash=SHA256(left.public_inputs.txs_hash | right.public_inputs.txs_hash), + num_txs=left.public_inputs.num_txs + right.public_inputs.num_txs, + txs_effect_hash=SHA256(left.public_inputs.txs_effect_hash | right.public_inputs.txs_effect_hash), out_hash=SHA256(left.public_inputs.out_hash | right.public_inputs.out_hash), start=left.public_inputs.start, end=right.public_inputs.end, diff --git a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md index d214a01011f..0e09c4663ff 100644 --- a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md @@ -183,8 +183,7 @@ def RootRollupCircuit( assert left.public_inputs.constants == right.public_inputs.constants assert left.public_inputs.end == right.public_inputs.start - assert left.public_inputs.type == right.public_inputs.type - assert left.public_inputs.height_in_block_tree == right.public_inputs.height_in_block_tree + assert left.public_inputs.num_txs >= right.public_inputs.num_txs assert parent.state.partial == left.public_inputs.start @@ -208,8 +207,8 @@ def RootRollupCircuit( header = Header( last_archive = left.public_inputs.constants.last_archive, content_commitment: ContentCommitment( - tx_tree_height = left.public_inputs.height_in_block_tree + 1, - txs_hash = SHA256(left.public_inputs.txs_hash | right.public_inputs.txs_hash), + num_txs=left.public_inputs.num_txs + right.public_inputs.num_txs, + txs_effect_hash=SHA256(left.public_inputs.txs_effect_hash | right.public_inputs.txs_effect_hash), in_hash = l1_to_l2_roots.public_inputs.sha_root, out_hash = SHA256(left.public_inputs.out_hash | right.public_inputs.out_hash), ), diff --git a/docs/docs/protocol-specs/state/tree-implementations.md b/docs/docs/protocol-specs/state/tree-implementations.md index cf0f9cf8ccf..b40a5557d65 100644 --- a/docs/docs/protocol-specs/state/tree-implementations.md +++ b/docs/docs/protocol-specs/state/tree-implementations.md @@ -8,6 +8,12 @@ In an append-only Merkle tree, new leaves are inserted in order from left to rig Append-only trees allow for more efficient syncing than sparse trees, since clients can sync from left to right starting with their last known value. Updates to the tree root, when inserting new leaves, can be computed from the rightmost "frontier" of the tree (i.e., from the sibling path of the rightmost nonzero leaf). Batch insertions can be computed with fewer hashes than in a sparse tree. The historical snapshots of append-only trees also enable efficient membership proofs; as older roots can be computed by completing the merkle path from a past left subtree with an empty right subtree. +### Wonky Merkle Trees + +We also use a special type of append-only tree to structure the rollup circuits. Given `n` leaves, we fill from left to right and attempt to pair them to produce the next layer. If `n` is a power of 2, this tree looks exactly like a standard append-only merkle tree. Otherwise, once we reach an odd-sized row we shift the final node up until we reach another odd row to combine them. + +This results in an unbalanced tree where there are no empty leaves. For rollups, this means we don't have to pad empty transactions and process them through the rollup circuits. A full explanation is given [here](./wonky-tree.md). + ## Indexed Merkle trees Indexed Merkle trees, introduced [here](https://eprint.iacr.org/2021/1263.pdf), allow for proofs of non-inclusion more efficiently than sparse Merkle trees. Each leaf in the tree is a tuple of: the leaf value, the next-highest value in the tree, and the index of the leaf where that next-highest value is stored. New leaves are inserted from left to right, as in the append-only tree, but existing leaves can be _modified_ to update the next-highest value and next-highest index (a.k.a. the "pointer") if a new leaf with a "closer value" is added to the tree. An Indexed Merkle trees behaves as a Merkle tree over a sorted linked list. diff --git a/docs/docs/protocol-specs/state/wonky-tree.md b/docs/docs/protocol-specs/state/wonky-tree.md new file mode 100644 index 00000000000..14d1a977675 --- /dev/null +++ b/docs/docs/protocol-specs/state/wonky-tree.md @@ -0,0 +1,422 @@ +# Wonky Tree + +A 'wonky' tree is an append-only unbalanced merkle tree, filled from left to right. It is used to construct [rollup](../rollup-circuits/index.md) proofs without padding empty transactions. + +For example, using a balanced merkle tree to rollup 5 transactions requires padding of 3 empty transactions: + +```mermaid +graph BT + R_c[Root] + + M4_c[Merge] + M5_c[Merge] + M4_c --> R_c + M5_c --> R_c + + + M0_c[Merge] + M1_c[Merge] + M0_c --> M4_c + M1_c --> M4_c + + B0_c[Base] + B1_c[Base] + B2_c[Base] + B3_c[Base] + B0_c --> M0_c + B1_c --> M0_c + B2_c --> M1_c + B3_c --> M1_c + + M2_c[Merge] + M3_c[Merge*] + M2_c --> M5_c + M3_c --> M5_c + + B4_c[Base] + B5_c[Base*] + B6_c[Base*] + B7_c[Base*] + B4_c --> M2_c + B5_c --> M2_c + B6_c --> M3_c + B7_c --> M3_c + + Tx0_c((Tx 0)) + Tx1_c((Tx 1)) + Tx2_c((Tx 2)) + Tx3_c((Tx 3)) + Tx4_c((Tx 4)) + + Tx0_c --> B0_c + Tx1_c --> B1_c + Tx2_c --> B2_c + Tx3_c --> B3_c + Tx4_c --> B4_c +``` + +Where each node marked with `*` indicates a circuit proving entirely empty information. While the above structure does allow us to easily construct balanced trees later on consisting of `out_hash`es and `tx_effects_hash`es, it will lead to wasted compute and higher block processing costs unless we provide a number of transactions equal to a power of 2. + +Our wonky tree implementation instead gives the below structure for 5 transactions: + +```mermaid +graph BT + R_c[Root] + + M4_c[Merge] + M4_c --> R_c + + + M0_c[Merge] + M1_c[Merge] + M0_c --> M4_c + M1_c --> M4_c + + B0_c[Base] + B1_c[Base] + B2_c[Base] + B3_c[Base] + B0_c --> M0_c + B1_c --> M0_c + B2_c --> M1_c + B3_c --> M1_c + + + B4_c[Base] + B4_c --> R_c + + Tx0_c((Tx 0)) + Tx1_c((Tx 1)) + Tx2_c((Tx 2)) + Tx3_c((Tx 3)) + Tx4_c((Tx 4)) + + Tx0_c --> B0_c + Tx1_c --> B1_c + Tx2_c --> B2_c + Tx3_c --> B3_c + Tx4_c --> B4_c +``` + +Here, each circuit is proving useful transaction information with no wasted compute. We can construct a tree like this one for any number of transactions by greedy filling from left to right. Given the required 5 base circuits: + +```mermaid +graph + B0_c[Base 0] + B1_c[Base 1] + B2_c[Base 2] + B3_c[Base 3] + B4_c[Base 4] +``` + +...we theh pair these base circuits up to form merges: + +```mermaid +graph BT + M0_c[Merge 0] + M1_c[Merge 1] + + B0_c[Base 0] + B1_c[Base 1] + B2_c[Base 2] + B3_c[Base 3] + B0_c --> M0_c + B1_c --> M0_c + B2_c --> M1_c + B3_c --> M1_c + + B4_c[Base 4] +``` + +Since we have an odd number of transactions, we cannot pair up the final base. Instead, we continue to pair the next layers until we reach a layer with an odd number of members. In this example, that's when we reach merge 2: + +```mermaid +graph BT + M0_c[Merge 0] + M1_c[Merge 1] + M2_c[Merge 2] + + B0_c[Base 0] + B1_c[Base 1] + B2_c[Base 2] + B3_c[Base 3] + B0_c --> M0_c + B1_c --> M0_c + B2_c --> M1_c + B3_c --> M1_c + + M0_c --> M2_c + M1_c --> M2_c + + B4_c[Base 4] +``` + +Once paired, the base layer has length 4, the next merge layer has 2, and the final merge layer has 1. After reaching a layer with odd length, the orchestrator can now pair base 4: + +```mermaid +graph BT + R_c[Root] + + M0_c[Merge 0] + M1_c[Merge 1] + M2_c[Merge 2] + + B0_c[Base 0] + B1_c[Base 1] + B2_c[Base 2] + B3_c[Base 3] + B0_c --> M0_c + B1_c --> M0_c + B2_c --> M1_c + B3_c --> M1_c + + M0_c --> M2_c + M1_c --> M2_c + + B4_c[Base 4] + M2_c --> R_c + B4_c --> R_c +``` +Since we have processed all base circuits, this final pair will be input to a root circuit. + +Filling from left to right means that we can easily reconstruct the tree only from the number of transactions `n`. The above method ensures that the final tree is a combination of *balanced* subtrees of descending size. The widths of these subtrees are given by the decomposition of `n` into powers of 2. For example, 5 transactions: + +``` +Subtrees: [4, 1] -> + left_subtree_root = balanced_tree(txs[0..4]) + right_subtree_root = balanced_tree(txs[4]) = txs[4] + root = left_subtree_root | right_subtree_root +``` + +For 31 transactions: +``` +Subtrees: [16, 8, 4, 2, 1] -> + Merge D: left_subtree_root = balanced_tree(txs[0..16]) + right_subtree_root = Subtrees: [8, 4, 2, 1] --> { + Merge C: left_subtree_root = balanced_tree(txs[16..24]) + right_subtree_root = Subtrees: [4, 2, 1] --> { + Merge B: left_subtree_root = balanced_tree(txs[24..28]) + right_subtree_root = Subtrees: [2, 1] --> { + Merge A: left_subtree_root = balanced_tree(txs[28..30]) + right_subtree_root = balanced_tree(txs[30]) = txs[30] + Merge 0: root = left_subtree_root | right_subtree_root + } + Merge 1: root = left_subtree_root | right_subtree_root + } + Merge 2: root = left_subtree_root | right_subtree_root + } + root = left_subtree_root | right_subtree_root +``` +An unrolled recursive algorithm is not the easiest thing to read. This diagram represents the 31 transactions rolled up in our wonky structure, where each `Merge ` is a 'subroot' above: + +```mermaid +graph BT + M2_c[Merge 2] + M3_c[Merge D + Subtree of 16 txs] + R_c[Root] + + + B4_c[Merge C + Subtree of 8 txs] + B5_c[Merge 1] + + B4_c --> M2_c + B5_c --> M2_c + + B6_c[Merge B + Subtree of 4 txs] + B7_c[Merge 0] + + B6_c --> B5_c + B7_c --> B5_c + + B8_c[Merge A + Subtree of 2 txs] + B9_c[Base 30] + + B8_c --> B7_c + B9_c --> B7_c + + + M3_c --> R_c + M2_c --> R_c +``` +The tree is reconstructed to check the `txs_effects_hash` (= the root of a wonky tree given by leaves of each tx's `tx_effects`) on L1. We also reconstruct it to provide a membership path against the stored `out_hash` (= the root of a wonky tree given by leaves of each tx's L2 to L1 message tree root) for consuming a L2 to L1 message. + +Currently, this tree is built via the [orchestrator](../../../../yarn-project/prover-client/src/orchestrator/proving-state.ts#74) given the number of transactions to rollup (`this.totalNumTxs`). Each 'node' is assigned a level (0 at the root) and index in that level. The below function finds the parent level: + +``` + // Calculates the index and level of the parent rollup circuit + public findMergeLevel(currentLevel: bigint, currentIndex: bigint) { + const moveUpMergeLevel = (levelSize: number, index: bigint, nodeToShift: boolean) => { + levelSize /= 2; + if (levelSize & 1) { + [levelSize, nodeToShift] = nodeToShift ? [levelSize + 1, false] : [levelSize - 1, true]; + } + index >>= 1n; + return { thisLevelSize: levelSize, thisIndex: index, shiftUp: nodeToShift }; + }; + let [thisLevelSize, shiftUp] = this.totalNumTxs & 1 ? [this.totalNumTxs - 1, true] : [this.totalNumTxs, false]; + const maxLevel = this.numMergeLevels + 1n; + let placeholder = currentIndex; + for (let i = 0; i < maxLevel - currentLevel; i++) { + ({ thisLevelSize, thisIndex: placeholder, shiftUp } = moveUpMergeLevel(thisLevelSize, placeholder, shiftUp)); + } + let thisIndex = currentIndex; + let mergeLevel = currentLevel; + while (thisIndex >= thisLevelSize && mergeLevel != 0n) { + mergeLevel -= 1n; + ({ thisLevelSize, thisIndex, shiftUp } = moveUpMergeLevel(thisLevelSize, thisIndex, shiftUp)); + } + return [mergeLevel - 1n, thisIndex >> 1n, thisIndex & 1n]; + } +``` + For example, `Base 4` above starts with `level = 3` and `index = 4`. Since we have an odd number of transactions at this level, `thisLevelSize` is set to 4 with `shiftUp = true`. + + The while loop triggers and shifts up our node to `level = 2` and `index = 2`. This level (containing `Merge 0` and `Merge 1`) is of even length, so the loop continues. The next iteration shifts up to `level = 1` and `index = 1` - we now have an odd level, so the loop stops. The actual position of `Base 4` is therefore at `level = 1` and `index = 1`. This function returns the parent level of the input node, so we return `level = 0`, `index = 0`, correctly indicating that the parent of `Base 4` is the root. + + +### Flexible wonky trees + +We can also encode the structure of *any* binary merkle tree by tracking `number_of_branches` and `number_of_leaves` for each node in the tree. This encoding was originally designed for [logs](../logs/index.md) before they were included in the `txs_effects_hash`, so the below explanation references the leaves stored in relation to logs and transactions. + +The benefit of this method as opposed to the one above is allowing for any binary structure and therefore allowing for 'skipping' leaves with no information. However, the encoding grows as the tree grows, by at least 2 bytes per node. The above implementation only requires the number of leaves to be encoded, which will likely only require a single field to store. + + + +#### Encoding + +1. The encoded logs data of a transaction is a flattened array of all logs data within the transaction: + + _`tx_logs_data = [number_of_logs, ...log_data_0, ...log_data_1, ...]`_ + +2. The encoded logs data of a block is a flatten array of a collection of the above _tx_logs_data_, with hints facilitating hashing replay in a binary tree structure: + + _`block_logs_data = [number_of_branches, number_of_transactions, ...tx_logs_data_0, ...tx_logs_data_1, ...]`_ + + - _number_of_transactions_ is the number of leaves in the left-most branch, restricted to either _1_ or _2_. + - _number_of_branches_ is the depth of the parent node of the left-most leaf. + +Here is a step-by-step example to construct the _`block_logs_data`_: + +1. A rollup, _R01_, merges two transactions: _tx0_ containing _tx_logs_data_0_, and _tx1_ containing _tx_logs_data_1_: + + ```mermaid + flowchart BT + tx0((tx0)) + tx1((tx1)) + R01((R01)) + tx0 --- R01 + tx1 --- R01 + ``` + + _block_logs_data_: _`[0, 2, ...tx_logs_data_0, ...tx_logs_data_1]`_ + + Where _0_ is the depth of the node _R01_, and _2_ is the number of aggregated _tx_logs_data_ of _R01_. + +2. Another rollup, _R23_, merges two transactions: _tx3_ containing _tx_logs_data_3_, and _tx2_ without any logs: + + ```mermaid + flowchart BT + tx2((tx2)) + tx3((tx3)) + R23((R23)) + tx2 -. no logs .- R23 + tx3 --- R23 + ``` + + _block_logs_data_: _`[0, 1, ...tx_logs_data_3]`_ + + Here, the number of aggregated _tx_logs_data_ is _1_. + +3. A rollup, _RA_, merges the two rollups _R01_ and _R23_: + + ```mermaid + flowchart BT + tx0((tx0)) + tx1((tx1)) + R01((R01)) + tx0 --- R01 + tx1 --- R01 + tx2((tx2)) + tx3((tx3)) + R23((R23)) + tx2 -.- R23 + tx3 --- R23 + RA((RA)) + R01 --- RA + R23 --- RA + ``` + + _block_logs_data_: _`[1, 2, ...tx_logs_data_0, ...tx_logs_data_1, 0, 1, ...tx_logs_data_3]`_ + + The result is the _block_logs_data_ of _R01_ concatenated with the _block_logs_data_ of _R23_, with the _number_of_branches_ of _R01_ incremented by _1_. The updated value of _number_of_branches_ (_0 + 1_) is also the depth of the node _R01_. + +4. A rollup, _RB_, merges the above rollup _RA_ and another rollup _R45_: + + ```mermaid + flowchart BT + tx0((tx0)) + tx1((tx1)) + R01((R01)) + tx0 --- R01 + tx1 --- R01 + tx2((tx2)) + tx3((tx3)) + R23((R23)) + tx2 -.- R23 + tx3 --- R23 + RA((RA)) + R01 --- RA + R23 --- RA + tx4((tx4)) + tx5((tx5)) + R45((R45)) + tx4 --- R45 + tx5 --- R45 + RB((RB)) + RA --- RB + R45 --- RB + ``` + + _block_logs_data_: _`[2, 2, ...tx_logs_data_0, ...tx_logs_data_1, 0, 1, ...tx_logs_data_3, 0, 2, ...tx_logs_data_4, ...tx_logs_data_5]`_ + + The result is the concatenation of the _block_logs_data_ from both rollups, with the _number_of_branches_ of the left-side rollup, _RA_, incremented by _1_. + +#### Verification + +Upon receiving a proof and its encoded logs data, the entity can ensure the correctness of the provided _block_logs_data_ by verifying that the _accumulated_logs_hash_ in the proof can be derived from it: + +```js +const accumulated_logs_hash = compute_accumulated_logs_hash(block_logs_data); +assert(accumulated_logs_hash == proof.accumulated_logs_hash); +assert(block_logs_data.accumulated_logs_length == proof.accumulated_logs_length); + +function compute_accumulated_logs_hash(logs_data) { + const number_of_branches = logs_data.read_u32(); + + const number_of_transactions = logs_data.read_u32(); + let res = hash_tx_logs_data(logs_data); + if number_of_transactions == 2 { + res = hash(res, hash_tx_logs_data(logs_data)); + } + + for (let i = 0; i < number_of_branches; ++i) { + const res_right = compute_accumulated_logs_hash(logs_data); + res = hash(res, res_right); + } + + return res; +} + +function hash_tx_logs_data(logs_data) { + const number_of_logs = logs_data.read_u32(); + let res = hash_log_data(logs_data); + for (let i = 1; i < number_of_logs; ++i) { + const log_hash = hash_log_data(logs_data); + res = hash(res, log_hash); + } + return res; +} +``` \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index 9e9383590d8..0093b1ab1b0 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -109,6 +109,7 @@ export default { "protocol-specs/state/note-hash-tree", "protocol-specs/state/nullifier-tree", "protocol-specs/state/public-data-tree", + "protocol-specs/state/wonky-tree", ], }, { diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 2ac9123a82f..13046308571 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -16,6 +16,7 @@ import {HeaderLib} from "./libraries/HeaderLib.sol"; import {Hash} from "./libraries/Hash.sol"; import {Errors} from "./libraries/Errors.sol"; import {Constants} from "./libraries/ConstantsGen.sol"; +import {MerkleLib} from "./libraries/MerkleLib.sol"; import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol"; // Contracts @@ -149,10 +150,10 @@ contract Rollup is IRollup { revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash); } - // Currently trying out storing each tx's L2 to L1 messages in variable height trees (smallest tree required) - // => path lengths will differ and we cannot provide one here - // We can provide a minimum which is the height of the rollup layers (txTreeHeight) and the smallest 'tree' (1 layer) - uint256 l2ToL1TreeMinHeight = header.contentCommitment.txTreeHeight + 1; + // TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim + // Min size = smallest path of the rollup tree + 1 + (uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs); + uint256 l2ToL1TreeMinHeight = min + 1; OUTBOX.insert( header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeMinHeight ); diff --git a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol index c01b2f378f1..6eba97fca43 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol @@ -11,7 +11,7 @@ import {DataStructures} from "../../libraries/DataStructures.sol"; * and will be consumed by the portal contracts. */ interface IOutbox { - event RootAdded(uint256 indexed l2BlockNumber, bytes32 indexed root, uint256 height); + event RootAdded(uint256 indexed l2BlockNumber, bytes32 indexed root, uint256 minHeight); event MessageConsumed( uint256 indexed l2BlockNumber, bytes32 indexed root, diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 7481445954d..e2c82cf5496 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -46,7 +46,7 @@ library Errors { error Rollup__TimestampInFuture(); // 0xbc1ce916 error Rollup__TimestampTooOld(); // 0x72ed9c81 error Rollup__UnavailableTxs(bytes32 txsHash); // 0x414906c3 - error Rollup__InvalidSequencer(address sequencer); + error Rollup__InvalidSequencer(address sequencer); // 0xa127a106 // Registry error Registry__RollupNotRegistered(address rollup); // 0xa1fee4cf @@ -54,6 +54,7 @@ library Errors { //TxsDecoder error TxsDecoder__InvalidLogsLength(uint256 expected, uint256 actual); // 0x829ca981 + error TxsDecoder__TxsTooLarge(uint256 expected, uint256 actual); // 0xc7d44a62 // HeaderLib error HeaderLib__InvalidHeaderSize(uint256 expected, uint256 actual); // 0xf3ccb247 diff --git a/l1-contracts/src/core/libraries/HeaderLib.sol b/l1-contracts/src/core/libraries/HeaderLib.sol index 877c617d7fa..e461b1381f1 100644 --- a/l1-contracts/src/core/libraries/HeaderLib.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -25,7 +25,7 @@ import {Hash} from "./Hash.sol"; * | 0x0000 | 0x20 | lastArchive.root * | 0x0020 | 0x04 | lastArchive.nextAvailableLeafIndex * | | | ContentCommitment { - * | 0x0024 | 0x20 | txTreeHeight + * | 0x0024 | 0x20 | numTxs * | 0x0044 | 0x20 | txsEffectsHash * | 0x0064 | 0x20 | inHash * | 0x0084 | 0x20 | outHash @@ -90,7 +90,7 @@ library HeaderLib { } struct ContentCommitment { - uint256 txTreeHeight; + uint256 numTxs; bytes32 txsEffectsHash; bytes32 inHash; bytes32 outHash; @@ -163,7 +163,7 @@ library HeaderLib { ); // Reading ContentCommitment - header.contentCommitment.txTreeHeight = uint256(bytes32(_header[0x0024:0x0044])); + header.contentCommitment.numTxs = uint256(bytes32(_header[0x0024:0x0044])); header.contentCommitment.txsEffectsHash = bytes32(_header[0x0044:0x0064]); header.contentCommitment.inHash = bytes32(_header[0x0064:0x0084]); header.contentCommitment.outHash = bytes32(_header[0x0084:0x00a4]); @@ -204,7 +204,7 @@ library HeaderLib { // must match the order in the Header.getFields fields[0] = _header.lastArchive.root; fields[1] = bytes32(uint256(_header.lastArchive.nextAvailableLeafIndex)); - fields[2] = bytes32(_header.contentCommitment.txTreeHeight); + fields[2] = bytes32(_header.contentCommitment.numTxs); fields[3] = _header.contentCommitment.txsEffectsHash; fields[4] = _header.contentCommitment.inHash; fields[5] = _header.contentCommitment.outHash; diff --git a/l1-contracts/src/core/libraries/MerkleLib.sol b/l1-contracts/src/core/libraries/MerkleLib.sol index c7ab82502b0..89dc020a5a2 100644 --- a/l1-contracts/src/core/libraries/MerkleLib.sol +++ b/l1-contracts/src/core/libraries/MerkleLib.sol @@ -51,4 +51,64 @@ library MerkleLib { revert Errors.MerkleLib__InvalidRoot(_expectedRoot, subtreeRoot, _leaf, _index); } } + + /** + * @notice Computes the minimum and maximum path size of an unbalanced tree. + * @dev Follows structure of rollup circuits by greedy filling subtrees. + * @param _numTxs - The number of txs to form into subtrees. + * @return (min, max) - The min and max path sizes. + */ + function computeMinMaxPathLength(uint256 _numTxs) internal pure returns (uint256, uint256) { + uint256 numTxs = _numTxs < 2 ? 2 : _numTxs; + uint256 numSubtrees = 0; + uint256 currentSubtreeSize = 1; + uint256 currentSubtreeHeight = 0; + uint256 firstSubtreeHeight; + uint256 finalSubtreeHeight; + while (numTxs != 0) { + // If size & txs == 0, the subtree doesn't exist for this number of txs + if (currentSubtreeSize & numTxs == 0) { + currentSubtreeSize <<= 1; + currentSubtreeHeight++; + continue; + } + // Assign the smallest rightmost subtree height + if (numSubtrees == 0) finalSubtreeHeight = currentSubtreeHeight; + // Assign the largest leftmost subtree height + if (numTxs - currentSubtreeSize == 0) firstSubtreeHeight = currentSubtreeHeight; + numTxs -= currentSubtreeSize; + currentSubtreeSize <<= 1; + currentSubtreeHeight++; + numSubtrees++; + } + if (numSubtrees == 1) { + // We have a balanced tree + return (firstSubtreeHeight, firstSubtreeHeight); + } + uint256 min = finalSubtreeHeight + numSubtrees - 1; + uint256 max = firstSubtreeHeight + 1; + return (min, max); + } + + /** + * @notice Calculates a tree height from the amount of elements in the tree + * @dev - This mirrors the function in TestUtil, but assumes _size is an exact power of 2 or = 1 + * @param _size - The number of elements in the tree + */ + function calculateTreeHeightFromSize(uint256 _size) internal pure returns (uint256) { + /// We need the height of the tree that will contain all of our leaves, + /// hence the next highest power of two from the amount of leaves - Math.ceil(Math.log2(x)) + uint256 height = 0; + + if (_size == 1) { + return 0; + } + + /// While size > 1, we divide by two, and count how many times we do this; producing a rudimentary way of calculating Math.Floor(Math.log2(x)) + while (_size > 1) { + _size >>= 1; + height++; + } + return height; + } } diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 43f00cc5b8e..e3ecc6ecb2c 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -261,7 +261,7 @@ library TxsDecoder { } } - return computeRoot(vars.baseLeaves); + return computeUnbalancedRoot(vars.baseLeaves); } /** @@ -516,6 +516,40 @@ library TxsDecoder { return _leafs[0]; } + /** + * @notice Computes the root for a binary unbalanced Merkle-tree given the leaves. + * @dev Filled in greedily with subtrees. Useful for txsEffectHash and outHash tree. + * @param _leaves - The 32 bytes leafs to build the tree of. + * @return The root of the Merkle tree. + */ + function computeUnbalancedRoot(bytes32[] memory _leaves) internal pure returns (bytes32) { + // e.g. an unbalanced tree of 7 txs will contain subtrees of 4, 2, and 1 tx(s) = 111 + // e.g. an unbalanced tree of 9 txs will contain subtrees of 8 and 1 tx(s) = 1001 + // We collect the roots of each subtree + bytes32 root; + uint256 currentSubtreeSize = 1; + uint256 numTxs = _leaves.length; + // We must calculate the smaller rightmost subtrees first, hence starting at 1 + while (numTxs != 0) { + // If size & txs == 0, the subtree doesn't exist for this number of txs + if (currentSubtreeSize & numTxs == 0) { + currentSubtreeSize <<= 1; + continue; + } + bytes32[] memory leavesInSubtree = new bytes32[](currentSubtreeSize); + uint256 start = numTxs - currentSubtreeSize; + for (uint256 i = start; i < numTxs; i++) { + leavesInSubtree[i - start] = _leaves[i]; + } + bytes32 subtreeRoot = computeRoot(leavesInSubtree); + root = + numTxs == _leaves.length ? subtreeRoot : Hash.sha256ToField(bytes.concat(subtreeRoot, root)); + numTxs -= currentSubtreeSize; + currentSubtreeSize <<= 1; + } + return root; + } + /** * @notice Wrapper around the slicing to avoid some stack too deep * @param _data - The data to slice @@ -592,18 +626,6 @@ library TxsDecoder { } else if (_numTxEffects == 1) { return 1; } - - uint32 v = _numTxEffects; - - // the following rounds _numTxEffects up to the next power of 2 (works only for 4 bytes value!) - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - return v - _numTxEffects; + return 0; } } diff --git a/l1-contracts/src/core/messagebridge/Outbox.sol b/l1-contracts/src/core/messagebridge/Outbox.sol index b62665d8a87..db1ccb76447 100644 --- a/l1-contracts/src/core/messagebridge/Outbox.sol +++ b/l1-contracts/src/core/messagebridge/Outbox.sol @@ -100,19 +100,14 @@ contract Outbox is IOutbox { if (rootData.nullified[_leafIndex]) { revert Errors.Outbox__AlreadyNullified(_l2BlockNumber, _leafIndex); } + // TODO(#7218): We will eventually move back to a balanced tree and constrain the path length + // to be equal to height - for now we just check the min // Min height = height of rollup layers // The smallest num of messages will require a subtree of height 1 - uint256 treeHeight = rootData.minHeight; - if (treeHeight > _path.length) { - revert Errors.Outbox__InvalidPathLength(treeHeight, _path.length); - } - - // Max height = height of rollup layers + max possible subtree height - // The max num of messages N will require a subtree of height log2(N) - uint256 maxSubtreeHeight = calculateTreeHeightFromSize(Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX); - if (treeHeight + maxSubtreeHeight < _path.length) { - revert Errors.Outbox__InvalidPathLength(treeHeight + maxSubtreeHeight, _path.length); + uint256 minHeight = rootData.minHeight; + if (minHeight > _path.length) { + revert Errors.Outbox__InvalidPathLength(minHeight, _path.length); } bytes32 messageHash = _message.sha256ToField(); @@ -138,22 +133,4 @@ contract Outbox is IOutbox { { return roots[_l2BlockNumber].nullified[_leafIndex]; } - - /** - * @notice Calculates a tree height from the amount of elements in the tree - * @dev - This mirrors the function in TestUtil, but assumes _size is an exact power of 2 - * @param _size - The number of elements in the tree - */ - function calculateTreeHeightFromSize(uint256 _size) internal pure returns (uint256) { - /// We need the height of the tree that will contain all of our leaves, - /// hence the next highest power of two from the amount of leaves - Math.ceil(Math.log2(x)) - uint256 height = 0; - - /// While size > 1, we divide by two, and count how many times we do this; producing a rudimentary way of calculating Math.Floor(Math.log2(x)) - while (_size > 1) { - _size >>= 1; - height++; - } - return height; - } } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 4d8613db027..3523412dd81 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -162,15 +162,15 @@ contract RollupTest is DecoderBase { // NB: The below works with full blocks because we require the largest possible subtrees // for L2 to L1 messages - usually we make variable height subtrees, the roots of which // form a balanced tree - uint256 numTxsWithPadding = txsHelper.computeNumTxEffectsToPad(numTxs) + numTxs; + // The below is a little janky - we know that this test deals with full txs with equal numbers // of msgs or txs with no messages, so the division works // TODO edit full.messages to include information about msgs per tx? uint256 subTreeHeight = merkleTestUtil.calculateTreeHeightFromSize( full.messages.l2ToL1Messages.length == 0 ? 0 : full.messages.l2ToL1Messages.length / numTxs ); - uint256 outHashTreeHeight = merkleTestUtil.calculateTreeHeightFromSize(numTxsWithPadding); - uint256 numMessagesWithPadding = numTxsWithPadding * Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX; + uint256 outHashTreeHeight = merkleTestUtil.calculateTreeHeightFromSize(numTxs); + uint256 numMessagesWithPadding = numTxs * Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX; uint256 treeHeight = subTreeHeight + outHashTreeHeight; NaiveMerkle tree = new NaiveMerkle(treeHeight); diff --git a/l1-contracts/test/decoders/Base.sol b/l1-contracts/test/decoders/Base.sol index 8301379c8f2..d962bbac376 100644 --- a/l1-contracts/test/decoders/Base.sol +++ b/l1-contracts/test/decoders/Base.sol @@ -73,8 +73,8 @@ contract DecoderBase is Test { struct ContentCommitment { bytes32 inHash; + uint256 numTxs; bytes32 outHash; - uint256 txTreeHeight; bytes32 txsEffectsHash; } diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index bd7eef2bf4b..a3f6c3958ca 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -72,11 +72,7 @@ contract DecodersTest is DecoderBase { { DecoderBase.ContentCommitment memory contentCommitment = referenceHeader.contentCommitment; - assertEq( - header.contentCommitment.txTreeHeight, - contentCommitment.txTreeHeight, - "Invalid txTreeSize" - ); + assertEq(header.contentCommitment.numTxs, contentCommitment.numTxs, "Invalid txTreeSize"); assertEq( header.contentCommitment.txsEffectsHash, contentCommitment.txsEffectsHash, @@ -332,26 +328,10 @@ contract DecodersTest is DecoderBase { numTxEffects = 3; paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 2 - numTxEffects, "Incorrect number of tx effects to pad"); - - numTxEffects = 5; - paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 3 - numTxEffects, "Incorrect number of tx effects to pad"); - - numTxEffects = 8; - paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 3 - numTxEffects, "Incorrect number of tx effects to pad"); - - numTxEffects = 10; - paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 4 - numTxEffects, "Incorrect number of tx effects to pad"); - - numTxEffects = 16; - paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 4 - numTxEffects, "Incorrect number of tx effects to pad"); + assertEq(paddedNumTxEffects, 0, "Incorrect number of tx effects to pad"); numTxEffects = 17; paddedNumTxEffects = txsHelper.computeNumTxEffectsToPad(numTxEffects); - assertEq(paddedNumTxEffects, 2 ** 5 - numTxEffects, "Incorrect number of tx effects to pad"); + assertEq(paddedNumTxEffects, 0, "Incorrect number of tx effects to pad"); } } diff --git a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol index 41b5352b270..f34fd9c3437 100644 --- a/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol +++ b/l1-contracts/test/decoders/helpers/TxsDecoderHelper.sol @@ -3,6 +3,7 @@ pragma solidity >=0.8.18; import {TxsDecoder} from "../../../src/core/libraries/decoders/TxsDecoder.sol"; +import {MerkleLib} from "../../../src/core/libraries/MerkleLib.sol"; contract TxsDecoderHelper { // A wrapper used such that we get "calldata" and not memory @@ -21,4 +22,12 @@ contract TxsDecoderHelper { function computeNumTxEffectsToPad(uint32 _numTxEffects) external pure returns (uint32) { return TxsDecoder.computeNumTxEffectsToPad(_numTxEffects); } + + function computeUnbalancedRoot(bytes32[] memory _leaves) external pure returns (bytes32) { + return TxsDecoder.computeUnbalancedRoot(_leaves); + } + + function computeMinMaxPathLength(uint32 _numTxEffects) external pure returns (uint256, uint256) { + return MerkleLib.computeMinMaxPathLength(_numTxEffects); + } } diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 3f6e46d2c1f..8698dda56e8 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -8,14 +8,14 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x1cf715c65eecea3dda1833ca8e9f7b23ca588a7ece864b957f919bb7f0890523", + "archive": "0x062d0b928c3e1fa5529032c8c663c4b3b1a359d03943f20667b02d87bf71a7ad", "body": "0x00000000", "txsEffectsHash": "0x00d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf2", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3", - "txTreeHeight": 1, + "numTxs": 2, "txsEffectsHash": "0x00d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf2" }, "globalVariables": { @@ -23,8 +23,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x154e0eb6154e0eb6154e0eb6154e0eb6154e0eb6", - "feeRecipient": "0x301bf845ed245d172febeaa6c1a11d59b6041b79531a00694f9042df161e2626", + "coinbase": "0x6adca08f06cc255a12c609d284c5861c1cad740c", + "feeRecipient": "0x09d7dc61a2ee0c764bc8f5954500c7b43d5422958e67d20144b3e738b04dfc07", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -55,8 +55,8 @@ } } }, - "header": "0x0afb332dff10b3b4221c5c26ead8202d94bb977f644c91b06dec3ee098acc2b600000001000000000000000000000000000000000000000000000000000000000000000100d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f27800000100021a6cc64c830b4914600d0296c3968c5d28c1b00c5c4b0b33d1f39d948edbd4000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000154e0eb6154e0eb6154e0eb6154e0eb6154e0eb6301bf845ed245d172febeaa6c1a11d59b6041b79531a00694f9042df161e2626000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00e1b985afe7ad2360a25bc829b614b5ef63e5cae914a38d99f59d5b2a5522fe", + "header": "0x0afb332dff10b3b4221c5c26ead8202d94bb977f644c91b06dec3ee098acc2b600000001000000000000000000000000000000000000000000000000000000000000000200d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f27800000100021a6cc64c830b4914600d0296c3968c5d28c1b00c5c4b0b33d1f39d948edbd4000001000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000006adca08f06cc255a12c609d284c5861c1cad740c09d7dc61a2ee0c764bc8f5954500c7b43d5422958e67d20144b3e738b04dfc07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x002aa4bb5409ae75e705b167d45ba569055b2ae62c67c1608f4cf17ac5129ad6", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 018b043a71a..a0706e4b24f 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,23 +8,23 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x2074c6a0cc1f2dd305c8614df3a7426eb3b20dac06850c5d6cb64910a5a1caef", + "archive": "0x0f049707f5cee10d833aea2adf93e1e3462eaa5b328576342fbea7837195c91a", "body": "0x00000000", "txsEffectsHash": "0x00d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf2", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3", - "txTreeHeight": 1, + "numTxs": 2, "txsEffectsHash": "0x00d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf2" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1718108388, + "timestamp": 1719332523, "version": 1, - "coinbase": "0x154e0eb6154e0eb6154e0eb6154e0eb6154e0eb6", - "feeRecipient": "0x301bf845ed245d172febeaa6c1a11d59b6041b79531a00694f9042df161e2626", + "coinbase": "0x6adca08f06cc255a12c609d284c5861c1cad740c", + "feeRecipient": "0x09d7dc61a2ee0c764bc8f5954500c7b43d5422958e67d20144b3e738b04dfc07", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1cf715c65eecea3dda1833ca8e9f7b23ca588a7ece864b957f919bb7f0890523" + "root": "0x062d0b928c3e1fa5529032c8c663c4b3b1a359d03943f20667b02d87bf71a7ad" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x1cf715c65eecea3dda1833ca8e9f7b23ca588a7ece864b957f919bb7f089052300000002000000000000000000000000000000000000000000000000000000000000000100d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f27800000180021a6cc64c830b4914600d0296c3968c5d28c1b00c5c4b0b33d1f39d948edbd4000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000666840e4154e0eb6154e0eb6154e0eb6154e0eb6154e0eb6301bf845ed245d172febeaa6c1a11d59b6041b79531a00694f9042df161e2626000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x002d5e3fa366ee431f598f8bc6060165320453e2ad908c3ad80b1e7d3c1a8006", + "header": "0x062d0b928c3e1fa5529032c8c663c4b3b1a359d03943f20667b02d87bf71a7ad00000002000000000000000000000000000000000000000000000000000000000000000200d09e7feff5a1049661763ded52742f02aac5d9793b27a40d6b9c60a668bdf200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f27800000180021a6cc64c830b4914600d0296c3968c5d28c1b00c5c4b0b33d1f39d948edbd4000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000667aeeab6adca08f06cc255a12c609d284c5861c1cad740c09d7dc61a2ee0c764bc8f5954500c7b43d5422958e67d20144b3e738b04dfc07000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00d8e0d4aa3b09294fa37c11ca7f356dc35c160e2ec9a95363a07dca826e1397", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index c0bc6a5c453..f9b76ee0dec 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -58,14 +58,14 @@ ] }, "block": { - "archive": "0x20fbe5614957ca8c09d74fd86ebbab70e3c95d6996b4e0086f7809f9d03a302d", + "archive": "0x1caafe747155b2a72a6f44744dc68fa9d6c3b605e5dc661383c5a202dd7ee7c8", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e08000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003410000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000003440000000000000000000000000000000000000000000000000000000000000345000000000000000000000000000000000000000000000000000000000000034600000000000000000000000000000000000000000000000000000000000003473f0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005690000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005660000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000056700000000000000000000000000000000000000000000000000000000000005710000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000057200000000000000000000000000000000000000000000000000000000000005690000000000000000000000000000000000000000000000000000000000000573000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000574000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000575000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000576000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000577000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000578000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005790000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000057a0000000000000000000000000000000000000000000000000000000000000571000000000000000000000000000000000000000000000000000000000000057b0000000000000000000000000000000000000000000000000000000000000572000000000000000000000000000000000000000000000000000000000000057c0000000000000000000000000000000000000000000000000000000000000573000000000000000000000000000000000000000000000000000000000000057d0000000000000000000000000000000000000000000000000000000000000574000000000000000000000000000000000000000000000000000000000000057e0000000000000000000000000000000000000000000000000000000000000575000000000000000000000000000000000000000000000000000000000000057f00000000000000000000000000000000000000000000000000000000000005760000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000057700000000000000000000000000000000000000000000000000000000000005810000000000000000000000000000000000000000000000000000000000000578000000000000000000000000000000000000000000000000000000000000058200000000000000000000000000000000000000000000000000000000000005790000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000057a0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000057b0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000057c0000000000000000000000000000000000000000000000000000000000000586000000000000000000000000000000000000000000000000000000000000057d0000000000000000000000000000000000000000000000000000000000000587000000000000000000000000000000000000000000000000000000000000057e0000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be08000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000000000000000000000000000000000000000000000000000000000382000000000000000000000000000000000000000000000000000000000000038300000000000000000000000000000000000000000000000000000000000003840000000000000000000000000000000000000000000000000000000000000385000000000000000000000000000000000000000000000000000000000000038600000000000000000000000000000000000000000000000000000000000003873f0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a900000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000005aa00000000000000000000000000000000000000000000000000000000000005a100000000000000000000000000000000000000000000000000000000000005ab00000000000000000000000000000000000000000000000000000000000005a200000000000000000000000000000000000000000000000000000000000005ac00000000000000000000000000000000000000000000000000000000000005a300000000000000000000000000000000000000000000000000000000000005ad00000000000000000000000000000000000000000000000000000000000005a400000000000000000000000000000000000000000000000000000000000005ae00000000000000000000000000000000000000000000000000000000000005a500000000000000000000000000000000000000000000000000000000000005af00000000000000000000000000000000000000000000000000000000000005a600000000000000000000000000000000000000000000000000000000000005b000000000000000000000000000000000000000000000000000000000000005a700000000000000000000000000000000000000000000000000000000000005b100000000000000000000000000000000000000000000000000000000000005a800000000000000000000000000000000000000000000000000000000000005b200000000000000000000000000000000000000000000000000000000000005a900000000000000000000000000000000000000000000000000000000000005b300000000000000000000000000000000000000000000000000000000000005aa00000000000000000000000000000000000000000000000000000000000005b400000000000000000000000000000000000000000000000000000000000005ab00000000000000000000000000000000000000000000000000000000000005b500000000000000000000000000000000000000000000000000000000000005ac00000000000000000000000000000000000000000000000000000000000005b600000000000000000000000000000000000000000000000000000000000005ad00000000000000000000000000000000000000000000000000000000000005b700000000000000000000000000000000000000000000000000000000000005ae00000000000000000000000000000000000000000000000000000000000005b800000000000000000000000000000000000000000000000000000000000005af00000000000000000000000000000000000000000000000000000000000005b900000000000000000000000000000000000000000000000000000000000005b000000000000000000000000000000000000000000000000000000000000005ba00000000000000000000000000000000000000000000000000000000000005b100000000000000000000000000000000000000000000000000000000000005bb00000000000000000000000000000000000000000000000000000000000005b200000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000000000000000000000000000000000000000005b300000000000000000000000000000000000000000000000000000000000005bd00000000000000000000000000000000000000000000000000000000000005b400000000000000000000000000000000000000000000000000000000000005be00000000000000000000000000000000000000000000000000000000000005b500000000000000000000000000000000000000000000000000000000000005bf00000000000000000000000000000000000000000000000000000000000005b600000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005b700000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005b800000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005b900000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005ba00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005bb00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005bd00000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005be00000000000000000000000000000000000000000000000000000000000005c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0800000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c73f00000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005ea00000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005eb00000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005ec00000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005ed00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005ee00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005ef00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005f000000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005f100000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005f200000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000005f300000000000000000000000000000000000000000000000000000000000005ea00000000000000000000000000000000000000000000000000000000000005f400000000000000000000000000000000000000000000000000000000000005eb00000000000000000000000000000000000000000000000000000000000005f500000000000000000000000000000000000000000000000000000000000005ec00000000000000000000000000000000000000000000000000000000000005f600000000000000000000000000000000000000000000000000000000000005ed00000000000000000000000000000000000000000000000000000000000005f700000000000000000000000000000000000000000000000000000000000005ee00000000000000000000000000000000000000000000000000000000000005f800000000000000000000000000000000000000000000000000000000000005ef00000000000000000000000000000000000000000000000000000000000005f900000000000000000000000000000000000000000000000000000000000005f000000000000000000000000000000000000000000000000000000000000005fa00000000000000000000000000000000000000000000000000000000000005f100000000000000000000000000000000000000000000000000000000000005fb00000000000000000000000000000000000000000000000000000000000005f200000000000000000000000000000000000000000000000000000000000005fc00000000000000000000000000000000000000000000000000000000000005f300000000000000000000000000000000000000000000000000000000000005fd00000000000000000000000000000000000000000000000000000000000005f400000000000000000000000000000000000000000000000000000000000005fe00000000000000000000000000000000000000000000000000000000000005f500000000000000000000000000000000000000000000000000000000000005ff00000000000000000000000000000000000000000000000000000000000005f6000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000005f7000000000000000000000000000000000000000000000000000000000000060100000000000000000000000000000000000000000000000000000000000005f8000000000000000000000000000000000000000000000000000000000000060200000000000000000000000000000000000000000000000000000000000005f9000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000000000000000000000000000000000005fa000000000000000000000000000000000000000000000000000000000000060400000000000000000000000000000000000000000000000000000000000005fb000000000000000000000000000000000000000000000000000000000000060500000000000000000000000000000000000000000000000000000000000005fc000000000000000000000000000000000000000000000000000000000000060600000000000000000000000000000000000000000000000000000000000005fd000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000005fe0000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e08000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004010000000000000000000000000000000000000000000000000000000000000402000000000000000000000000000000000000000000000000000000000000040300000000000000000000000000000000000000000000000000000000000004040000000000000000000000000000000000000000000000000000000000000405000000000000000000000000000000000000000000000000000000000000040600000000000000000000000000000000000000000000000000000000000004073f0000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006290000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000062a0000000000000000000000000000000000000000000000000000000000000621000000000000000000000000000000000000000000000000000000000000062b0000000000000000000000000000000000000000000000000000000000000622000000000000000000000000000000000000000000000000000000000000062c0000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000062d0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000062e0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000062f00000000000000000000000000000000000000000000000000000000000006260000000000000000000000000000000000000000000000000000000000000630000000000000000000000000000000000000000000000000000000000000062700000000000000000000000000000000000000000000000000000000000006310000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000063200000000000000000000000000000000000000000000000000000000000006290000000000000000000000000000000000000000000000000000000000000633000000000000000000000000000000000000000000000000000000000000062a0000000000000000000000000000000000000000000000000000000000000634000000000000000000000000000000000000000000000000000000000000062b0000000000000000000000000000000000000000000000000000000000000635000000000000000000000000000000000000000000000000000000000000062c0000000000000000000000000000000000000000000000000000000000000636000000000000000000000000000000000000000000000000000000000000062d0000000000000000000000000000000000000000000000000000000000000637000000000000000000000000000000000000000000000000000000000000062e0000000000000000000000000000000000000000000000000000000000000638000000000000000000000000000000000000000000000000000000000000062f00000000000000000000000000000000000000000000000000000000000006390000000000000000000000000000000000000000000000000000000000000630000000000000000000000000000000000000000000000000000000000000063a0000000000000000000000000000000000000000000000000000000000000631000000000000000000000000000000000000000000000000000000000000063b0000000000000000000000000000000000000000000000000000000000000632000000000000000000000000000000000000000000000000000000000000063c0000000000000000000000000000000000000000000000000000000000000633000000000000000000000000000000000000000000000000000000000000063d0000000000000000000000000000000000000000000000000000000000000634000000000000000000000000000000000000000000000000000000000000063e0000000000000000000000000000000000000000000000000000000000000635000000000000000000000000000000000000000000000000000000000000063f00000000000000000000000000000000000000000000000000000000000006360000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000063700000000000000000000000000000000000000000000000000000000000006410000000000000000000000000000000000000000000000000000000000000638000000000000000000000000000000000000000000000000000000000000064200000000000000000000000000000000000000000000000000000000000006390000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000063a0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000063b0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000063c0000000000000000000000000000000000000000000000000000000000000646000000000000000000000000000000000000000000000000000000000000063d0000000000000000000000000000000000000000000000000000000000000647000000000000000000000000000000000000000000000000000000000000063e0000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x006e4c1d10533ea35e67118a58a08e56c1c799d33ae60046b88aeb76bc5974a3", "decodedHeader": { "contentCommitment": { "inHash": "0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c", "outHash": "0x0071556a0e9f403540d572c98a081d21b325e7c802b8b3baf54f3d56fecb2230", - "txTreeHeight": 2, + "numTxs": 4, "txsEffectsHash": "0x006e4c1d10533ea35e67118a58a08e56c1c799d33ae60046b88aeb76bc5974a3" }, "globalVariables": { @@ -73,8 +73,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xcb460eb6cb460eb6cb460eb6cb460eb6cb460eb6", - "feeRecipient": "0x0cacc1f59212369f15989d55449e2460f787453f9a729749d363f4eee29d4c8c", + "coinbase": "0x38e74ed15dd5ab05fff041b5037372cce88aa7e9", + "feeRecipient": "0x1bf48a8c128750df4186da470571948ac0d14d79b3de69978f5a779fbdf547be", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -105,8 +105,8 @@ } } }, - "header": "0x0afb332dff10b3b4221c5c26ead8202d94bb977f644c91b06dec3ee098acc2b6000000010000000000000000000000000000000000000000000000000000000000000002006e4c1d10533ea35e67118a58a08e56c1c799d33ae60046b88aeb76bc5974a300089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0071556a0e9f403540d572c98a081d21b325e7c802b8b3baf54f3d56fecb22301864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001802f72d4fe80aa0b43708532e4fb05cdf574bfd36c8c6bba1ff4ec3c6e0ffc9b3a000001800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000cb460eb6cb460eb6cb460eb6cb460eb6cb460eb60cacc1f59212369f15989d55449e2460f787453f9a729749d363f4eee29d4c8c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00c13e59e7ffaa51e87daa6e5e2983fa353c47ff1883bfef731b9e784ade8399", + "header": "0x0afb332dff10b3b4221c5c26ead8202d94bb977f644c91b06dec3ee098acc2b6000000010000000000000000000000000000000000000000000000000000000000000004006e4c1d10533ea35e67118a58a08e56c1c799d33ae60046b88aeb76bc5974a300089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0071556a0e9f403540d572c98a081d21b325e7c802b8b3baf54f3d56fecb22301864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001802f72d4fe80aa0b43708532e4fb05cdf574bfd36c8c6bba1ff4ec3c6e0ffc9b3a000001800000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000038e74ed15dd5ab05fff041b5037372cce88aa7e91bf48a8c128750df4186da470571948ac0d14d79b3de69978f5a779fbdf547be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x0086d49b8b947a0b784ea6e86697292895d7f54a547fa954ab820140274340d4", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 62963048eb1..b3d023bdcda 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -58,23 +58,23 @@ ] }, "block": { - "archive": "0x1782e665d3991213a60e4add07b2bdf3c49bd81f93ca6ca1d79da91b937cebb2", + "archive": "0x0796e4e2dcd2e9d783732a42084fd8fd79acd7bbc7e9d511f5d0c59d4de6aa80", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e08000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004410000000000000000000000000000000000000000000000000000000000000442000000000000000000000000000000000000000000000000000000000000044300000000000000000000000000000000000000000000000000000000000004440000000000000000000000000000000000000000000000000000000000000445000000000000000000000000000000000000000000000000000000000000044600000000000000000000000000000000000000000000000000000000000004473f0000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006690000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000066a0000000000000000000000000000000000000000000000000000000000000661000000000000000000000000000000000000000000000000000000000000066b0000000000000000000000000000000000000000000000000000000000000662000000000000000000000000000000000000000000000000000000000000066c0000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000066d0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000066e0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000066f00000000000000000000000000000000000000000000000000000000000006660000000000000000000000000000000000000000000000000000000000000670000000000000000000000000000000000000000000000000000000000000066700000000000000000000000000000000000000000000000000000000000006710000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000067200000000000000000000000000000000000000000000000000000000000006690000000000000000000000000000000000000000000000000000000000000673000000000000000000000000000000000000000000000000000000000000066a0000000000000000000000000000000000000000000000000000000000000674000000000000000000000000000000000000000000000000000000000000066b0000000000000000000000000000000000000000000000000000000000000675000000000000000000000000000000000000000000000000000000000000066c0000000000000000000000000000000000000000000000000000000000000676000000000000000000000000000000000000000000000000000000000000066d0000000000000000000000000000000000000000000000000000000000000677000000000000000000000000000000000000000000000000000000000000066e0000000000000000000000000000000000000000000000000000000000000678000000000000000000000000000000000000000000000000000000000000066f00000000000000000000000000000000000000000000000000000000000006790000000000000000000000000000000000000000000000000000000000000670000000000000000000000000000000000000000000000000000000000000067a0000000000000000000000000000000000000000000000000000000000000671000000000000000000000000000000000000000000000000000000000000067b0000000000000000000000000000000000000000000000000000000000000672000000000000000000000000000000000000000000000000000000000000067c0000000000000000000000000000000000000000000000000000000000000673000000000000000000000000000000000000000000000000000000000000067d0000000000000000000000000000000000000000000000000000000000000674000000000000000000000000000000000000000000000000000000000000067e0000000000000000000000000000000000000000000000000000000000000675000000000000000000000000000000000000000000000000000000000000067f00000000000000000000000000000000000000000000000000000000000006760000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000067700000000000000000000000000000000000000000000000000000000000006810000000000000000000000000000000000000000000000000000000000000678000000000000000000000000000000000000000000000000000000000000068200000000000000000000000000000000000000000000000000000000000006790000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000067a0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000067b0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000067c0000000000000000000000000000000000000000000000000000000000000686000000000000000000000000000000000000000000000000000000000000067d0000000000000000000000000000000000000000000000000000000000000687000000000000000000000000000000000000000000000000000000000000067e0000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be08000000000000000000000000000000000000000000000000000000000000048000000000000000000000000000000000000000000000000000000000000004810000000000000000000000000000000000000000000000000000000000000482000000000000000000000000000000000000000000000000000000000000048300000000000000000000000000000000000000000000000000000000000004840000000000000000000000000000000000000000000000000000000000000485000000000000000000000000000000000000000000000000000000000000048600000000000000000000000000000000000000000000000000000000000004873f0000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a900000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000006aa00000000000000000000000000000000000000000000000000000000000006a100000000000000000000000000000000000000000000000000000000000006ab00000000000000000000000000000000000000000000000000000000000006a200000000000000000000000000000000000000000000000000000000000006ac00000000000000000000000000000000000000000000000000000000000006a300000000000000000000000000000000000000000000000000000000000006ad00000000000000000000000000000000000000000000000000000000000006a400000000000000000000000000000000000000000000000000000000000006ae00000000000000000000000000000000000000000000000000000000000006a500000000000000000000000000000000000000000000000000000000000006af00000000000000000000000000000000000000000000000000000000000006a600000000000000000000000000000000000000000000000000000000000006b000000000000000000000000000000000000000000000000000000000000006a700000000000000000000000000000000000000000000000000000000000006b100000000000000000000000000000000000000000000000000000000000006a800000000000000000000000000000000000000000000000000000000000006b200000000000000000000000000000000000000000000000000000000000006a900000000000000000000000000000000000000000000000000000000000006b300000000000000000000000000000000000000000000000000000000000006aa00000000000000000000000000000000000000000000000000000000000006b400000000000000000000000000000000000000000000000000000000000006ab00000000000000000000000000000000000000000000000000000000000006b500000000000000000000000000000000000000000000000000000000000006ac00000000000000000000000000000000000000000000000000000000000006b600000000000000000000000000000000000000000000000000000000000006ad00000000000000000000000000000000000000000000000000000000000006b700000000000000000000000000000000000000000000000000000000000006ae00000000000000000000000000000000000000000000000000000000000006b800000000000000000000000000000000000000000000000000000000000006af00000000000000000000000000000000000000000000000000000000000006b900000000000000000000000000000000000000000000000000000000000006b000000000000000000000000000000000000000000000000000000000000006ba00000000000000000000000000000000000000000000000000000000000006b100000000000000000000000000000000000000000000000000000000000006bb00000000000000000000000000000000000000000000000000000000000006b200000000000000000000000000000000000000000000000000000000000006bc00000000000000000000000000000000000000000000000000000000000006b300000000000000000000000000000000000000000000000000000000000006bd00000000000000000000000000000000000000000000000000000000000006b400000000000000000000000000000000000000000000000000000000000006be00000000000000000000000000000000000000000000000000000000000006b500000000000000000000000000000000000000000000000000000000000006bf00000000000000000000000000000000000000000000000000000000000006b600000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006b700000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006b800000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006b900000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006ba00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006bb00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006bc00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006bd00000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006be00000000000000000000000000000000000000000000000000000000000006c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0800000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c100000000000000000000000000000000000000000000000000000000000004c200000000000000000000000000000000000000000000000000000000000004c300000000000000000000000000000000000000000000000000000000000004c400000000000000000000000000000000000000000000000000000000000004c500000000000000000000000000000000000000000000000000000000000004c600000000000000000000000000000000000000000000000000000000000004c73f00000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006ea00000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006eb00000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006ec00000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006ed00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006ee00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006ef00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006f100000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006f200000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000006f300000000000000000000000000000000000000000000000000000000000006ea00000000000000000000000000000000000000000000000000000000000006f400000000000000000000000000000000000000000000000000000000000006eb00000000000000000000000000000000000000000000000000000000000006f500000000000000000000000000000000000000000000000000000000000006ec00000000000000000000000000000000000000000000000000000000000006f600000000000000000000000000000000000000000000000000000000000006ed00000000000000000000000000000000000000000000000000000000000006f700000000000000000000000000000000000000000000000000000000000006ee00000000000000000000000000000000000000000000000000000000000006f800000000000000000000000000000000000000000000000000000000000006ef00000000000000000000000000000000000000000000000000000000000006f900000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000000006fa00000000000000000000000000000000000000000000000000000000000006f100000000000000000000000000000000000000000000000000000000000006fb00000000000000000000000000000000000000000000000000000000000006f200000000000000000000000000000000000000000000000000000000000006fc00000000000000000000000000000000000000000000000000000000000006f300000000000000000000000000000000000000000000000000000000000006fd00000000000000000000000000000000000000000000000000000000000006f400000000000000000000000000000000000000000000000000000000000006fe00000000000000000000000000000000000000000000000000000000000006f500000000000000000000000000000000000000000000000000000000000006ff00000000000000000000000000000000000000000000000000000000000006f6000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000006f7000000000000000000000000000000000000000000000000000000000000070100000000000000000000000000000000000000000000000000000000000006f8000000000000000000000000000000000000000000000000000000000000070200000000000000000000000000000000000000000000000000000000000006f9000000000000000000000000000000000000000000000000000000000000070300000000000000000000000000000000000000000000000000000000000006fa000000000000000000000000000000000000000000000000000000000000070400000000000000000000000000000000000000000000000000000000000006fb000000000000000000000000000000000000000000000000000000000000070500000000000000000000000000000000000000000000000000000000000006fc000000000000000000000000000000000000000000000000000000000000070600000000000000000000000000000000000000000000000000000000000006fd000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000006fe0000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e08000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000005010000000000000000000000000000000000000000000000000000000000000502000000000000000000000000000000000000000000000000000000000000050300000000000000000000000000000000000000000000000000000000000005040000000000000000000000000000000000000000000000000000000000000505000000000000000000000000000000000000000000000000000000000000050600000000000000000000000000000000000000000000000000000000000005073f0000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007290000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000072a0000000000000000000000000000000000000000000000000000000000000721000000000000000000000000000000000000000000000000000000000000072b0000000000000000000000000000000000000000000000000000000000000722000000000000000000000000000000000000000000000000000000000000072c0000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000072d0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000072e0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000072f00000000000000000000000000000000000000000000000000000000000007260000000000000000000000000000000000000000000000000000000000000730000000000000000000000000000000000000000000000000000000000000072700000000000000000000000000000000000000000000000000000000000007310000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000073200000000000000000000000000000000000000000000000000000000000007290000000000000000000000000000000000000000000000000000000000000733000000000000000000000000000000000000000000000000000000000000072a0000000000000000000000000000000000000000000000000000000000000734000000000000000000000000000000000000000000000000000000000000072b0000000000000000000000000000000000000000000000000000000000000735000000000000000000000000000000000000000000000000000000000000072c0000000000000000000000000000000000000000000000000000000000000736000000000000000000000000000000000000000000000000000000000000072d0000000000000000000000000000000000000000000000000000000000000737000000000000000000000000000000000000000000000000000000000000072e0000000000000000000000000000000000000000000000000000000000000738000000000000000000000000000000000000000000000000000000000000072f00000000000000000000000000000000000000000000000000000000000007390000000000000000000000000000000000000000000000000000000000000730000000000000000000000000000000000000000000000000000000000000073a0000000000000000000000000000000000000000000000000000000000000731000000000000000000000000000000000000000000000000000000000000073b0000000000000000000000000000000000000000000000000000000000000732000000000000000000000000000000000000000000000000000000000000073c0000000000000000000000000000000000000000000000000000000000000733000000000000000000000000000000000000000000000000000000000000073d0000000000000000000000000000000000000000000000000000000000000734000000000000000000000000000000000000000000000000000000000000073e0000000000000000000000000000000000000000000000000000000000000735000000000000000000000000000000000000000000000000000000000000073f00000000000000000000000000000000000000000000000000000000000007360000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000073700000000000000000000000000000000000000000000000000000000000007410000000000000000000000000000000000000000000000000000000000000738000000000000000000000000000000000000000000000000000000000000074200000000000000000000000000000000000000000000000000000000000007390000000000000000000000000000000000000000000000000000000000000743000000000000000000000000000000000000000000000000000000000000073a0000000000000000000000000000000000000000000000000000000000000744000000000000000000000000000000000000000000000000000000000000073b0000000000000000000000000000000000000000000000000000000000000745000000000000000000000000000000000000000000000000000000000000073c0000000000000000000000000000000000000000000000000000000000000746000000000000000000000000000000000000000000000000000000000000073d0000000000000000000000000000000000000000000000000000000000000747000000000000000000000000000000000000000000000000000000000000073e0000000000000000000000000000000000000000000000000000000000000748000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x00c6c40beb1ea89a3546d3527c7f1e86eb3866a40ce5f9854afaefd49f51cd5b", "decodedHeader": { "contentCommitment": { "inHash": "0x00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb891937", "outHash": "0x008bb57ba402f4917a5169c695e37af3fa10ae64220de709573dbf127d9955e8", - "txTreeHeight": 2, + "numTxs": 4, "txsEffectsHash": "0x00c6c40beb1ea89a3546d3527c7f1e86eb3866a40ce5f9854afaefd49f51cd5b" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1718108261, + "timestamp": 1719332461, "version": 1, - "coinbase": "0xcb460eb6cb460eb6cb460eb6cb460eb6cb460eb6", - "feeRecipient": "0x0cacc1f59212369f15989d55449e2460f787453f9a729749d363f4eee29d4c8c", + "coinbase": "0x38e74ed15dd5ab05fff041b5037372cce88aa7e9", + "feeRecipient": "0x1bf48a8c128750df4186da470571948ac0d14d79b3de69978f5a779fbdf547be", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -82,7 +82,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x20fbe5614957ca8c09d74fd86ebbab70e3c95d6996b4e0086f7809f9d03a302d" + "root": "0x1caafe747155b2a72a6f44744dc68fa9d6c3b605e5dc661383c5a202dd7ee7c8" }, "stateReference": { "l1ToL2MessageTree": { @@ -105,8 +105,8 @@ } } }, - "header": "0x20fbe5614957ca8c09d74fd86ebbab70e3c95d6996b4e0086f7809f9d03a302d00000002000000000000000000000000000000000000000000000000000000000000000200c6c40beb1ea89a3546d3527c7f1e86eb3866a40ce5f9854afaefd49f51cd5b00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb891937008bb57ba402f4917a5169c695e37af3fa10ae64220de709573dbf127d9955e82e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802f1b0fefdce35aa5d17156a75b5df1128daa19c74dd56455e4545054d6a48eff000002800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066684065cb460eb6cb460eb6cb460eb6cb460eb6cb460eb60cacc1f59212369f15989d55449e2460f787453f9a729749d363f4eee29d4c8c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x008ce3a989d35090e9f9539ddecbc7b3f9f11b7c58321cf5c3b02ade618d3f67", + "header": "0x1caafe747155b2a72a6f44744dc68fa9d6c3b605e5dc661383c5a202dd7ee7c800000002000000000000000000000000000000000000000000000000000000000000000400c6c40beb1ea89a3546d3527c7f1e86eb3866a40ce5f9854afaefd49f51cd5b00212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb891937008bb57ba402f4917a5169c695e37af3fa10ae64220de709573dbf127d9955e82e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802f1b0fefdce35aa5d17156a75b5df1128daa19c74dd56455e4545054d6a48eff000002800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000667aee6d38e74ed15dd5ab05fff041b5037372cce88aa7e91bf48a8c128750df4186da470571948ac0d14d79b3de69978f5a779fbdf547be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x006abc0437c6efc01d8f9e20d9bc15d8181ffcbf03c5869276d004c087bc117a", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/merkle/UnbalancedMerkle.t.sol b/l1-contracts/test/merkle/UnbalancedMerkle.t.sol new file mode 100644 index 00000000000..ce3604351ab --- /dev/null +++ b/l1-contracts/test/merkle/UnbalancedMerkle.t.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; +import {Hash} from "../../src/core/libraries/Hash.sol"; + +import {TxsDecoderHelper} from "../decoders/helpers/TxsDecoderHelper.sol"; +/** + * Tests the tree construction for unbalanced rollups. + * Used for calculating txsEffectsHash over non balanced rollups - each leaf is one baseLeaf + * calculated in TxsDecoder.sol. + */ + +contract UnbalancedMerkleTest is Test { + /** + * Rollups are constructed greedily, with a set of N transactions split into subtrees of decreasing + * powers of 2. + * We list them in reverse order as we compute subtree roots from R to L + */ + TxsDecoderHelper internal txsHelper; + + function setUp() public { + txsHelper = new TxsDecoderHelper(); + } + + function testDecomp() public { + // Worst case - max num txs + uint32 numTxs = 65535; + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 15); + assertEq(max, 16); + // Single tree of 2**15 + numTxs = 32768; + (min, max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 15); + assertEq(max, 15); + // Single tree of 2**13 + numTxs = 8192; + (min, max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 13); + assertEq(max, 13); + // Trees of 2**12, 2**11, ... 2**0 + numTxs = 8191; + (min, max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 12); + assertEq(max, 13); + // Single tree of 2**8 + numTxs = 256; + (min, max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 8); + assertEq(max, 8); + // Left subtree of 2**8, right subtree of single leaf + numTxs = 257; + (min, max) = txsHelper.computeMinMaxPathLength(numTxs); + assertEq(min, 1); + assertEq(max, 9); + } + + // Example - 2 txs: + // + // root + // / \ + // base base + function testComputeTxsEffectsHash2() public { + // Generate some base leaves + bytes32[] memory baseLeaves = new bytes32[](2); + for (uint256 i = 0; i < 2; i++) { + baseLeaves[i] = Hash.sha256ToField(abi.encodePacked(i)); + } + // We have just one 'balanced' branch, so depth is 0 with 2 elements + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(2); + assertEq(min, 1); + assertEq(max, 1); + bytes32 rootTxsEffectsHash = Hash.sha256ToField(bytes.concat(baseLeaves[0], baseLeaves[1])); + bytes32 calculatedTxsEffectsHash = txsHelper.computeUnbalancedRoot(baseLeaves); + assertEq(calculatedTxsEffectsHash, rootTxsEffectsHash); + } + // Example - 3 txs: + // + // root + // / \ + // merge base + // / \ + // base base + + function testComputeTxsEffectsHash3() public { + // Generate some base leaves + bytes32[] memory baseLeaves = new bytes32[](3); + for (uint256 i = 0; i < 3; i++) { + baseLeaves[i] = Hash.sha256ToField(abi.encodePacked(i)); + } + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(3); + assertEq(min, 1); + assertEq(max, 2); + bytes32 mergeTxsEffectsHash = Hash.sha256ToField(bytes.concat(baseLeaves[0], baseLeaves[1])); + bytes32 rootTxsEffectsHash = + Hash.sha256ToField(bytes.concat(mergeTxsEffectsHash, baseLeaves[2])); + bytes32 calculatedTxsEffectsHash = txsHelper.computeUnbalancedRoot(baseLeaves); + assertEq(calculatedTxsEffectsHash, rootTxsEffectsHash); + } + + // Example - 5 txs: + // + // root + // / \ + // merge base + // / \ + // merge merge + // / \ / \ + // base base base base + function testComputeTxsEffectsHash5() public { + // Generate some base leaves + bytes32[] memory baseLeaves = new bytes32[](5); + for (uint256 i = 0; i < 5; i++) { + baseLeaves[i] = Hash.sha256ToField(abi.encodePacked(i)); + } + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(5); + assertEq(min, 1); + assertEq(max, 3); + bytes32 firstMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[0], baseLeaves[1])); + bytes32 secondMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[2], baseLeaves[3])); + bytes32 thirdMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(firstMergeTxsEffectsHash, secondMergeTxsEffectsHash)); + bytes32 rootTxsEffectsHash = + Hash.sha256ToField(bytes.concat(thirdMergeTxsEffectsHash, baseLeaves[4])); + bytes32 calculatedTxsEffectsHash = txsHelper.computeUnbalancedRoot(baseLeaves); + assertEq(calculatedTxsEffectsHash, rootTxsEffectsHash); + } + + // Example - 6 txs: + // + // root + // / \ + // merge4 merge3 + // / \ / \ + // merge1 merge2 base base + // / \ / \ + // base base base base + function testComputeTxsEffectsHash6() public { + // Generate some base leaves + bytes32[] memory baseLeaves = new bytes32[](6); + for (uint256 i = 0; i < 6; i++) { + baseLeaves[i] = Hash.sha256ToField(abi.encodePacked(i)); + } + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(6); + assertEq(min, 2); + assertEq(max, 3); + bytes32 firstMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[0], baseLeaves[1])); + bytes32 secondMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[2], baseLeaves[3])); + bytes32 thirdMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[4], baseLeaves[5])); + bytes32 fourthMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(firstMergeTxsEffectsHash, secondMergeTxsEffectsHash)); + bytes32 rootTxsEffectsHash = + Hash.sha256ToField(bytes.concat(fourthMergeTxsEffectsHash, thirdMergeTxsEffectsHash)); + bytes32 calculatedTxsEffectsHash = txsHelper.computeUnbalancedRoot(baseLeaves); + assertEq(calculatedTxsEffectsHash, rootTxsEffectsHash); + } + + // Example - 7 txs: + // + // root + // / \ + // merge3 merge5 + // / \ / \ + // merge1 merge2 merge4 base + // / \ / \ / \ + // base base base base base base + function testComputeTxsEffectsHash7() public { + // Generate some base leaves + bytes32[] memory baseLeaves = new bytes32[](7); + for (uint256 i = 0; i < 6; i++) { + baseLeaves[i] = Hash.sha256ToField(abi.encodePacked(i)); + } + (uint256 min, uint256 max) = txsHelper.computeMinMaxPathLength(7); + assertEq(min, 2); + assertEq(max, 3); + bytes32 firstMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[0], baseLeaves[1])); + bytes32 secondMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[2], baseLeaves[3])); + bytes32 thirdMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(firstMergeTxsEffectsHash, secondMergeTxsEffectsHash)); + bytes32 fourthMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(baseLeaves[4], baseLeaves[5])); + bytes32 fifthMergeTxsEffectsHash = + Hash.sha256ToField(bytes.concat(fourthMergeTxsEffectsHash, baseLeaves[6])); + + bytes32 rootTxsEffectsHash = + Hash.sha256ToField(bytes.concat(thirdMergeTxsEffectsHash, fifthMergeTxsEffectsHash)); + bytes32 calculatedTxsEffectsHash = txsHelper.computeUnbalancedRoot(baseLeaves); + assertEq(calculatedTxsEffectsHash, rootTxsEffectsHash); + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 0b643692f67..cbe1a5cb28b 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -12,9 +12,7 @@ struct BaseOrMergeRollupPublicInputs { // rollup_type is either 0 (base) or 1 (merge) // TODO(Kev): Why is this a u32 instead of a u8/u16? rollup_type : u32, - // subtree height is always 0 for base. - // so that we always pass-in two base/merge circuits of the same height into the next level of recursion - height_in_block_tree : Field, + num_txs : u32, constants : ConstantRollupData, start: PartialStateReference, @@ -35,7 +33,7 @@ impl Empty for BaseOrMergeRollupPublicInputs { fn empty() -> Self { BaseOrMergeRollupPublicInputs { rollup_type : 0 as u32, - height_in_block_tree : 0, + num_txs : 0 as u32, constants : ConstantRollupData::empty(), start: PartialStateReference::empty(), end: PartialStateReference::empty(), @@ -49,7 +47,7 @@ impl Empty for BaseOrMergeRollupPublicInputs { impl Eq for BaseOrMergeRollupPublicInputs { fn eq(self, other: Self) -> bool { (self.rollup_type == other.rollup_type) & - (self.height_in_block_tree == other.height_in_block_tree) & + (self.num_txs == other.num_txs) & (self.constants.eq(other.constants)) & (self.start.eq(other.start)) & (self.end.eq(other.end)) & @@ -64,7 +62,7 @@ impl Serialize for BaseOrMergeRollupPublicIn let mut fields: BoundedVec = BoundedVec::new(); fields.push(self.rollup_type as Field); - fields.push(self.height_in_block_tree as Field); + fields.push(self.num_txs as Field); fields.extend_from_array(self.constants.serialize()); fields.extend_from_array(self.start.serialize()); fields.extend_from_array(self.end.serialize()); @@ -83,7 +81,7 @@ impl Deserialize for BaseOrMergeRollupPublic let mut reader = Reader::new(fields); let item = Self { rollup_type: reader.read() as u32, - height_in_block_tree: reader.read(), + num_txs: reader.read() as u32, constants: reader.read_struct(ConstantRollupData::deserialize), start: reader.read_struct(PartialStateReference::deserialize), end: reader.read_struct(PartialStateReference::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index c68f2215780..e9317e56105 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -128,7 +128,7 @@ impl BaseRollupInputs { BaseOrMergeRollupPublicInputs { rollup_type: BASE_ROLLUP_TYPE, - height_in_block_tree: 0, + num_txs: 1, constants: self.constants, start: self.start, end: PartialStateReference { @@ -1147,10 +1147,10 @@ mod tests { } #[test] - unconstrained fn subtree_height_is_0() { + unconstrained fn num_txs_is_1() { let outputs = BaseRollupInputsBuilder::new().execute(); - assert_eq(outputs.height_in_block_tree, 0); + assert_eq(outputs.num_txs, 1); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index e74c8398eaf..4653d57bae0 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -15,28 +15,29 @@ use dep::types::{ }; /** - * Asserts that the rollup types are the same. - * Either both merge or both base + * Asserts that the tree formed by rollup circuits is filled greedily from L to R + * */ -pub fn assert_both_input_proofs_of_same_rollup_type( +pub fn assert_txs_filled_from_left( left: BaseOrMergeRollupPublicInputs, right: BaseOrMergeRollupPublicInputs ) { - assert(left.rollup_type == right.rollup_type, "input proofs are of different rollup types"); -} - -/** - * Asserts that the rollup subtree heights are the same and returns the height - * Returns the height of the rollup subtrees - */ -pub fn assert_both_input_proofs_of_same_height_and_return( - left: BaseOrMergeRollupPublicInputs, - right: BaseOrMergeRollupPublicInputs -) -> Field { - assert( - left.height_in_block_tree == right.height_in_block_tree, "input proofs are of different rollup heights" - ); - left.height_in_block_tree + // assert that the left rollup is either a base (1 tx) or a balanced tree (num txs = power of 2) + if (left.rollup_type == 1) { + let left_txs = left.num_txs; + let right_txs = right.num_txs; + // See https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 + assert( + (left_txs) & (left_txs - 1) == 0, "The rollup should be filled greedily from L to R, but received an unbalanced left subtree" + ); + assert( + right_txs <= left_txs, "The rollup should be filled greedily from L to R, but received a L txs < R txs" + ); + } else { + assert( + right.rollup_type == 0, "The rollup should be filled greedily from L to R, but received a L base and R merge" + ); + } } /** diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr index daa66bfff13..0fbdc3d22d4 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr @@ -28,10 +28,7 @@ impl MergeRollupInputs { let left = self.previous_rollup_data[0].base_or_merge_rollup_public_inputs; let right = self.previous_rollup_data[1].base_or_merge_rollup_public_inputs; - // check that both input proofs are either both "BASE" or "MERGE" and not a mix! - // this prevents having wonky commitment, nullifier and contract subtrees. - components::assert_both_input_proofs_of_same_rollup_type(left, right); - let current_height = components::assert_both_input_proofs_of_same_height_and_return(left, right); + components::assert_txs_filled_from_left(left, right); components::assert_equal_constants(left, right); components::assert_prev_rollups_follow_on_from_each_other(left, right); @@ -43,7 +40,7 @@ impl MergeRollupInputs { let public_inputs = BaseOrMergeRollupPublicInputs { rollup_type: MERGE_ROLLUP_TYPE, - height_in_block_tree: current_height + 1, + num_txs: left.num_txs + right.num_txs, constants: left.constants, start: left.start, end: right.end, @@ -63,7 +60,7 @@ mod tests { }; use dep::types::hash::accumulate_sha256; - #[test(should_fail_with="input proofs are of different rollup types")] + #[test(should_fail_with="The rollup should be filled greedily from L to R, but received a L base and R merge")] fn different_rollup_type_fails() { let mut inputs = default_merge_rollup_inputs(); inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.rollup_type = 0; @@ -71,14 +68,6 @@ mod tests { let _output = inputs.merge_rollup_circuit(); } - #[test(should_fail_with="input proofs are of different rollup heights")] - fn different_height_fails() { - let mut inputs = default_merge_rollup_inputs(); - inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree = 0; - inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; - let _output = inputs.merge_rollup_circuit(); - } - #[test(should_fail_with="input proofs have different constants")] fn constants_different_fails() { let mut inputs = default_merge_rollup_inputs(); @@ -116,20 +105,44 @@ mod tests { let mut inputs = default_merge_rollup_inputs(); let mut outputs = inputs.merge_rollup_circuit(); assert_eq(outputs.rollup_type, 1); - assert_eq( - outputs.height_in_block_tree, inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree + 1 - ); + assert_eq(outputs.num_txs, 2); // set inputs to have a merge rollup type and set the rollup height and test again. inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.rollup_type = 1; - inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; + inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.num_txs = 2; inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.rollup_type = 1; - inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; + inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.num_txs = 2; outputs = inputs.merge_rollup_circuit(); assert_eq(outputs.rollup_type, 1); - assert_eq(outputs.height_in_block_tree, 2); + assert_eq(outputs.num_txs, 4); + } + + #[test] + fn tx_subtrees_are_set_correctly() { + let mut inputs = default_merge_rollup_inputs(); + let mut outputs = inputs.merge_rollup_circuit(); + // Start with two bases => two single txs + assert_eq(outputs.num_txs, 2); + // Test one merge of 2 merged with one base + inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.rollup_type = 1; + inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.num_txs = 2; + outputs = inputs.merge_rollup_circuit(); + // Should have one subtree of size 2, and one of size 1 + assert_eq(outputs.num_txs, 3); + // Test two merges, each with a subtree of 2 + inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.rollup_type = 1; + inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.num_txs = 2; + outputs = inputs.merge_rollup_circuit(); + // Should have one subtree of size 4 + assert_eq(outputs.num_txs, 4); + + // Test two merges, one with a subtree of 16, one with subtrees of 4 and 1 + inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.num_txs = 16; + inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.num_txs = 5; + outputs = inputs.merge_rollup_circuit(); + assert_eq(outputs.num_txs, 21); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr index e0864e6b27a..512e46b78e0 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr @@ -43,8 +43,7 @@ impl RootRollupInputs { let left = self.previous_rollup_data[0].base_or_merge_rollup_public_inputs; let right = self.previous_rollup_data[1].base_or_merge_rollup_public_inputs; - components::assert_both_input_proofs_of_same_rollup_type(left, right); - let _ = components::assert_both_input_proofs_of_same_height_and_return(left, right); + components::assert_txs_filled_from_left(left, right); components::assert_equal_constants(left, right); components::assert_prev_rollups_follow_on_from_each_other(left, right); @@ -63,7 +62,7 @@ impl RootRollupInputs { let state = StateReference { l1_to_l2_message_tree: new_l1_to_l2_message_tree_snapshot, partial: right.end }; let content_commitment = ContentCommitment { - tx_tree_height: right.height_in_block_tree + 1, + num_txs: (left.num_txs + right.num_txs) as Field, txs_effects_hash: components::compute_txs_effects_hash(self.previous_rollup_data), in_hash: self.l1_to_l2_roots.public_inputs.sha_root, out_hash: components::compute_out_hash(self.previous_rollup_data) diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr index df34d71d866..52edabc33e6 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr @@ -59,8 +59,8 @@ pub fn default_previous_rollup_data() -> [PreviousRollupData; 2] { previous_rollup_data[0].base_or_merge_rollup_public_inputs.rollup_type = BASE_ROLLUP_TYPE; previous_rollup_data[1].base_or_merge_rollup_public_inputs.rollup_type = BASE_ROLLUP_TYPE; - previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; + previous_rollup_data[0].base_or_merge_rollup_public_inputs.num_txs = 1; + previous_rollup_data[1].base_or_merge_rollup_public_inputs.num_txs = 1; previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash = 1; previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = 2; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr index 3279b6ab9f2..bc1b421134c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr @@ -4,7 +4,7 @@ use crate::{ }; struct ContentCommitment { - tx_tree_height: Field, + num_txs: Field, txs_effects_hash: Field, in_hash: Field, out_hash: Field, @@ -14,7 +14,7 @@ impl Serialize for ContentCommitment { fn serialize(self) -> [Field; CONTENT_COMMITMENT_LENGTH] { let mut fields: BoundedVec = BoundedVec::new(); - fields.push(self.tx_tree_height); + fields.push(self.num_txs); fields.push(self.txs_effects_hash); fields.push(self.in_hash); fields.push(self.out_hash); @@ -25,7 +25,7 @@ impl Serialize for ContentCommitment { impl Deserialize for ContentCommitment { fn deserialize(serialized: [Field; CONTENT_COMMITMENT_LENGTH]) -> Self { - let tx_tree_height = serialized[0]; + let num_txs = serialized[0]; let txs_effects_hash = serialized[1]; @@ -34,7 +34,7 @@ impl Deserialize for ContentCommitment { let out_hash = serialized[3]; Self { - tx_tree_height, + num_txs, txs_effects_hash, in_hash, out_hash, @@ -45,7 +45,7 @@ impl Deserialize for ContentCommitment { impl Empty for ContentCommitment { fn empty() -> Self { Self { - tx_tree_height: 0, + num_txs: 0, txs_effects_hash: 0, in_hash: 0, out_hash: 0, @@ -55,7 +55,7 @@ impl Empty for ContentCommitment { impl Eq for ContentCommitment { fn eq(self, other: Self) -> bool { - (self.tx_tree_height == other.tx_tree_height) + (self.num_txs == other.num_txs) & (self.txs_effects_hash == other.txs_effects_hash) & (self.in_hash == other.in_hash) & (self.out_hash == other.out_hash) diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index b7cbfdb577a..a4fcecef5f7 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -53,7 +53,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { type AztecKVStore } from '@aztec/kv-store'; import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; -import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; +import { SHA256Trunc, StandardTree, UnbalancedTree } from '@aztec/merkle-tree'; import { AztecKVTxPool, type P2P, createP2PClient } from '@aztec/p2p'; import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer'; import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; @@ -550,26 +550,16 @@ export class AztecNodeService implements AztecNode { true, ); - const l2toL1SubtreeRoots = l2toL1Subtrees.map(t => Fr.fromBuffer(t.getRoot(true))); - const treeHeight = block.header.contentCommitment.txTreeHeight.toNumber(); - // NOTE: This padding only works assuming that an 'empty' out hash is H(0,0) - const paddedl2toL1SubtreeRoots = padArrayEnd( - l2toL1SubtreeRoots, - Fr.fromBuffer(sha256Trunc(Buffer.alloc(64))), - 2 ** treeHeight, - ); + let l2toL1SubtreeRoots = l2toL1Subtrees.map(t => Fr.fromBuffer(t.getRoot(true))); + if (l2toL1SubtreeRoots.length < 2) { + l2toL1SubtreeRoots = padArrayEnd(l2toL1SubtreeRoots, Fr.fromBuffer(sha256Trunc(Buffer.alloc(64))), 2); + } + const maxTreeHeight = Math.ceil(Math.log2(l2toL1SubtreeRoots.length)); // The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA - const outHashTree = new StandardTree( - openTmpStore(true), - new SHA256Trunc(), - 'temp_outhash_sibling_path', - treeHeight, - 0n, - Fr, - ); - await outHashTree.appendLeaves(paddedl2toL1SubtreeRoots); + const outHashTree = new UnbalancedTree(new SHA256Trunc(), 'temp_outhash_sibling_path', maxTreeHeight, Fr); + await outHashTree.appendLeaves(l2toL1SubtreeRoots); - const pathOfTxInOutHashTree = await outHashTree.getSiblingPath(BigInt(indexOfMsgTx), true); + const pathOfTxInOutHashTree = await outHashTree.getSiblingPath(l2toL1SubtreeRoots[indexOfMsgTx].toBigInt()); // Append subtree path to out hash tree path const mergedPath = subtreePathOfL2ToL1Message.toBufferArray().concat(pathOfTxInOutHashTree.toBufferArray()); // Append binary index of subtree path to binary index of out hash tree path diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index 98d8b51ecab..c0e63aa43d3 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -48,39 +48,52 @@ export class Body { /** * Computes the transactions effects hash for the L2 block - * This hash is also computed in the `AvailabilityOracle` and the `Circuit`. + * This hash is also computed in the `AvailabilityOracle`. * @returns The txs effects hash. */ getTxsEffectsHash() { + // Adapted from proving-state.ts -> findMergeLevel and unbalanced_tree.ts + // Calculates the tree upwards layer by layer until we reach the root + // The L1 calculation instead computes the tree from right to left (slightly cheaper gas) + // TODO: A more thorough investigation of which method is cheaper, then use that method everywhere const computeRoot = (leaves: Buffer[]): Buffer => { - const layers: Buffer[][] = [leaves]; - let activeLayer = 0; - - while (layers[activeLayer].length > 1) { - const layer: Buffer[] = []; - const layerLength = layers[activeLayer].length; - - for (let i = 0; i < layerLength; i += 2) { - const left = layers[activeLayer][i]; - const right = layers[activeLayer][i + 1]; - - layer.push(sha256Trunc(Buffer.concat([left, right]))); + const depth = Math.ceil(Math.log2(leaves.length)); + let [layerWidth, nodeToShift] = + leaves.length & 1 ? [leaves.length - 1, leaves[leaves.length - 1]] : [leaves.length, Buffer.alloc(0)]; + // Allocate this layer's leaves and init the next layer up + let thisLayer = leaves.slice(0, layerWidth); + let nextLayer = []; + for (let i = 0; i < depth; i++) { + for (let j = 0; j < layerWidth; j += 2) { + // Store the hash of each pair one layer up + nextLayer[j / 2] = sha256Trunc(Buffer.concat([thisLayer[j], thisLayer[j + 1]])); } - - layers.push(layer); - activeLayer++; + layerWidth /= 2; + if (layerWidth & 1) { + if (nodeToShift.length) { + // If the next layer has odd length, and we have a node that needs to be shifted up, add it here + nextLayer.push(nodeToShift); + layerWidth += 1; + nodeToShift = Buffer.alloc(0); + } else { + // If we don't have a node waiting to be shifted, store the next layer's final node to be shifted + layerWidth -= 1; + nodeToShift = nextLayer[layerWidth]; + } + } + // reset the layers + thisLayer = nextLayer; + nextLayer = []; } - - return layers[layers.length - 1][0]; + // return the root + return thisLayer[0]; }; const emptyTxEffectHash = TxEffect.empty().hash(); - const leaves: Buffer[] = padArrayEnd( - this.txEffects.map(txEffect => txEffect.hash()), - emptyTxEffectHash, - this.numberOfTxsIncludingPadded, - ); - + let leaves: Buffer[] = this.txEffects.map(txEffect => txEffect.hash()); + if (leaves.length < 2) { + leaves = padArrayEnd(leaves, emptyTxEffectHash, 2); + } return computeRoot(leaves); } @@ -114,20 +127,7 @@ export class Body { return 2; } - // Note that the following could be implemented in a more simple way as "2 ** Math.ceil(Math.log2(numTxEffects));" - // but we want to keep the same logic as in Solidity and there we don't have the math functions. - let v = numTxEffects; - - // The following rounds numTxEffects up to the next power of 2 (works only for 4 bytes value!) - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - - return v; + return numTxEffects; } static random( diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index 6de8796aa5a..92e0145bb0e 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -6,7 +6,7 @@ import { CONTENT_COMMITMENT_LENGTH } from '../constants.gen.js'; export const NUM_BYTES_PER_SHA256 = 32; export class ContentCommitment { - constructor(public txTreeHeight: Fr, public txsEffectsHash: Buffer, public inHash: Buffer, public outHash: Buffer) { + constructor(public numTxs: Fr, public txsEffectsHash: Buffer, public inHash: Buffer, public outHash: Buffer) { if (txsEffectsHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`txsEffectsHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } @@ -32,12 +32,12 @@ export class ContentCommitment { } toBuffer() { - return serializeToBuffer(this.txTreeHeight, this.txsEffectsHash, this.inHash, this.outHash); + return serializeToBuffer(this.numTxs, this.txsEffectsHash, this.inHash, this.outHash); } toFields(): Fr[] { const serialized = [ - this.txTreeHeight, + this.numTxs, Fr.fromBuffer(this.txsEffectsHash), Fr.fromBuffer(this.inHash), Fr.fromBuffer(this.outHash), @@ -80,7 +80,7 @@ export class ContentCommitment { isEmpty(): boolean { return ( - this.txTreeHeight.isZero() && + this.numTxs.isZero() && this.txsEffectsHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) && this.inHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) && this.outHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) diff --git a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts index 0bb2f4603ec..d814dd1861c 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts @@ -15,11 +15,9 @@ export class BaseOrMergeRollupPublicInputs { */ public rollupType: RollupTypes, /** - * Rollup sub tree height. - * Note 1: Base rollup circuit always have a sub tree height of 0. - * Note 2: With each merge, the sub tree height increases by 1. + * Number of txs in this rollup. */ - public rollupSubtreeHeight: Fr, + public numTxs: number, /** * Data which is forwarded through the rollup circuits unchanged. */ @@ -59,7 +57,7 @@ export class BaseOrMergeRollupPublicInputs { const reader = BufferReader.asReader(buffer); return new BaseOrMergeRollupPublicInputs( reader.readNumber(), - Fr.fromBuffer(reader), + reader.readNumber(), reader.readObject(ConstantRollupData), reader.readObject(PartialStateReference), reader.readObject(PartialStateReference), @@ -77,7 +75,7 @@ export class BaseOrMergeRollupPublicInputs { toBuffer() { return serializeToBuffer( this.rollupType, - this.rollupSubtreeHeight, + this.numTxs, this.constants, this.start, diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 3b03eed8014..77956df0f35 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -922,7 +922,7 @@ export function makeBaseOrMergeRollupPublicInputs( ): BaseOrMergeRollupPublicInputs { return new BaseOrMergeRollupPublicInputs( RollupTypes.Base, - new Fr(0n), + 1, makeConstantBaseRollupData(seed + 0x200, globalVariables), makePartialStateReference(seed + 0x300), makePartialStateReference(seed + 0x400), diff --git a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index 17340f06675..af92189500d 100644 --- a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts @@ -262,7 +262,7 @@ describe('L1Publisher integration', () => { contentCommitment: { inHash: `0x${block.header.contentCommitment.inHash.toString('hex').padStart(64, '0')}`, outHash: `0x${block.header.contentCommitment.outHash.toString('hex').padStart(64, '0')}`, - txTreeHeight: Number(block.header.contentCommitment.txTreeHeight.toBigInt()), + numTxs: Number(block.header.contentCommitment.numTxs), txsEffectsHash: `0x${block.header.contentCommitment.txsEffectsHash.toString('hex').padStart(64, '0')}`, }, globalVariables: { @@ -484,6 +484,7 @@ describe('L1Publisher integration', () => { GasFees.empty(), ); const blockTicket = await buildBlock(globalVariables, txs, l1ToL2Messages); + await builder.setBlockCompleted(); const result = await blockTicket.provingPromise; expect(result.status).toBe(PROVING_STATUS.SUCCESS); const blockResult = await builder.finaliseBlock(); diff --git a/yarn-project/merkle-tree/src/index.ts b/yarn-project/merkle-tree/src/index.ts index 7ac5cb2dc6e..412a545aad3 100644 --- a/yarn-project/merkle-tree/src/index.ts +++ b/yarn-project/merkle-tree/src/index.ts @@ -8,6 +8,7 @@ export * from './sparse_tree/sparse_tree.js'; export { StandardIndexedTree } from './standard_indexed_tree/standard_indexed_tree.js'; export { StandardIndexedTreeWithAppend } from './standard_indexed_tree/test/standard_indexed_tree_with_append.js'; export * from './standard_tree/standard_tree.js'; +export * from './unbalanced_tree.js'; export { INITIAL_LEAF, getTreeMeta } from './tree_base.js'; export { newTree } from './new_tree.js'; export { loadTree } from './load_tree.js'; diff --git a/yarn-project/merkle-tree/src/unbalanced_tree.test.ts b/yarn-project/merkle-tree/src/unbalanced_tree.test.ts new file mode 100644 index 00000000000..14ee0252ee4 --- /dev/null +++ b/yarn-project/merkle-tree/src/unbalanced_tree.test.ts @@ -0,0 +1,273 @@ +import { sha256Trunc } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; +import { type FromBuffer } from '@aztec/foundation/serialize'; +import { openTmpStore } from '@aztec/kv-store/utils'; +import { type Hasher } from '@aztec/types/interfaces'; + +import { SHA256Trunc } from './sha_256.js'; +import { StandardTree } from './standard_tree/standard_tree.js'; +import { UnbalancedTree } from './unbalanced_tree.js'; + +const noopDeserializer: FromBuffer = { + fromBuffer: (buffer: Buffer) => buffer, +}; + +// Follows sol implementation and tests in UnbalancedMerkle.t.sol +describe('Wonky tree', () => { + let hasher: Hasher; + let tree: UnbalancedTree; + let leaves: Buffer[]; + + const createAndFillTree = async (size: number) => { + const depth = Math.ceil(Math.log2(size)); + const tree = new UnbalancedTree(hasher, `test`, depth, noopDeserializer); + const leaves = Array(size) + .fill(0) + .map((_, i) => sha256Trunc(new Fr(i).toBuffer())); + // For the final test, we make the final (shifted up) leaf be H(1, 2), so we can calculate the root + // with a standard tree easily. + if (leaves[30]) { + leaves[30] = hasher.hash(new Fr(1).toBuffer(), new Fr(2).toBuffer()); + } + await tree.appendLeaves(leaves); + return { tree, leaves }; + }; + + beforeAll(() => { + hasher = new SHA256Trunc(); + }); + + // Example - 2 txs: + // + // root + // / \ + // base base + describe('2 Transactions', () => { + beforeAll(async () => { + const res = await createAndFillTree(2); + tree = res.tree; + leaves = res.leaves; + }); + + it("Shouldn't accept more leaves", () => { + expect(() => tree.appendLeaves([Buffer.alloc(32)])).toThrow( + "Can't re-append to an unbalanced tree. Current has 2 leaves.", + ); + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(1); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + const expectedRoot = sha256Trunc(Buffer.concat([leaves[0], leaves[1]])); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling path', async () => { + const sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + expect(sibPath.pathSize).toEqual(1); + const expectedSibPath = [leaves[1]]; + expect(sibPath.toBufferArray()).toEqual(expectedSibPath); + }); + }); + + // Example - 3 txs: + // + // root + // / \ + // merge base + // / \ + // base base + describe('3 Transactions', () => { + beforeAll(async () => { + const res = await createAndFillTree(3); + tree = res.tree; + leaves = res.leaves; + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(2); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + const mergeNode = sha256Trunc(Buffer.concat([leaves[0], leaves[1]])); + const expectedRoot = sha256Trunc(Buffer.concat([mergeNode, leaves[2]])); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling path', async () => { + const sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + expect(sibPath.pathSize).toEqual(2); + const expectedSibPath = [leaves[1], leaves[2]]; + expect(sibPath.toBufferArray()).toEqual(expectedSibPath); + }); + }); + + // Example - 5 txs: + // + // root + // / \ + // merge base + // / \ + // merge merge + // / \ / \ + // base base base base + describe('5 Transactions', () => { + beforeAll(async () => { + const res = await createAndFillTree(5); + tree = res.tree; + leaves = res.leaves; + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(3); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + let leftMergeNode = sha256Trunc(Buffer.concat([leaves[0], leaves[1]])); + const rightMergeNode = sha256Trunc(Buffer.concat([leaves[2], leaves[3]])); + leftMergeNode = sha256Trunc(Buffer.concat([leftMergeNode, rightMergeNode])); + const expectedRoot = sha256Trunc(Buffer.concat([leftMergeNode, leaves[4]])); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling path', async () => { + const sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + expect(sibPath.pathSize).toEqual(3); + const expectedSibPath = [leaves[1], sha256Trunc(Buffer.concat([leaves[2], leaves[3]])), leaves[4]]; + expect(sibPath.toBufferArray()).toEqual(expectedSibPath); + }); + }); + + // Example - 6 txs: + // + // root + // / \ + // merge4 merge3 + // / \ / \ + // merge1 merge2 base base + // / \ / \ + // base base base base + describe('6 Transactions', () => { + beforeAll(async () => { + const res = await createAndFillTree(6); + tree = res.tree; + leaves = res.leaves; + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(3); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + let leftMergeNode = sha256Trunc(Buffer.concat([leaves[0], leaves[1]])); + let rightMergeNode = sha256Trunc(Buffer.concat([leaves[2], leaves[3]])); + leftMergeNode = sha256Trunc(Buffer.concat([leftMergeNode, rightMergeNode])); + rightMergeNode = sha256Trunc(Buffer.concat([leaves[4], leaves[5]])); + const expectedRoot = sha256Trunc(Buffer.concat([leftMergeNode, rightMergeNode])); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling path', async () => { + const sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + expect(sibPath.pathSize).toEqual(3); + const expectedSibPath = [ + leaves[1], + sha256Trunc(Buffer.concat([leaves[2], leaves[3]])), + sha256Trunc(Buffer.concat([leaves[4], leaves[5]])), + ]; + expect(sibPath.toBufferArray()).toEqual(expectedSibPath); + }); + }); + + // Example - 7 txs: + // + // root + // / \ + // merge3 merge5 + // / \ / \ + // merge1 merge2 merge4 base + // / \ / \ / \ + // base base base base base base + describe('7 Transactions', () => { + let secondMergeNode: Buffer; + let fifthMergeNode: Buffer; + beforeAll(async () => { + const res = await createAndFillTree(7); + tree = res.tree; + leaves = res.leaves; + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(3); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + const firstMergeNode = sha256Trunc(Buffer.concat([leaves[0], leaves[1]])); + secondMergeNode = sha256Trunc(Buffer.concat([leaves[2], leaves[3]])); + const thirdMergeNode = sha256Trunc(Buffer.concat([firstMergeNode, secondMergeNode])); + const fourthMergeNode = sha256Trunc(Buffer.concat([leaves[4], leaves[5]])); + fifthMergeNode = sha256Trunc(Buffer.concat([fourthMergeNode, leaves[6]])); + const expectedRoot = sha256Trunc(Buffer.concat([thirdMergeNode, fifthMergeNode])); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling path', async () => { + const sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + expect(sibPath.pathSize).toEqual(3); + const expectedSibPath = [leaves[1], secondMergeNode, fifthMergeNode]; + expect(sibPath.toBufferArray()).toEqual(expectedSibPath); + }); + }); + + // Example - 31 txs: + // The same as a standard 32 leaf balanced tree, but with the last 'leaf' shifted up one. + describe('31 Transactions', () => { + let stdTree: StandardTree; + beforeAll(async () => { + const res = await createAndFillTree(31); + tree = res.tree; + leaves = res.leaves; + stdTree = new StandardTree(openTmpStore(true), hasher, `temp`, 5, 0n, noopDeserializer); + // We have set the last leaf to be H(1, 2), so we can fill a 32 size tree with: + await stdTree.appendLeaves([...res.leaves.slice(0, 30), new Fr(1).toBuffer(), new Fr(2).toBuffer()]); + }); + + it('Correctly computes tree information', () => { + expect(tree.getNumLeaves()).toEqual(BigInt(leaves.length)); + expect(tree.getDepth()).toEqual(5); + expect(tree.findLeafIndex(leaves[0])).toEqual(0n); + }); + + it('Correctly computes root', () => { + const root = tree.getRoot(); + const expectedRoot = stdTree.getRoot(true); + expect(root).toEqual(expectedRoot); + }); + + it('Correctly computes sibling paths', async () => { + let sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[0].toString('hex'))); + let expectedSibPath = await stdTree.getSiblingPath(0n, true); + expect(sibPath).toEqual(expectedSibPath); + sibPath = await tree.getSiblingPath(BigInt('0x' + leaves[27].toString('hex'))); + expectedSibPath = await stdTree.getSiblingPath(27n, true); + expect(sibPath).toEqual(expectedSibPath); + }); + }); +}); diff --git a/yarn-project/merkle-tree/src/unbalanced_tree.ts b/yarn-project/merkle-tree/src/unbalanced_tree.ts new file mode 100644 index 00000000000..6920b5d1278 --- /dev/null +++ b/yarn-project/merkle-tree/src/unbalanced_tree.ts @@ -0,0 +1,239 @@ +import { SiblingPath } from '@aztec/circuit-types'; +import { type Bufferable, type FromBuffer, serializeToBuffer } from '@aztec/foundation/serialize'; +import { type Hasher } from '@aztec/types/interfaces'; + +import { HasherWithStats } from './hasher_with_stats.js'; +import { type MerkleTree } from './interfaces/merkle_tree.js'; + +const indexToKeyHash = (name: string, level: number, index: bigint) => `${name}:${level}:${index}`; + +/** + * An ephemeral unbalanced Merkle tree implementation. + * Follows the rollup implementation which greedily hashes pairs of nodes up the tree. + * Remaining rightmost nodes are shifted up until they can be paired. See proving-state.ts -> findMergeLevel. + */ +export class UnbalancedTree implements MerkleTree { + // This map stores index and depth -> value + private cache: { [key: string]: Buffer } = {}; + // This map stores value -> index and depth, since we have variable depth + private valueCache: { [key: string]: string } = {}; + protected size: bigint = 0n; + protected readonly maxIndex: bigint; + + protected hasher: HasherWithStats; + root: Buffer = Buffer.alloc(32); + + public constructor( + hasher: Hasher, + private name: string, + private maxDepth: number = 0, + protected deserializer: FromBuffer, + ) { + this.hasher = new HasherWithStats(hasher); + this.maxIndex = 2n ** BigInt(this.maxDepth) - 1n; + } + + /** + * Returns the root of the tree. + * @returns The root of the tree. + */ + public getRoot(): Buffer { + return this.root; + } + + /** + * Returns the number of leaves in the tree. + * @returns The number of leaves in the tree. + */ + public getNumLeaves() { + return this.size; + } + + /** + * Returns the max depth of the tree. + * @returns The max depth of the tree. + */ + public getDepth(): number { + return this.maxDepth; + } + + /** + * @remark A wonky tree is (currently) only ever ephemeral, so we don't use any db to commit to. + * The fn must exist to implement MerkleTree however. + */ + public commit(): Promise { + throw new Error("Unsupported function - cannot commit on an unbalanced tree as it's always ephemeral."); + return Promise.resolve(); + } + + /** + * Rolls back the not-yet-committed changes. + * @returns Empty promise. + */ + public rollback(): Promise { + this.clearCache(); + return Promise.resolve(); + } + + /** + * Clears the cache. + */ + private clearCache() { + this.cache = {}; + this.size = 0n; + } + + /** + * @remark A wonky tree can validly have duplicate indices: + * e.g. 001 (index 1 at level 3) and 01 (index 1 at level 2) + * So this function cannot reliably give the expected leaf value. + * We cannot add level as an input as its based on the MerkleTree class's function. + */ + public getLeafValue(_index: bigint): undefined { + throw new Error('Unsupported function - cannot get leaf value from an index in an unbalanced tree.'); + } + + /** + * Returns the index of a leaf given its value, or undefined if no leaf with that value is found. + * @param leaf - The leaf value to look for. + * @returns The index of the first leaf found with a given value (undefined if not found). + * @remark This is NOT the index as inserted, but the index which will be used to calculate path structure. + */ + public findLeafIndex(value: T): bigint | undefined { + const key = this.valueCache[serializeToBuffer(value).toString('hex')]; + const [, , index] = key.split(':'); + return BigInt(index); + } + + /** + * Returns the first index containing a leaf value after `startIndex`. + * @param value - The leaf value to look for. + * @param startIndex - The index to start searching from. + * @returns The index of the first leaf found with a given value (undefined if not found). + * @remark This is not really used for a wonky tree, but required to implement MerkleTree. + */ + public findLeafIndexAfter(value: T, startIndex: bigint): bigint | undefined { + const index = this.findLeafIndex(value); + if (!index || index < startIndex) { + return undefined; + } + return index; + } + + /** + * Returns the node at the given level and index + * @param level - The level of the element (root is at level 0). + * @param index - The index of the element. + * @returns Leaf or node value, or undefined. + */ + public getNode(level: number, index: bigint): Buffer | undefined { + if (level < 0 || level > this.maxDepth) { + throw Error('Invalid level: ' + level); + } + + if (index < 0 || index >= this.maxIndex) { + throw Error('Invalid index: ' + index); + } + + return this.cache[indexToKeyHash(this.name, level, index)]; + } + + /** + * Returns a sibling path for the element at the given index. + * @param value - The value of the element. + * @returns A sibling path for the element. + * Note: The sibling path is an array of sibling hashes, with the lowest hash (leaf hash) first, and the highest hash last. + */ + public getSiblingPath(value: bigint): Promise> { + const path: Buffer[] = []; + const [, depth, _index] = this.valueCache[serializeToBuffer(value).toString('hex')].split(':'); + let level = parseInt(depth, 10); + let index = BigInt(_index); + while (level > 0) { + const isRight = index & 0x01n; + const key = indexToKeyHash(this.name, level, isRight ? index - 1n : index + 1n); + const sibling = this.cache[key]; + path.push(sibling); + level -= 1; + index >>= 1n; + } + return Promise.resolve(new SiblingPath(parseInt(depth, 10) as N, path)); + } + + /** + * Appends the given leaves to the tree. + * @param leaves - The leaves to append. + * @returns Empty promise. + */ + public appendLeaves(leaves: T[]): Promise { + this.hasher.reset(); + if (this.size != BigInt(0)) { + throw Error(`Can't re-append to an unbalanced tree. Current has ${this.size} leaves.`); + } + if (this.size + BigInt(leaves.length) - 1n > this.maxIndex) { + throw Error(`Can't append beyond max index. Max index: ${this.maxIndex}`); + } + const root = this.batchInsert(leaves); + this.root = root; + + return Promise.resolve(); + } + + /** + * Calculates root while adding leaves and nodes to the cache. + * @param leaves - The leaves to append. + * @returns Resulting root of the tree. + */ + private batchInsert(_leaves: T[]): Buffer { + // If we have an even number of leaves, hash them all in pairs + // Otherwise, store the final leaf to be shifted up to the next odd sized level + let [layerWidth, nodeToShift] = + _leaves.length & 1 + ? [_leaves.length - 1, serializeToBuffer(_leaves[_leaves.length - 1])] + : [_leaves.length, Buffer.alloc(0)]; + // Allocate this layer's leaves and init the next layer up + let thisLayer = _leaves.slice(0, layerWidth).map(l => serializeToBuffer(l)); + let nextLayer = []; + // Store the bottom level leaves + thisLayer.forEach((leaf, i) => this.storeNode(leaf, this.maxDepth, BigInt(i))); + for (let i = 0; i < this.maxDepth; i++) { + for (let j = 0; j < layerWidth; j += 2) { + // Store the hash of each pair one layer up + nextLayer[j / 2] = this.hasher.hash(serializeToBuffer(thisLayer[j]), serializeToBuffer(thisLayer[j + 1])); + this.storeNode(nextLayer[j / 2], this.maxDepth - i - 1, BigInt(j >> 1)); + } + layerWidth /= 2; + if (layerWidth & 1) { + if (nodeToShift.length) { + // If the next layer has odd length, and we have a node that needs to be shifted up, add it here + nextLayer.push(serializeToBuffer(nodeToShift)); + this.storeNode(nodeToShift, this.maxDepth - i - 1, BigInt((layerWidth * 2) >> 1)); + layerWidth += 1; + nodeToShift = Buffer.alloc(0); + } else { + // If we don't have a node waiting to be shifted, store the next layer's final node to be shifted + layerWidth -= 1; + nodeToShift = nextLayer[layerWidth]; + } + } + // reset the layers + thisLayer = nextLayer; + nextLayer = []; + } + this.size += BigInt(_leaves.length); + // return the root + return thisLayer[0]; + } + + /** + * Stores the given node in the cache. + * @param value - The value to store. + * @param depth - The depth of the node in the full tree. + * @param index - The index of the node at the given depth. + */ + private storeNode(value: T | Buffer, depth: number, index: bigint) { + const key = indexToKeyHash(this.name, depth, index); + this.cache[key] = serializeToBuffer(value); + this.valueCache[serializeToBuffer(value).toString('hex')] = key; + } +} diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index c276fc8a16d..28448f316c1 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1965,7 +1965,7 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( ): BaseOrMergeRollupPublicInputsNoir { return { rollup_type: mapFieldToNoir(new Fr(baseOrMergeRollupPublicInputs.rollupType)), - height_in_block_tree: mapFieldToNoir(new Fr(baseOrMergeRollupPublicInputs.rollupSubtreeHeight)), + num_txs: mapFieldToNoir(new Fr(baseOrMergeRollupPublicInputs.numTxs)), constants: mapConstantRollupDataToNoir(baseOrMergeRollupPublicInputs.constants), start: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.start), end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), @@ -2012,7 +2012,7 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( ): BaseOrMergeRollupPublicInputs { return new BaseOrMergeRollupPublicInputs( mapNumberFromNoir(baseOrMergeRollupPublicInputs.rollup_type), - mapFieldFromNoir(baseOrMergeRollupPublicInputs.height_in_block_tree), + mapNumberFromNoir(baseOrMergeRollupPublicInputs.num_txs), mapConstantRollupDataFromNoir(baseOrMergeRollupPublicInputs.constants), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), @@ -2183,7 +2183,7 @@ export function mapHeaderFromNoir(header: HeaderNoir): Header { */ export function mapContentCommitmentToNoir(contentCommitment: ContentCommitment): ContentCommitmentNoir { return { - tx_tree_height: mapFieldToNoir(contentCommitment.txTreeHeight), + num_txs: mapFieldToNoir(contentCommitment.numTxs), txs_effects_hash: mapSha256HashToNoir(contentCommitment.txsEffectsHash), in_hash: mapSha256HashToNoir(contentCommitment.inHash), out_hash: mapSha256HashToNoir(contentCommitment.outHash), @@ -2196,7 +2196,7 @@ export function mapContentCommitmentToNoir(contentCommitment: ContentCommitment) */ export function mapContentCommitmentFromNoir(contentCommitment: ContentCommitmentNoir): ContentCommitment { return new ContentCommitment( - mapFieldFromNoir(contentCommitment.tx_tree_height), + mapFieldFromNoir(contentCommitment.num_txs), mapSha256HashFromNoir(contentCommitment.txs_effects_hash), mapSha256HashFromNoir(contentCommitment.in_hash), mapSha256HashFromNoir(contentCommitment.out_hash), diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index c6159039a72..1f68ce4c4ef 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -135,10 +135,8 @@ export class ProvingOrchestrator { this.initialHeader = await this.db.buildInitialHeader(); } - // Check that the length of the array of txs is a power of two - // See https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 - if (!Number.isInteger(numTxs) || numTxs < 2 || (numTxs & (numTxs - 1)) !== 0) { - throw new Error(`Length of txs for the block should be a power of two and at least two (got ${numTxs})`); + if (!Number.isInteger(numTxs) || numTxs < 2) { + throw new Error(`Length of txs for the block should be at least two (got ${numTxs})`); } // Cancel any currently proving block before starting a new one this.cancelBlock(); @@ -225,12 +223,17 @@ export class ProvingOrchestrator { logger.info(`Received transaction: ${tx.hash}`); + if (tx.isEmpty) { + logger.warn(`Ignoring empty transaction ${tx.hash} - it will not be added to this block`); + return; + } + const [inputs, treeSnapshots] = await this.prepareTransaction(tx, this.provingState); this.enqueueFirstProof(inputs, treeSnapshots, tx, this.provingState); } /** - * Marks the block as full and pads it to the full power of 2 block size, no more transactions will be accepted. + * Marks the block as full and pads it if required, no more transactions will be accepted. */ @trackSpan('ProvingOrchestrator.setBlockCompleted', function () { if (!this.provingState) { @@ -252,10 +255,15 @@ export class ProvingOrchestrator { const paddingTxCount = this.provingState.totalNumTxs - this.provingState.transactionsReceived; if (paddingTxCount === 0) { return; + } else if (this.provingState.totalNumTxs > 2) { + throw new Error(`Block not ready for completion: expecting ${paddingTxCount} more transactions.`); } logger.debug(`Padding rollup with ${paddingTxCount} empty transactions`); // Make an empty padding transaction + // Required for: + // 0 (when we want an empty block, largely for testing), or + // 1 (we need to pad with one tx as all rollup circuits require a pair of inputs) txs // Insert it into the tree the required number of times to get all of the // base rollup inputs // Then enqueue the proving of all the transactions @@ -579,13 +587,18 @@ export class ProvingOrchestrator { VerificationKeyAsFields, ], ) { - const mergeLevel = currentLevel - 1n; - const indexWithinMergeLevel = currentIndex >> 1n; + const [mergeLevel, indexWithinMergeLevel, indexWithinMerge] = provingState.findMergeLevel( + currentLevel, + currentIndex, + ); const mergeIndex = 2n ** mergeLevel - 1n + indexWithinMergeLevel; - const subscript = Number(mergeIndex); - const indexWithinMerge = Number(currentIndex & 1n); - const ready = provingState.storeMergeInputs(mergeInputs, indexWithinMerge, subscript); - return { ready, indexWithinMergeLevel, mergeLevel, mergeInputData: provingState.getMergeInputs(subscript) }; + const ready = provingState.storeMergeInputs(mergeInputs, Number(indexWithinMerge), Number(mergeIndex)); + return { + ready, + indexWithinMergeLevel, + mergeLevel, + mergeInputData: provingState.getMergeInputs(Number(mergeIndex)), + }; } // Executes the base rollup circuit and stored the output as intermediate state for the parent merge/root circuit diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts index 01e9ee52eb4..e4ae1e55a4a 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts @@ -70,6 +70,13 @@ describe('prover/orchestrator/errors', () => { ); }); + it('throws if setting an incomplete block completed', async () => { + await context.orchestrator.startNewBlock(3, context.globalVariables, [], getMockVerificationKeys()); + await expect(async () => await context.orchestrator.setBlockCompleted()).rejects.toThrow( + `Block not ready for completion: expecting ${3} more transactions.`, + ); + }); + it('throws if finalising an already finalised block', async () => { const txs = await Promise.all([ makeEmptyProcessedTestTx(context.actualDb), @@ -80,13 +87,10 @@ describe('prover/orchestrator/errors', () => { txs.length, context.globalVariables, [], - getMockVerificationKeys(), ); - for (const tx of txs) { - await context.orchestrator.addNewTx(tx); - } + await context.orchestrator.setBlockCompleted(); const result = await blockTicket.provingPromise; expect(result.status).toBe(PROVING_STATUS.SUCCESS); @@ -111,7 +115,7 @@ describe('prover/orchestrator/errors', () => { ).rejects.toThrow('Rollup not accepting further transactions'); }); - it.each([[-4], [0], [1], [3], [8.1], [7]] as const)( + it.each([[-4], [0], [1], [8.1]] as const)( 'fails to start a block with %i transactions', async (blockSize: number) => { await expect( @@ -123,7 +127,7 @@ describe('prover/orchestrator/errors', () => { getMockVerificationKeys(), ), - ).rejects.toThrow(`Length of txs for the block should be a power of two and at least two (got ${blockSize})`); + ).rejects.toThrow(`Length of txs for the block should be at least two (got ${blockSize})`); }, ); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts index d53cb3aff11..6e31aebd688 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts @@ -7,7 +7,7 @@ import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import { jest } from '@jest/globals'; import { TestCircuitProver } from '../../../bb-prover/src/test/test_circuit_prover.js'; -import { makeEmptyProcessedTestTx } from '../mocks/fixtures.js'; +import { makeBloatedProcessedTx } from '../mocks/fixtures.js'; import { TestContext } from '../mocks/test_context.js'; import { ProvingOrchestrator } from './orchestrator.js'; @@ -67,10 +67,9 @@ describe('prover/orchestrator/failures', () => { ] as const)('handles a %s error', async (message: string, fn: () => void) => { fn(); const txs = await Promise.all([ - makeEmptyProcessedTestTx(context.actualDb), - makeEmptyProcessedTestTx(context.actualDb), - makeEmptyProcessedTestTx(context.actualDb), - makeEmptyProcessedTestTx(context.actualDb), + makeBloatedProcessedTx(context.actualDb, 1), + makeBloatedProcessedTx(context.actualDb, 2), + makeBloatedProcessedTx(context.actualDb, 3), ]); const blockTicket = await orchestrator.startNewBlock( diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts index 7cd3a337b8f..5c686a472a5 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts @@ -30,9 +30,8 @@ describe('prover/orchestrator/mixed-blocks', () => { const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); - // this needs to be a 4 tx block that will need to be completed const blockTicket = await context.orchestrator.startNewBlock( - 4, + 3, context.globalVariables, l1ToL2Messages, diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks_2.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks_2.test.ts index c9f8b930df2..3000e349085 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks_2.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks_2.test.ts @@ -7,7 +7,7 @@ import { createDebugLogger } from '@aztec/foundation/log'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; -import { makeBloatedProcessedTx, makeEmptyProcessedTestTx, updateExpectedTreesFromTxs } from '../mocks/fixtures.js'; +import { makeBloatedProcessedTx, updateExpectedTreesFromTxs } from '../mocks/fixtures.js'; import { TestContext } from '../mocks/test_context.js'; const logger = createDebugLogger('aztec:orchestrator-mixed-blocks-2'); @@ -26,51 +26,37 @@ describe('prover/orchestrator/mixed-blocks', () => { }); describe('blocks', () => { - it.each([ - [0, 2], - [1, 2], - [4, 4], - [5, 8], - ] as const)( - 'builds an L2 block with %i bloated txs and %i txs total', - async (bloatedCount: number, totalCount: number) => { - const noteHashTreeBefore = await context.actualDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); - const txs = [ - ...(await Promise.all(times(bloatedCount, (i: number) => makeBloatedProcessedTx(context.actualDb, i)))), - ...(await Promise.all(times(totalCount - bloatedCount, _ => makeEmptyProcessedTestTx(context.actualDb)))), - ]; + it.each([2, 4, 5, 8] as const)('builds an L2 block with %i bloated txs', async (totalCount: number) => { + const txs = [ + ...(await Promise.all(times(totalCount, (i: number) => makeBloatedProcessedTx(context.actualDb, i)))), + ]; - const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); - const blockTicket = await context.orchestrator.startNewBlock( - txs.length, - context.globalVariables, - l1ToL2Messages, + const blockTicket = await context.orchestrator.startNewBlock( + txs.length, + context.globalVariables, + l1ToL2Messages, - getMockVerificationKeys(), - ); + getMockVerificationKeys(), + ); - for (const tx of txs) { - await context.orchestrator.addNewTx(tx); - } + for (const tx of txs) { + await context.orchestrator.addNewTx(tx); + } - const result = await blockTicket.provingPromise; - expect(result.status).toBe(PROVING_STATUS.SUCCESS); + const result = await blockTicket.provingPromise; + expect(result.status).toBe(PROVING_STATUS.SUCCESS); - const finalisedBlock = await context.orchestrator.finaliseBlock(); + const finalisedBlock = await context.orchestrator.finaliseBlock(); - expect(finalisedBlock.block.number).toEqual(context.blockNumber); + expect(finalisedBlock.block.number).toEqual(context.blockNumber); - await updateExpectedTreesFromTxs(expectsDb, txs); - const noteHashTreeAfter = await context.actualDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); + await updateExpectedTreesFromTxs(expectsDb, txs); + const noteHashTreeAfter = await context.actualDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE); - if (bloatedCount > 0) { - expect(noteHashTreeAfter.root).not.toEqual(noteHashTreeBefore.root); - } - - const expectedNoteHashTreeAfter = await expectsDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE).then(t => t.root); - expect(noteHashTreeAfter.root).toEqual(expectedNoteHashTreeAfter); - }, - ); + const expectedNoteHashTreeAfter = await expectsDb.getTreeInfo(MerkleTreeId.NOTE_HASH_TREE).then(t => t.root); + expect(noteHashTreeAfter.root).toEqual(expectedNoteHashTreeAfter); + }); }); }); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts index 808aa3dae8d..635d1dec429 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts @@ -7,7 +7,7 @@ import { sleep } from '@aztec/foundation/sleep'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; -import { makeBloatedProcessedTx, makeEmptyProcessedTestTx, updateExpectedTreesFromTxs } from '../mocks/fixtures.js'; +import { makeBloatedProcessedTx, updateExpectedTreesFromTxs } from '../mocks/fixtures.js'; import { TestContext } from '../mocks/test_context.js'; const logger = createDebugLogger('aztec:orchestrator-single-blocks'); @@ -27,21 +27,14 @@ describe('prover/orchestrator/blocks', () => { describe('blocks', () => { it('builds an empty L2 block', async () => { - const txs = await Promise.all([ - makeEmptyProcessedTestTx(context.actualDb), - makeEmptyProcessedTestTx(context.actualDb), - ]); - const blockTicket = await context.orchestrator.startNewBlock( - txs.length, + 2, context.globalVariables, [], getMockVerificationKeys(), ); - for (const tx of txs) { - await context.orchestrator.addNewTx(tx); - } + await context.orchestrator.setBlockCompleted(); const result = await blockTicket.provingPromise; expect(result.status).toBe(PROVING_STATUS.SUCCESS); diff --git a/yarn-project/prover-client/src/orchestrator/proving-state.ts b/yarn-project/prover-client/src/orchestrator/proving-state.ts index d2b92000f61..51004578237 100644 --- a/yarn-project/prover-client/src/orchestrator/proving-state.ts +++ b/yarn-project/prover-client/src/orchestrator/proving-state.ts @@ -71,6 +71,32 @@ export class ProvingState { return BigInt(Math.ceil(Math.log2(this.totalNumTxs)) - 1); } + // Calculates the index and level of the parent rollup circuit + // Based on tree implementation in unbalanced_tree.ts -> batchInsert() + public findMergeLevel(currentLevel: bigint, currentIndex: bigint) { + const moveUpMergeLevel = (levelSize: number, index: bigint, nodeToShift: boolean) => { + levelSize /= 2; + if (levelSize & 1) { + [levelSize, nodeToShift] = nodeToShift ? [levelSize + 1, false] : [levelSize - 1, true]; + } + index >>= 1n; + return { thisLevelSize: levelSize, thisIndex: index, shiftUp: nodeToShift }; + }; + let [thisLevelSize, shiftUp] = this.totalNumTxs & 1 ? [this.totalNumTxs - 1, true] : [this.totalNumTxs, false]; + const maxLevel = this.numMergeLevels + 1n; + let placeholder = currentIndex; + for (let i = 0; i < maxLevel - currentLevel; i++) { + ({ thisLevelSize, thisIndex: placeholder, shiftUp } = moveUpMergeLevel(thisLevelSize, placeholder, shiftUp)); + } + let thisIndex = currentIndex; + let mergeLevel = currentLevel; + while (thisIndex >= thisLevelSize && mergeLevel != 0n) { + mergeLevel -= 1n; + ({ thisLevelSize, thisIndex, shiftUp } = moveUpMergeLevel(thisLevelSize, thisIndex, shiftUp)); + } + return [mergeLevel - 1n, thisIndex >> 1n, thisIndex & 1n]; + } + // Adds a transaction to the proving state, returns it's index // Will update the proving life cycle if this is the last transaction public addNewTx(tx: TxProvingState) { diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 0a441453780..fb20cb3507f 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -258,9 +258,7 @@ export class Sequencer { const processor = await this.publicProcessorFactory.create(historicalHeader, newGlobalVariables); const numRealTxs = validTxs.length; - const pow2 = Math.log2(numRealTxs); - const totalTxs = 2 ** Math.ceil(pow2); - const blockSize = Math.max(2, totalTxs); + const blockSize = Math.max(2, numRealTxs); const blockBuildingTimer = new Timer(); const blockTicket = await this.prover.startNewBlock(blockSize, newGlobalVariables, l1ToL2Messages);