From 8553fa0dceaadf8b1053ad5fcb6b18a7c46a7799 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 25 Jul 2023 17:39:32 +0000 Subject: [PATCH 01/58] feat: add blocks tree data to l2 block --- l1-contracts/src/core/libraries/Constants.sol | 10 +- l1-contracts/src/core/libraries/Decoder.sol | 102 ++++----- l1-contracts/test/Decoder.t.sol | 23 +- l1-contracts/test/DecoderHelper.sol | 6 +- l1-contracts/test/Rollup.t.sol | 200 +++++++++--------- .../src/integration_l1_publisher.test.ts | 8 +- .../block_builder/solo_block_builder.test.ts | 2 + .../src/block_builder/solo_block_builder.ts | 6 +- yarn-project/types/src/l2_block.ts | 34 ++- .../server_world_state_synchroniser.test.ts | 2 + 10 files changed, 218 insertions(+), 175 deletions(-) diff --git a/l1-contracts/src/core/libraries/Constants.sol b/l1-contracts/src/core/libraries/Constants.sol index 2784a5d9e88..c86fb7d0ec0 100644 --- a/l1-contracts/src/core/libraries/Constants.sol +++ b/l1-contracts/src/core/libraries/Constants.sol @@ -14,10 +14,10 @@ library Constants { // Constants used for decoding rollup blocks // TODO(962): Make this constant consistent across the codebase. - uint256 internal constant COMMITMENTS_PER_KERNEL = 16; - uint256 internal constant NULLIFIERS_PER_KERNEL = 16; - uint256 internal constant PUBLIC_DATA_WRITES_PER_KERNEL = 4; - uint256 internal constant CONTRACTS_PER_KERNEL = 1; - uint256 internal constant L2_TO_L1_MSGS_PER_KERNEL = 2; + uint256 internal constant COMMITMENTS_PER_TX = 16; + uint256 internal constant NULLIFIERS_PER_TX = 16; + uint256 internal constant PUBLIC_DATA_WRITES_PER_TX = 4; + uint256 internal constant CONTRACTS_PER_TX = 1; + uint256 internal constant L2_TO_L1_MSGS_PER_TX = 2; uint256 internal constant L1_TO_L2_MSGS_PER_ROLLUP = 16; } diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 2c4bc324ca3..20ecf12a5c6 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -19,7 +19,7 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * ------------------- * * | byte start | num bytes | name - * | --- | --- | --- + * | --- | --- | --- * | 0x0000 | 0x20 | chain-id * | 0x0020 | 0x20 | version * | 0x0040 | 0x20 | L2 block number @@ -39,34 +39,37 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * | 0x0174 | 0x04 | startL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex * | 0x0178 | 0x20 | startTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.root * | 0x0198 | 0x04 | startTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x019c | 0x20 | endPrivateDataTreeSnapshot.root - * | 0x01bc | 0x04 | endPrivateDataTreeSnapshot.nextAvailableLeafIndex - * | 0x01c0 | 0x20 | endNullifierTreeSnapshot.root - * | 0x01e0 | 0x04 | endNullifierTreeSnapshot.nextAvailableLeafIndex - * | 0x01e4 | 0x20 | endContractTreeSnapshot.root - * | 0x0204 | 0x04 | endContractTreeSnapshot.nextAvailableLeafIndex - * | 0x0208 | 0x20 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.root - * | 0x0228 | 0x04 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x022c | 0x20 | endTreeOfHistoricContractTreeRootsSnapshot.root - * | 0x024c | 0x04 | endTreeOfHistoricContractTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x0250 | 0x20 | endPublicDataTreeRoot - * | 0x0270 | 0x20 | endL1ToL2MessagesTreeSnapshot.root - * | 0x0290 | 0x04 | endL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex - * | 0x0294 | 0x20 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.root - * | 0x02b4 | 0x04 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x02b8 | 0x04 | len(newCommitments) denoted a - * | 0x02bc | a * 0x20 | newCommitments (each element 32 bytes) - * | 0x02bc + a * 0x20 | 0x04 | len(newNullifiers) denoted b - * | 0x02c0 + a * 0x20 | b * 0x20 | newNullifiers (each element 32 bytes) - * | 0x02c0 + (a + b) * 0x20 | 0x04 | len(newPublicDataWrites) denoted c - * | 0x02c4 + (a + b) * 0x20 | c * 0x40 | newPublicDataWrites (each element 64 bytes) - * | 0x02c4 + (a + b) * 0x20 + c * 0x40 | 0x04 | len(newL2ToL1msgs) denoted d - * | 0x02c8 + (a + b) * 0x20 + c * 0x40 | d * 0x20 | newL2ToL1msgs (each element 32 bytes) - * | 0x02c8 + (a + b + d) * 0x20 + c * 0x40 | 0x04 | len(newContracts) denoted e - * | 0x02cc + (a + b + d) * 0x20 + c * 0x40 | e * 0x20 | newContracts (each element 32 bytes) - * | 0x02cc + (a + b + d) * 0x20 + c * 0x40 + e * 0x20 | e * 0x34 | newContractData (each element 52 bytes) - * | 0x02cc + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | 0x04 | len(l1ToL2Messages) denoted f - * | K := 0x02cc + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | f * 0x20 | l1ToL2Messages (each element 32 bytes) + * | 0x019c | 0x20 | startBlocksTreeSnapshot.root + * | 0x01bc | 0x04 | startBlocksTreeSnapshot.nextAvailableLeafIndex + * | 0x01c0 | 0x20 | endPrivateDataTreeSnapshot.root + * | 0x01e0 | 0x04 | endPrivateDataTreeSnapshot.nextAvailableLeafIndex + * | 0x01e4 | 0x20 | endNullifierTreeSnapshot.root + * | 0x0204 | 0x04 | endNullifierTreeSnapshot.nextAvailableLeafIndex + * | 0x0208 | 0x20 | endContractTreeSnapshot.root + * | 0x0228 | 0x04 | endContractTreeSnapshot.nextAvailableLeafIndex + * | 0x022c | 0x20 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.root + * | 0x024c | 0x04 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.nextAvailableLeafIndex + * | 0x0250 | 0x20 | endTreeOfHistoricContractTreeRootsSnapshot.root + * | 0x0270 | 0x04 | endTreeOfHistoricContractTreeRootsSnapshot.nextAvailableLeafIndex + * | 0x0274 | 0x20 | endPublicDataTreeRoot + * | 0x0294 | 0x20 | endL1ToL2MessagesTreeSnapshot.root + * | 0x02b4 | 0x04 | endL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex + * | 0x0300 | 0x20 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.root + * | 0x02d8 | 0x04 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.nextAvailableLeafIndex + * | 0x02dc | 0x20 | endBlocksTreeSnapshot.root + * | 0x02fc | 0x04 | endBlocksTreeSnapshot.nextAvailableLeafIndex + * | 0x0300 | a * 0x20 | newCommitments (each element 32 bytes) + * | 0x0300 + a * 0x20 | 0x04 | len(newNullifiers) denoted b + * | 0x0304 + a * 0x20 | b * 0x20 | newNullifiers (each element 32 bytes) + * | 0x0304 + (a + b) * 0x20 | 0x04 | len(newPublicDataWrites) denoted c + * | 0x0308 + (a + b) * 0x20 | c * 0x40 | newPublicDataWrites (each element 64 bytes) + * | 0x0308 + (a + b) * 0x20 + c * 0x40 | 0x04 | len(newL2ToL1msgs) denoted d + * | 0x030c + (a + b) * 0x20 + c * 0x40 | d * 0x20 | newL2ToL1msgs (each element 32 bytes) + * | 0x030c + (a + b + d) * 0x20 + c * 0x40 | 0x04 | len(newContracts) denoted e + * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 | e * 0x20 | newContracts (each element 32 bytes) + * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x20 | e * 0x34 | newContractData (each element 52 bytes) + * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | 0x04 | len(l1ToL2Messages) denoted f + * | K := 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | f * 0x20 | l1ToL2Messages (each element 32 bytes) * | K + f * 0x20 | 0x04 | byteLen(newEncryptedLogs) denoted g * | K + f * 0x20 + 0x04 | g | newEncryptedLogs * | K + f * 0x20 + 0x04 + g | 0x04 | byteLen(newUnencryptedLogs) denoted h @@ -134,7 +137,7 @@ library Decoder { // Note, for startStateHash to match the storage, the l2 block number must be new - 1. // Only jumping 1 block at a time. startStateHash = computeStateHash(l2BlockNumber - 1, 0x80, _l2Block); - endStateHash = computeStateHash(l2BlockNumber, 0x19c, _l2Block); + endStateHash = computeStateHash(l2BlockNumber, 0x1c0, _l2Block); bytes32 diffRoot; bytes32 l1ToL2MsgsHash; @@ -155,11 +158,11 @@ library Decoder { bytes32 _diffRoot, bytes32 _l1ToL2MsgsHash ) internal pure returns (bytes32) { - bytes memory temp = new bytes(0x02b8 + 0x20 + 0x20); + bytes memory temp = new bytes(0x0300 + 0x20 + 0x20); assembly { - calldatacopy(add(temp, 0x20), _l2Block.offset, 0x02b8) - mstore(add(temp, add(0x20, 0x02b8)), _diffRoot) - mstore(add(temp, add(0x40, 0x02b8)), _l1ToL2MsgsHash) + calldatacopy(add(temp, 0x20), _l2Block.offset, 0x0300) + mstore(add(temp, add(0x20, 0x0300)), _diffRoot) + mstore(add(temp, add(0x40, 0x0300)), _l1ToL2MsgsHash) } return Hash.sha256ToField(temp); } @@ -190,14 +193,14 @@ library Decoder { pure returns (bytes32) { - // 0x20 for the block number + 0x11c for the header elements - bytes memory temp = new bytes(0x20 + 0x11c); + // 0x20 for the block number + 0x140 for the header elements + bytes memory temp = new bytes(0x20 + 0x140); assembly { // Copy block number mstore(add(temp, 0x20), _l2BlockNumber) // Copy header elements (not including block number) for start or end - calldatacopy(add(temp, 0x40), add(_l2Block.offset, _offset), 0x11c) + calldatacopy(add(temp, 0x40), add(_l2Block.offset, _offset), 0x140) } return sha256(temp); @@ -222,7 +225,7 @@ library Decoder { ArrayOffsets memory offsets; { assembly { - let offset := add(_l2Block.offset, 0x02b8) + let offset := add(_l2Block.offset, 0x0300) let commitmentCount := and(shr(224, calldataload(offset)), 0xffffffff) offset := add(add(offset, 0x4), mul(commitmentCount, 0x20)) let nullifierCount := and(shr(224, calldataload(offset)), 0xffffffff) @@ -253,7 +256,7 @@ library Decoder { ConsumablesVars memory vars; vars.baseLeaves = new bytes32[]( - lengths.commitmentCount / (Constants.COMMITMENTS_PER_KERNEL * 2) + lengths.commitmentCount / (Constants.COMMITMENTS_PER_TX * 2) ); vars.l2ToL1Msgs = new bytes32[]( lengths.l2ToL1MsgsCount @@ -261,7 +264,7 @@ library Decoder { // Data starts after header. Look at L2 Block Data specification at the top of this file. { - offsets.commitmentOffset = 0x02bc; + offsets.commitmentOffset = 0x0304; offsets.nullifierOffset = offsets.commitmentOffset + 0x4 + lengths.commitmentCount * 0x20; offsets.publicDataOffset = offsets.nullifierOffset + 0x4 + lengths.nullifierCount * 0x20; offsets.l2ToL1MsgsOffset = offsets.publicDataOffset + 0x4 + lengths.dataWritesCount * 0x40; @@ -272,20 +275,21 @@ library Decoder { offsets.unencryptedLogsOffset = offsets.encryptedLogsOffset + 0x4 + lengths.encryptedLogsLength; + // load the l2 to l1 msgs (done here as offset will be altered in loop) assembly { let l2ToL1Msgs := mload(add(vars, 0x20)) calldatacopy( add(l2ToL1Msgs, 0x20), - add(_l2Block.offset, mload(add(offsets, 0x60))), + add(_l2Block.offset, mload(add(offsets,0x60))), mul(mload(add(lengths, 0x60)), 0x20) ) } - // Create the leaf to contain commitments (2 * COMMITMENTS_PER_KERNEL * 0x20) + nullifiers (2 * NULLIFIERS_PER_KERNEL * 0x20) + // Create the leaf to contain commitments (2 * COMMITMENTS_PER_TX * 020) + nullifiers (2 * NULLIFIERS_PER_TX * 0x20) // + new public data writes (8 * 0x40) + contract deployments (2 * 0x60) + logs hashes (2 * 4 * 0x20) vars.baseLeaf = - new bytes(2 * Constants.COMMITMENTS_PER_KERNEL * 0x20 + 2 * Constants.NULLIFIERS_PER_KERNEL * 0x20 + 2 * Constants.PUBLIC_DATA_WRITES_PER_KERNEL * 0x40 + 2 * Constants.CONTRACTS_PER_KERNEL * 0x60 + 2 * 4 * 0x20); + new bytes(2 * Constants.COMMITMENTS_PER_TX * 0x20 + 2 * Constants.NULLIFIERS_PER_TX * 0x20 + 2 * Constants.PUBLIC_DATA_WRITES_PER_TX * 0x40 + 2 * Constants.CONTRACTS_PER_TX * 0x60 + 2 * 4 * 0x20); for (uint256 i = 0; i < vars.baseLeaves.length; i++) { /* @@ -328,8 +332,8 @@ library Decoder { (vars.unencryptedLogsHashKernel2, offsets.unencryptedLogsOffset) = computeKernelLogsHash(offsets.unencryptedLogsOffset, _l2Block); - uint256 commitmentsPerBase = 2 * Constants.COMMITMENTS_PER_KERNEL; - uint256 nullifiersPerBase = 2 * Constants.NULLIFIERS_PER_KERNEL; + uint256 commitmentsPerBase = 2 * Constants.COMMITMENTS_PER_TX; + uint256 nullifiersPerBase = 2 * Constants.NULLIFIERS_PER_TX; assembly { let baseLeaf := mload(add(vars, 0x40)) // Load the pointer to `vars.baseLeaf` @@ -394,10 +398,10 @@ library Decoder { mstore(dstPtr, mload(add(vars, 0xc0))) // `unencryptedLogsHashKernel2` starts at 0xc0 in `vars` } - offsets.commitmentOffset += 2 * Constants.COMMITMENTS_PER_KERNEL * 0x20; - offsets.nullifierOffset += 2 * Constants.NULLIFIERS_PER_KERNEL * 0x20; - offsets.publicDataOffset += 2 * Constants.PUBLIC_DATA_WRITES_PER_KERNEL * 0x40; - offsets.l2ToL1MsgsOffset += 2 * Constants.L2_TO_L1_MSGS_PER_KERNEL * 0x20; + offsets.commitmentOffset += 2 * Constants.COMMITMENTS_PER_TX * 0x20; + offsets.nullifierOffset += 2 * Constants.NULLIFIERS_PER_TX * 0x20; + offsets.publicDataOffset += 2 * Constants.PUBLIC_DATA_WRITES_PER_TX * 0x40; + offsets.l2ToL1MsgsOffset += 2 * Constants.L2_TO_L1_MSGS_PER_TX * 0x20; offsets.contractOffset += 2 * 0x20; offsets.contractDataOffset += 2 * 0x34; diff --git a/l1-contracts/test/Decoder.t.sol b/l1-contracts/test/Decoder.t.sol index 4761e0dcf31..a2951920314 100644 --- a/l1-contracts/test/Decoder.t.sol +++ b/l1-contracts/test/Decoder.t.sol @@ -24,11 +24,12 @@ contract DecoderTest is Test { Outbox internal outbox; Rollup internal rollup; - bytes internal block_empty_1 = - hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d000000200668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000002e04e54c3675ba6bd68f104ce19d391c57488f31736639dee94d707989843f110000000119c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e150000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb6710000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d000000600668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000040b217b2a07953bc0e8f56aac96308f81a2682074c229dc0034f091674d23993d00000002238b20b7bc1d5190f8e928eb2aa2094412588f9cad6c7862f69c09a9b246d6ed000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e1500000010238b20b7bc1d5190f8e928eb2aa2094412588f9cad6c7862f69c09a9b246d6ed00000002000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000"; + bytes internal block_empty_1 = hex'0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda5410000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000006027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000040050f7a38e7222792175befc9d6af3433c94309b86f3d2cccb3d9dafb178071a000000022bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f119000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000102bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f11900000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000'; + + bytes internal block_mixed_1 = hex'0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000235f4e41a2440aa28f9ac14e7eed447ddd2e539179cee4c0941e6e408d2443e50000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000600b6abbab461cfb072b267bfc1ecf8dc3c943736341baf11c5c829e345c49b509000000041c1b17b2cb59cc2314fb65fe31dcfdb1b014630fab522a263d9935601ff78a5c000000022d02c42204d7182da24e9ca1e3244fbff1e00efb8c85ee3a1ac9488fe2e3aa9d000000022d9b8d2353587ca56bdf967b4bb8847af3671bd6901e9e28f82c240c6e33129a2fbbd267a1c9b23b3ac1609b2c2a7961a0338c56d62607d5f8d6b6a29e7fe4cb000000101d223d0a7bbe8cd9eace6507ee0fa9dbf84565685a1c6ceb978cdd46c47025ea00000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d00000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc000000906eb2b444212e7fc5426b585fe92da7a94010f06dc82f8ae57dd4dc91cac317e141462fbe15290e7da75db817402d54bb34c3e36b82b681103e75a06b53742b0b225f76d3e207d15147eb3fa760d364422d4bb6a9ec10df5ac9b8fbedada4b6f97045637edc6c78f389dfd44a466e10e2cbfd84b112515666452a25e6877921275cc60bda20061ed54e6775087bd44cae00000090b3f361eebad14c9843114c3e6e2bd810b17a1381953eb6cbb0920e5412435c42cb36efa2ddf219d289c394700893caed500cb13b1d5724d57cb97922ec555d7fc40c94889a666bced531fbda4f9aff016a6b4267972abbd9f60287f6c1676f6b2b20577f3781e34a8cc4dd36cc6e2725d1b8f6f9aa612fc43358c1fc167a56d9bcb3a463fb9abf152723c36020393f5d00000090e084263ed67cf75ffbcf9f9922716125423be3ae02c0c3729c564a7d4209afe4534a20db0dc79f85a69ec8676eaa7b094857b5af72dbd40346c7bf2f79cb39bbbf37e977fb595639e0585abc2bc6ad67b097c23a286a2c4c62380ee2d496222ddced1e4d329d5fb47a9545927466e8c663e2a559d4fd78af3845efa3c09ebb3d6d01582609371337d6d83ecb704ce2e2000001bc00000090979ac1a9ccb8fa6b9f8d1747232ea8e8864f3cf83ac87f780d923d33e97a85f6265276e47faac640a966272722bbd297083a0c65244eb2af13e1606259957c60a88e03366a96fc328b0702cd760a399e1c3a1aaea86e4dea5ee70213ff3cec470cd54c52097126ba8556b129d085d5e393c78dfb03b4c3626a77cd5b0d2f42acdd3b5e975a06cc2582ce355071364a0f00000090359b86b1136c91f98136d693ca665141f5f7adf0ddc0b3d24ebe39ed6e4e41b9d239e64256b0609710419eff5f183af46cdb7407aec40ff9d3d291befc3e23e65fd6254b68848954eee73e0ff6964789f04ec290cc99421d4e0e56821a8a312a67970a7ebe83173b49ed73d8840b89a9d9cb0dc98fe9f4feaae4fa92b060a935d8c1406da1a627653baba6a8267cc62c00000090c194828fe951f3090d5c36d57dbe3998258d521b01ab426864e64d06e29e126a3ad8bf44eb471f87b57ab7a4ae675696029cd9ebb22d0531b43d8768a2c6426a1dce65ef024e065ea151a865b0c85a176d8c1e6f882fbe4d67d91820b6d412466f0dad365b4a824700c697093f14e8dd6c6262d7d377d014f64c941ebc6cbf9f6edc9d695fde67204b98c24c4975a621000001bc000000904bdaadd47d29131302d4a29451be409a04d7dfef42764e84acea034f5997dcbe37cb01583b3e82cb83e5c6f66818dc340b00d9e3a89c9b43045a69ed33478bf28bb11cce3ef0f7af62f96b40e80bbba69f3672751c10958bc365f2285c16012675d00111f440bdca78403ccc5411412c66e4e4da0e786295bc665b891221254152b8af23424761cdb74b45b4a9da854b000000905ae0304af7a3c27c9ea281ccc1f646de7110b4c4ed43e3739324c42dcc84d93fc6c6b4325bb3c081cd7159315060af0c6b2d1e60956ca9210ef483f7ec880282606f8a6ec48556f3badd07a2a0859bade234daba4801ca7c2b55766a4e62b3492c16e2b4077dcbeb2a3cd33fab95774791d743dba7dd5572d76d58cc65a95161d1c46fe75c05ba2cd1e8a994d9b2caba000000904314d956bc3d4990810346da528a4f7af2994e5a41e969346e41617b8a6cddb91268f8f471847037fc84388c60eb4cac3d15e774a3e243f151cdce2ce60bf348b1fabddb3adeff2f669172cd67eebd8ae153423391241572e335b54922c21f9db35c717babaec2c746ad769603696eaf7f4a7037893de3c4a2d7afbe6f8374ae39f1eb65835c02e41b176cde83fbc469000001bc000000900d2c37ba80eb50fa643e8bb1b2be6abfcb87e67b9a3199aa54911d35fea3f6e918b7d19c876d978c6af8d9416d334a02a380d5067d016d1c38e72efdd1dd82f89fc0ccf03ed4b02ecf0430f19c8f7d036a4ca56654acb8a6cca6aed4ef70e69226a73ff44595e59920650a1b1c4507efeb2540949a053bd59bd3225b7683d04eb845e22b4c2854f4ce3ad69404b8517a0000009046adc2c903a76594df533c486b5f0213e1bfb5ce70b22034e328d2b40b0c3126919fde6536d823bdd4b6429e3418199c5cdaab29240d4bf6466118f526c193d3cd8d7e9ec4e829271c230d3b558c8503b1e22d71a9e72473e18feb31ca5de0d9d57e77fb27c8f28c11b5e07dd8c2254540e3ea20650ef88d221732a4a9164bfdcebfc77a9f2badbba68231f5ef4ea3040000009062878ac127eb51ad6bb82e75f3d0d003c664b2010bcaf68e8b2cc6001a8911b57ac81fa23591d33248c0babdc70b53f53955ba124a852dc866ca6f32db37a4fcb0c39309e80f73c59ab0d76d41671aaed89b54ed6a85d306cef2c65afc2042893d6f858f8c5555a4e64180c3629acaeb813598f7b08328cefb69b413d5583ac0c4c5571e856bf556ba0c01d4af59f5e7000001bc00000090ff2435a0b914f0faebbd91d4473d7c139e093fb7fb5a7fbfd3976a36731bcf8bc1ceee34a855f3646e37f07c05bbfdc304c8b4e4105fe1ba8f620cac6ad84344ae67c9a98270792c376248abc54a3887fed1aa32da71444ef85cb0c5bf6754d067e543b18cfddb2a2bf05782018afc649a8d40cccc2cef80819321359ea87ed2840e321bafe6f6df4ce11895b969230600000090f01ef0a085fcda6760980143ece14b530125bfcd9c38b6ca47961cec36698d684a520168b9092ecb88d0384f90cb0262add2ee8a6c9752a1dab7f73738d95b87c2f4acbc816672097635bfe14f61937cb5baa0574172a2d84271e6c4dab145c3fda63e7099ea0e3949af3642e6d00d41c19d3d48d86455e6f6f168d9009d8780e81d3f9a125f360079aa0ea5774e44cd00000090303d2297696cd74d806fa47bcb234b1224a624737e75db864007d03a4d006c857384de3b141e2f0846f2c4cb2ff4db2cce6d75e727e02ac0d8bcf7185a00d7f177bd856967359edf67dbd6c41097dd03bd51d1b5523c54c2794e4d1323f4ecec113f36c7384b14e3cf95bfa98ff5357be32226a1825968b50fe076821f5afcb320c8ee22da0a669326cdee408481c431000001bc000000906cce662bc89f0e2bfc073f7fb02b5e4554c04245864b2f8602b3b5b8ce869b0b80809dd2abd376f7689aebf4eb9a9ddf4c1b45204f38eca18d00c03a6c1a7ee006b51552f21ef587bf99f532f0b9289f8e9378a8e70c04affcd6653339149435f6392edddd8631fe099e48a14a3f714a636a820243919b24c28af14eb67b949b3efc7bb1fc8592549f7cf417596ff50a00000090cf301578a705479b2c666d95ba9c33e6b446216ce84ebcb5c692cd64b70b5ff911a6a110725e656b5da4f5559c3fdbf660544f979fc6afde525bed51dcecef52e0d7c786c10dae116109ac08d0d42cb2417fe2e221cd8e195f82c859713f535ac972c169759aa3017a916cade68fd0fbf12ab770072571828122daea5e755e47eb2bb9c17858753d6fb7b50465554a58000000905b43550bbfc6b90c6c71e4e852d5c5965fad0bad906e057d7fce52b4931f46162925b802d2c59930528850130a421e5dce1b5a5b31f9dd5856dd11fb1265b64e6df9d3576b9b1b5492752a39f0941556df29a41d1ebd53b6e3a4076034b2b22a4572fbb47811d8cec4d811fb2f44ecba5c9e31ce6f24de219646a85d9535317828aa378309793ecf6d3955aeb9fef712000001bc0000009002d5ac96e04b1354d51222d6d525e6ba31104b2d19e076f1389f8a6cff3ecb73dd21c8161e41b470bb995cad44e7a4f4c61d0ae08c6acb6e4ec4a38c1e4957fe7b0f385a655164401c7a4f6e50de8c0588e83d37df12b64a79acba23f7ee0a6a0a7818fea578680d50ee7e289d911617a42f9728cce2bbc7f4a2cdf22f3e64dc697871edd0c33ce1c9b179b793a89c810000009006dae99b741eb1404deb4f716aa6b153d9e05ee4f1ca76b2495d9559b1d408939bac110c8dbac10957a5f709367885a802c9df7ae0b4dbf29b74e53b1d182639d2ed888a4e8c250ed8a6f4acefeab665e2a8481da550dee1ced20fae158e99d993a034fa78054330793a31574fc1d469b6689ae9d8d54162d82a6982f4ebd239f152ed0c53f962cdc7611a298c1d1592000000904ae4fb51433228123b9b6110d0cf7536ff9c13daba8e88ea129e44d451bafa159ae0c73e148f91b0b7f04e43230dc4860532d8b1bb623d0ef7e5636ea43fc8edf5a31135f50a0eb7b57a0a431c3531a80d354f9f199a9e36ce690946e8ac360a652b68c56c7df4ad623f10d99650ab6bdc95b401657481352a4aa5f48610d76c236f78b2b64e9799a338a7b18993a625000001bc000000903c5e8cf037296bef39b34178fc6704de6be6b9c4c977f13b9040a369b85b7579564bfbc3ef32baf2d59d016be685f44851f43ec4fc7a39417e4bc16278193c97776bc2bc06178d5dad9747e5a6eb8283ff8b3ac8b11299f8022ea8afedfb356c814c3cd9fb989d851d9e6722382e1b184d7fcae98f122dc70dcb57ef5536850a266c6c3061c0bc501a081531abd0335c00000090be24b50850949a6fb272128474fb4c9e44c4e9f21235c43134f06e36a8d5432724daf0258ffb72863d934b189725a9fb2ee95dfacc5d5568d0f70b7de4140befb4496fdf54e02d215e98b06b0fc32ad6ec2f9397b324c153d5d3dc88a988308460fcb61192b89021848e19f0efb11f6de7d9a344d696d292c960c567f4e2f3f3a45d30c7fc1b28b762476e613a45bb0500000090a58b1f5a78bae600267b40964f867160741759b2db895253e6629306741e9629a1d6eca76350864f297ca566a3ba2c707e3f7ac5633178a517de20edf98a9ae237474de5012f88ab0ed68ce79ba0cc9af44313bca966d78c44f76798775ab86123a53224c43805e4d668574646374c3b5d944a8583bbe508cf6516e68f5a21f1bf5f591fd1e965422ac31a07960249ce00000e00000001bc00000090f9e56638daabd6fc1023090b32bedcf471261843722a57589df71ae6a6fb9068fc9f7fd1a2746d7a3696b7e4552c6a6fbf8a709ad295ea66afd3201783748f5fec2ab3f2516703404e1149360415d8166646796b117adb6aa3294c81795dddad2ffc84d88828d21a751619c15d804dfa695b23298f03b1ed6f0b1b5aa5076c284fcf2d268a181c195d62c83cd6bbe15800000090ef28121a593a23b9575a043dbf21b4f7004de19f7f9d8b43b8685911aca0728843c35ea6ec86bf567e12414e458ba0c4eb73ad926d1c9834b0fe095cf0375a736a131bcdb899c59c46c9b6323f8468b118818e941ceca4af4b1235f6eb2fa0d1e9b6f9f5225a424fc95448d3249d3e672fc868b5b9cc2550f0b63ce2932a31e1c15fc4c8bcec304cd7dc5c91b21197b200000090e7812aca513f0efbaeb1f26d0dd854f2d959e8462a3df8510ef9151e027e4f6e0022c0fa5a5ae9b2fe2b07cf9737d5d3e3c14302ee2e0b7f94fb7c5a22b4f0768bfe97c8f292df7746f468569b93071072ee308dfc981df098886e07495f5545e69f5566b6b2049cbce7030decdb2b5cb7b41f0b6dff5cccbb90321752986fd36856a38e466e521fd4b2e0219dc11200000001bc00000090af74c11a88f7c49a1f09874652ba9ff762cf886bdd68768c15dad92b6f9e121e4337f607c653ac7527a675c4ae43fa036b11b3f401c49b0bd4b6c30e21d20ea4145e357279338288fa4f91ea704e8a5cdb739226b24b268f842c062554cdd33272f62fb85bc76c9545a9989dbaf9b7962c56812b8a972fc4142e97d02745b716576ad36e242813eb32b0d78a64a1fba2000000903d20a276fd09c048d101c8d78e69ec6ca4055f68e0b3ff07fda4cf6bfdf4b0be29d235a77951e58ab7c184554ae31f3e50331dba55308646321cf17c473cf2e8fd37f08cc65451a3e498d22256855afa8f1be99c5d7023363fa700f3acdd5a354035fd19633197559766a56f49222704f16ae8755e01aa305077f1ff2e1fb381db6ee2d45d60a2daf03489428defd79800000090561ca53af312ded7a6d1a45f6d93aa1b1079f2de66713b4a6a2c303ce78fd26fe6e9bc0f61b3a86a82e95ff52ea020a581dd45e2dba70bf76b474e752c260fba9b676e9dcd0a84f9aaa993882d584a0aba6282985a46eafba41305ac5767b163ed2a590d84629bc3d402b21f4c2ed4621dbdc432ffab8b2b4591d7ef05bdf11c0a34f9354189dbbd779617c765073876000001bc000000904ce42b5eec11797c1f8afc79114c6ea9cedd82426075ddfd8a6dbbca559c60094fe58300bf1a7107370f8c6bed505cd3bcea1aba6dc2be4367c69f1f79f45514118830b1424fb0e8ce93de8bdcbb95280169924700023e4f98aaf6419da9b08cd1a792c726434a03ef7b3059c4757d6e3e7328b4876b13bd0fcf7dbc7134ec3d92ddfa8846d014f09b04cf7037b901f90000009050b61813c794d0bf68daa228a05a5f6a95456520afed8a5a0c07ebb4ca7242a7594462868b811c95d65bb08a3c369162f6bc6fb1fc8b9267586dc03f411953e700ab00cf55764d79f429d21fac45539dff80233566854493d4159e35cd15d02840fec6cf5eea625b82c390df073898f3854f3c9f19d14a3f155118b91d629098ca8388ad5f260fac5dea06a5449b917a000000904bc2c01e9e4e3a2f2f148a881b87e635785c7b440d634a8ae7f894c732aedeb8f87367117b6b5ebb585282e3dcd53c42362c962af14bd4e370133ce2387ecc5102149a62089aeb02c8ffab68df211bbde384d0d9d5325c8e85de847b5d810eee257d18ddd970cf4ec90396d34725f691d2b21e0b6ca8debb8c2f894980ce2db28fe97c8c00d4182346cd335219d8c014000001bc0000009080d739bf38be185bab1564dc36940e345491b0ba1a0d519301f946ff88cd36c8ab9bae17bae9828c5aa4608851b9ea14cc6de10f8338bfdeef0890a31282fc30d1459e0f43c63ee33e150d9069b090b573857a013db7442b4147639d91768ce87a93e560dafe84e975f24b8967a91009cb5555fb2e3ca35e25ba3246cf307d00d050d906a8f1427da6eb0e49236e66320000009052160a2b2b01d3adb6ace0f043523e0baa2fee091941ff5b95ddf66db5170b22b8ba578f09fd8c8cf127920c5da841bd7c5d439fe6ab222ba2f7cbb69b0e34ca217afd282d4a1d85c76d8a108970528731c1e4f32703e0ee92410eedbd52d0fb7d2d7797c038e887d69c2e4016c56a4cf9a98df0fecdffe16be815b94b1a5cb382fd02c2ad91a49a5d1ec5882cc574ed00000090102ef5abafe1a801f359491349a458cc2b0bc567c7752fcae65a0408230fbc88334098c5c8ae4cde42d383eba6832d71abe6f4c450f5c14b6f56dd9e0c02d818d912a893ac1694dcab0cf9ec29fdb378b95fa3179a82757312ddf0d7852bb9f1a380f20e8851a2b7313900fbea3e07a3ae18e457ddf5639a0b1f3e7dbce05d8e42db93082774587393b3daf59ffbba7b000001bc000000905f9d5406ea0521e54cc2918df8c5b6b97473424f4d0107a32d0aa31ea5453a8bed2f4f455892d61bed404080577e7744bbcdd880f418d4a091b9f8482514ad04674abb41585d5558d36c03be687ea2be36a493ede581eac13fc309f0b3c74a2edc152217cc24c45fcb48bca15ef00900fd62429786c725a99d1b9edb9b03bc7cdb177909c0a8c3e6822f2e32269cc96900000090c927d7dc259777e39ac2a14352dd6a3743403cdd15c154c3d44d15014018603356e926eb1efe597d34708527cd952eba7a9fc1b3c527427d4732ab4830cbfdb10f315e4e11ec1eae6440dc7f5aa4f53b95a2921f19be7a5f9acabeee51d7d73af893305bb86855559e8bf31bdf56cfe732a504e5b4a2005a75c607031da39ec02a783d92222beb4aa8c4ca142d33bb5600000090c1a905e2bb0dd6c444a2f3f909be4e7d338651ed45be1ee8d55caef42b1df59cc1b2324db5fc9c999b94e14b1f0447ce0a42443028e2207f2df5f5a87a3e2f44390755f9908681a74703197b78d7c95d1a2771e8782388975e8e0eefa35a14cd6ea38bbb117632e8d4f3b4ddcffe3dfa4d63b86b51240e7d7d10f437b9495aaaf1270731bffe191410f6a90668f09deb000001bc00000090bab929e7b47f9ffc56a6698a8586afb23a4aa1c135394fc784dae3798fb20ba90a120b82855688b82f24f1ed8786b6364df9a68e2f0798704c17145749e9e1e4be89447f9cae3a4266199652501f57a779ee3649be8adc4c4e515e2bb5eb6b7662688fef126aaa71429e5c7a06c831d6a3b4fe014084e76c332b02be583144528799385b1adb5a227006e516c7c651c200000090b97b9efef32a05892ac56dce7dbd53422e989e83691ca29d8b33c2be35873522fb4618a8670a13922212d7e552915def6c707d8c7d5b7bf2c27eb86c1745bc79ab35f331c2f7d47bbf973f5e4061beab3d0363416bc6d512f1d3bcc01fe8b2200d690392bddeda24b48651ed9fc04fe54af774b6a474e2b4726d50b1068ace093509adcac756800a16af821d54ec7d1c000000909226c5084e16e186bd9e541267ee3d429c15bb43dbf0b763b357d5320de671721292478be795f2161612269c46f198116b4fc074fa67c80f18d1b4e357961645275e12a098aa4c2491c88033e83cec70998c0490b185fadfd1a5ed843b1f67de377a733e70b96f9a283739eb6a6cb91e3a0ad6cef9f36fc79a8c137e391ad860235728abb7d32d359e61a7c81d1d5e9a000001bc00000090cc0215e729382d3444ad0f362c10056bf719c015218de84e473dc849791d970f9eef969e1e029bcf044160e4b86c8de4e86a615a8826a4337775ae718f0c5249da0b7ced10a9097a6f5ce151b7256c2a901b827c57f6f0ce0574c366dbc01cf1349fb660ad93693d4cdeab0936e38498378823c74e1e6c905d503609b1705481589d96412b8dfed83d65f3c6292614f9000000909934e72118bae1be1466cf7aa6a7fff16e7b7ad069e0803caeed5c89fcc2962159bc74a1ac5798d03622e679750b324bd7e046c5b893cfe79b91da241b65800d912434f58bee9fb242c4c99ddbe6694f4f0a8777d7aa71e3bfdf5c207add86e13d6e96b3998ca754b3b1ab566f5b72a8229e85ab4acd20574e82849ab399ad2bbd593a35d2fbb284522ac11d5abd3df700000090896c70456c2b313d7af3ed9a5c2c525bda692a4eaee80933d90db9e96a419f4f7c89fbe5d578a12ff8e9825b245431f76b851f33a8e353f3267f8252bb4522165b6c4bf96fa512302ebdf8ff64bf1cc283236e096edcb7d3b726f96bd1c7cb2e91abcc042e3ec5e06e74d748fe76b432fade0eb0a9cb20b06806f71415fc8a27e3d803bf1ba923c090b509dde7168318000001bc0000009020562ad9bf630b1d12fefc8c620f2a403f54813c295e87c7e90f527ab1a83f2ca6e9e92d4896597a0aebfb3f63059b413b29f61ebd672aee82b842cd1c41c6e56378c332552195c3a924a4fcae0616f117bffd90494105c3358d9aeb389e1350bbae80dfa5b7bbc7c3a30422f177eae6297a332ce4d78ab39383f8983db42d78f7ba2e78137dcb3bad3964a4e287ec02000000908d9737b8984f04ac7c553973a24c6e3b42c916e97512ebb783a07d7cc71f39cc316c89a37a6ac719a050e31867aebf4dc15884ab4aa256e3bd7e85144f9ffaec76c3dddd8326974d55b4fdb20c1d09818c2241bf3094744e5da9d95e931d76d896241d07edf58792c6f272c4b8e67530fe4f05c662ad8b3239ad450cc084ae0eacaea4c928a730d98982773c8a9cfba4000000902d21ea94707238e11327f310cc5a1d61bcf3b230dd8358c66534dd1e61141a3e8f6eb32018fb065de3e271d2f58e93a73d3343ada4788dcbc38458e908a3236ac828b6260f81ba94e4dd8b361c695272575fccc0dbefc5c37ee856177898dfc6bf745e8e856e0bdc0f8ed1460ef0d31600ef32af4a5efa05d3c1dfc71b80087afb2c6356354e92953cb28285632a5e2700000e00000001bc00000090b6b785a893c9c0c4368bcd283bd218703dcc8f2ecc9f721af430d61dabc087c4e0b0c3c575b9dbb67bd9b18eb7ea50838216d8fffce548aefccd802598cf68ec879632163d9d3f424f5cde402f2e90c6aafdbff67f1d76138bdf0f07aa66f218d7fa82d5b71c96c428086521f0a1b3d99f6570c10c1570def6ebb734ce38fba2d31df12e13fafea1903d8059cea3b38a00000090379a72abb0a5df1331e887d28e17eb23e3868c552d316db9d6630362d9a9f0b18eec57ce9854d860a772b2b25bb7138b79bc060c7d426c6c08b3c850d8db8d96500704f9b43ee791c28c24ee4dcf55f66f4205d46208f33365f534f4d24e0240dee79567fa3959bcce06b3e4431d6207a1a01c97d3adbf3383c8ef83618bfa92e87c57b00fc5188b9092bf5ada6ce3200000009057cc225fc73ba28aea06a45d52d711e347438edde7f1cb29eb308515818601cbe5f722ec0e59b1be58a2db33ac0740bd9c726824cc807a0b6f84817c61c339c2fd95fdf0ebf4d31b3e713ad261bf09745821334d718216ea8c2feeb0d21e31bb6f695b6ba86f8ce95af1169727d3c83434305ebf2a5800ef53395addd383aa6a860f2ca133e7c173a02807ea8248f5d8000001bc0000009090438b8cbaa0fe2876ee6560b32b396f688f9a76e7968d1f81350d8ce0a94e0239940ba0c1a79dcff2e7b0894111ae4969f5b82a9d602fba69377f582be4ba8d1dfed2f84574ee6375c6317f8734a547f6dd457c9027e32bb9c807fcdd23d2beebc622ad99659610852a3f3ae3cf55fb4e5689147ca3329931df0ba8d69f44f9db5a2eee4fed51b3602d0ddc2ee2e1b0000000904679f91e736276795fddaa7f672ee5329fb2b2805ccbdd3344ead6beddc96e33cb9ecfd683b9f90997c47f4fdb8d1aa34c9b2e259d778956736a640cc6b3c49f43d012682b8966605d17066d490187f9fb7ec62e0ac58c151365ff968f5672ce87f5152181252407d6cf5fcf72aee330382c05f284c9bfa40048726d829d715675b02b1bbb158099ed76de7732dd87a300000090171df1386679177b3caaf165a29d44b91172ab5ba6e11e73abba018a0712fb7216150d9914802d24af90df73b5d10e5cfeee085ba89dc862e131675351e2fe066b5edab3ef380d47c225134aa6696c96fc979781acd6d92c1bf1d6fe5a22952fce22b40f9abab339e8c824ca182f5b564f852d5022cec42c1e5808063cad2c0a6899dc91f4b4e0f014d41ecf30b0733c000001bc00000090f73cda38e1011799114681aec8676d15cf04e1996f7bebd9620b3899d2a88fadd31bf6c00de4b90d3d33631049e855eb455a0af7b258a3c87c30c737972ac5240c474d9e18fba22dfb6cb19113b7af3646fa5b0c4cc78129e064ed53a5dfce38aee2cef0adc1ecc9526947508a0525ed50dcf5a64a6a34c8035e46f154b3dbc91d3b62396072e48b7927ceaf80a948a500000090a2c90c3fd62e6c3b9236753c545563ab765db750c0d46fb03313eb289c16e21800ea14b8461d404ca2a3c132e15a2eebdcdfda6fb26a53e1c543a9c15b223533b1647f7aca04960a0fe6f18ada9dd4013a0976129cfe596f6de5c0eabd25b48b582fc782a503ba4ec03a1cc0e07213b9a43b13551261e65fb070f85e226b2521ad441db4038781eed1185bc63ce3dc7b00000090e4da73a3e62cfd1e71baef3b802a0b10ccb723bcf26f6115ab679724e6e08d1a589baca7fc9b1088e8bda527540e3d2d37c06341ce746b8c4f4d6133375f7fd13d0ea62b1f99fe88b143a5731be5f648e8db78b0352b87bc7c114676ecbf14790f5e328ad74e914ceb0d87c7dd9908a8e012ae04d037bc0ddc5c582cebf384aa6553fa166b8c639046910afcbd64ad68000001bc00000090857e1aee424f91f5699f41b2b6f3bf426eec3b2aac6f23f18df162c275c5c981a1f1c50cdaaf71172438bf825711ff7ca25c98e693027bc89aabfe189498b4f5a3fb62aebe2428924afd861410d87ef97254e972470c67f4d60a4c4ab6f3619b151ff6384b4d969f41f9ebc7068940b006fc39dac0c91cc0e867a39bfb65b855fa75cce185ecd028ee9ec9e79534a9cf00000090167a6241e3a93f0138b987eac85ae919534d16dc9a80bd86ea97ffdb0b9b6042d75a6fd0db555bb907336f013dc8ebb30c42990c97fb0a770742fb27cec4e37b909788ce1338151890dcbcbc8c5af9916bec77f98d4cd2c358a72f3662eab1dd157fdb71b58ea8c95e44c6f6e842c107ea4042fdabeb88cd7772bb01939449b3a84c95589b7fbfc8b65275af7561537f0000009071d5c3c0bf428b360fa2d5b119e112662503032cddd90044d840d6230cd305bc1ef5629c4bdc326df89baa9b27f8ba45d932d8b193c01ef48659a4706c4f00ee893fc062155c71ee0a07d964106e57f8d4fa6fe30b75d32fc85cbb6bb51bfaf86c24842d317ff4fe76663ab6ab358ccd52d81d4ca5e1f51d2c63269c1667f6788d0a2ef5abee5676692c32c63eab63e8000001bc000000905447d0488946ca5c41b79d52ef05da1889d794eff409b97f7c0ba11327cee35fe4481a454324cddb7dccf17ea311fe6aaf0d7d5a8b813a5ae9796eb447b4e080e5e96420503f3ce734879dd26a945fcf3c0517a8fff0501034a03c12f8fe328dfb4179db4e9ebba66a1a4ec52e63c149159d0c7d85390fd7b458860afb0706bf6a9d4b4cf7bb519b105dcbdb69a8e47e00000090bb17f41eefaebbd2e8a125e590260bd565dd1160b71761a311d35e1fb466be6b4edfe197c926b16b21ec942637a24d5cba7b0a97ed452c8abfbaeea57f84f9147d85059d020805dd39e9a382707c6c50e3db9740a25c1cc806acd0f2b3b348732d0b40d230efd56be31b6c14c8db7f323872f465a8c8c2883d802b537cd033fa22dd2d94d41dffb719209c7066faf76800000090fb1d99c034031173cf99df92d2c1466c06bd9fd2ddf61d80c7764ec2e9b3fc39e3754f8385d47c7cbc91853a2e230d68c43ecbcdc05148c54bf4bdd589c0de19234f13628c5173e59e73a21009df9cb2ed5fb9c2f572f3b6eddbdf12140f810bbd0d43b740b45f16a6571e3890b7d0daf91382c6df2a6cf694f755a3a54f2ad7d4e08a3c34d136981ecbe959a88a10b6000001bc00000090394bd2a4044e0fa016de48eaf444b3166f1155216741ca6cddeb4a8635bf438146dc5d98811ba76954928ed4aca1ae6df227525a888987d4d8ba94b7c8616326ec01b5f37da8c4af05b846737a1ca500cb2865a53eeba6cff09cd48cb1ef61dd56adf08f0d02d6cb792db82dbf92b24b4fb3e6ee985fd11f2521dd4eaf6e208d76998c8d8ee2bcc58382e8e403a6061e00000090ceaebed596c0d16e317d6bbeefc1256611ecc3711ace9376cc4204cacff94326588f0f3114653d57af1d1c72ed28462e6820b3fc7392131938b575e04712c03216f04d2a8fc6d2413ade9058dfec7f5e36cc943ab8a741873017c17c57869929df35739e7b7ff6aa64182ed1d21beecc3c7c884746fb05eff157a60c13da5a04ee701972f5103422b5b20f875ead5fd600000090164177fa3d9453fbd6c7cb4884d3b7a77e056a7e2962273c809411486775c93e06b6e2f067a1b1da7b7deb8d1cb1cb3eaaea0880d2a898591d12e6656c44db58b466489f58567f88f9d5e1f19c26935fa13fc182a358b7067af8a9fad9265d3b05f1220ebda17412e2a5f579d58c7727d5d151d99530c5a68ca290c6014ad665eac46eccf1dd4beab4add602ee4a0b3a000001bc0000009013f0191618599cd9a94329b8941fcdac9e8f2c843cb1ad35077c6312c089d53369b012990d86772aab4184f99dab44d4dabcab6894c540ae40c03f3c97f0739d98dc70c26f3b2ec3ff78621f9e255f095448117aae033cfafd752da06b13bf47db123018a68019c84ea43ac1d534fd8b6ab5b160d5764d920cb896c2ccf492d713d6495a1f5507d26866b8d8ad24fe8e0000009088a2599f38885350473ee05bab6679aec3fd6753be0b0029d3ded6f1a7d781e6828c47a0c800da06454f58c27383aa7e6ca6dbe57453a74ec6effe58b52b0b36e972a1fc5b3d965f8d849dcde51921a6b0755e7e3dd1cb7ff046cf1496f3dded3bbe5bda67b253d6e09ac2ead6ae8d7c2b763831d67bf238756cf9feda6a0078dbf8404268be7c950a2be61e1726ef330000009094d580c24085ec765663c6290fcd6b482893e572d671dd593a8ac82e50c2899db396a0474cfa5ba8d6b8ed16dc32f95af966916ade952275b586589a81d0c7fae4462e5f7569002eee9e419369dd1f7585feab27fd512d387ec76c4a38a3008691bb586210d1f006aecf9f5053362341994b414a0afd445c9192368596000f3528002e99747a94749be62520a9941419000001bc00000090ab299d12da5d4400c0fb7ede1ce9a277dfefb8ac60ef4822a5d3f2e2cece137e0d386dbfc29d9e612821b416028b692eea91374c805d368c233bf6acb49c8ca1d814a95863ef18a0aaa6351550205a065010b875e2802729f30777c6442a9f3a725de94b37025c070de6ce4ec381e6bd2462bc35010939e34a13b802cb58455ea56c994263367e6d9d5c30c94fc3cea10000009085327a7bde96de64cf1ec0dd4ae3f6fe4893bb14ba8a8f210032294c990cf6b8532f184c440f93d61eeb66b7f8f4900026d77e3c7fce28e5e8479aaccdad7fd97792199b48289ee96021f658f9542994ca61997d4e3ce8de1ece2eeddcc76c745b4de2a263246f98a6c120d4c896c1cf1dbfda47b149f41523a6ac90883c32d41a82210ae996907d5215f87c20010a4400000090b9297568777df8232be5498e8608b7244657c6240ec9b869ca97ffbd5cca719f0a18759e2fa4b37a7cf41c753adfd4a4803e2c9439cbfa4420776dba88391c9c5a18c05111fcae73dc406a731e9d2296758d195b6823c5853772b44583059794fee392be61e2523602befa969cd93915e2a2354eaf942a28dee21baf732016656ebe18812de6682dcafd4b43a5ffdb4c00000e00000001bc00000090801ef9c2577ec82636d3cd9bddf8fe9faa1916f076983c1eb61db7cdf5284a554b54c708549f4a16fea0a64a7509a7656d7ff04c0b6dd5b92b76641930d3ecbf22c0c96082a97cad9030dbb6287e5c4c9ac5078e55f4f8a1bdcbd55a42d9c882c1563509b06f4484a793be80ecfe0e42cd3acf1f33fab869b03690d0e2c8995e3fef9bc8a02f4cb7e9d076ba2cb0e8aa00000090c932ad01f8bf981f307cd0678be81a254fcd35fe1dd01d89f4dbc1a08aa1b6d7821e4599904894618943195181dda479755864f7bbb228795182ce13ff45656bbca9f56112e7d630bd48f8490b013067141e69379d4ccc05f08c357f8e54b10bf8ac4731da861cea9b509b90c0f76fdd834371a2de507483b09b9d402065fa038b4591acc7c3a1726616c368d64ef87600000090875924116fbfe13068edea36b4029e0f8684bd7921447fd7cfb85f2ce489b755934b81eb2dfb0d318cb390cefead098c670756c2204a29d8b53f6284618638950529a0c5c6bc9e927efa083b460a275c69923a91038c0089470cbdab7fb51d7ac7b05e20bef690eaf28615d5de31b260257239137bceefac894dd3803070ebcf0a743b06accbe856b7785d0815427796000001bc00000090c1524c555d1de312b4d6dfd4498bb6f0689f10df8814c31dd2cc9f9e47cae78f4cf612c9de50d777cabf50e738f3076a1d4464e3d51631f72adf16337c02d58da83591df58291f8edc2055376691623215a04d791b2f70d724b4999523352553eebeb5a815c66504d1f6be97ae94c778e606d4ff110fad07a919469eba144602ad947f2f1cf21063d666f700bcdc152f00000090a4f0fa4eda04c3269acb3b63bd19447076a8df4d3c7f4ed3775da5c54afd384d84b0dcff3a2afc5dd9d9c604f0716208b997a22a7f0ebc3794dee40ae80031b4ae1e695636fd8675eeea73abe669097e05df866fde70faf4cf15c9d9eb01645ffb7fa40a8ec963802a6b838b47fd91466c838102ea392c72d20d1cd2e2cd525be013551576dffa28bb6fbf2bde78b6e20000009031a6d25d6b5bf8d27fcd97cb17614b487ae1fc7a3296a0e56c34492b7cfe3b52d542b80b0114fb19b7527a8b7fc497a0d88fd8e29e8d86552cf56e773dae95ad63502b0fd6d487cf69b9c23b808698ce7b707a40b5b765da987905f0979b836aaf6fec136f7427c9f53273c7145c1cf8236f43ea369ed0ef4250512935073d11e9f1a2605b9e6fdaf9953c89ebd1296a000001bc000000900f346de1f80bebd75770adeec5e1b40134cbb2c6d8f71bcecaddc6a162646a7dc1b546e104294f9d399e0b07274babe75668f43cf1bc1390c6c7f03479135102d76810e3006c7a1c5691a677f441380b3749e616b1853ae1086c2f9de1ec1158a5966587d30fc7a062a98b77de490774366ac4bd55176ae71ebcf97380e3458f99a64c68858d9a542d787c419407480c00000090afc3a982e9b18074b18f8e9241af438e78e8ac319bd7db91a3cc42b095e12a18dd961b24b8c863a0994234adbfc2d6e7483a79e4d54481048d90cccffc9465218ff5f5d901203764b62af6b4db57e2602543585602e1f94f4c086dd69c5c9b37edbc03abffdfe322f353c5abf54ce07eb8ed5e805a5bec7d59d15256362230beac173d50d74e67226306ffd589b5c0d5000000908c9f222581c07fb644955af88c1a00a64c28e97433755fb8d2b824a045ef3ef9718e05c4ef36217d6bf5167ad0a5f17798cbfc967d8db658d369d2ece607d90374f295103ae9d79a0695c5def30bd3a43c4e04d2d915f347f444225e75f01ad2d68492efd52ecb47064ff9632f5e47a8d35122a170d5d95428aa035584ea80b6ffe3e499ea40492da1d7e469a030ee11000001bc00000090f3aa49be1ef2da782a3a250d14a09a4571b0b2875223e27ecf0701a757e03405d9ec08c8bb839dea797c25693021bb0695d2e5629a2568ddaa8d79b3316a5ff059388a49c33c70e4ff39cbd33dde9f049c3a9aa1dc9f5c0d8143641736d572c1e3486a58835a47adc0d8fb9710f1563229892d45e055aec29e9531fccbe7b46ceb68ea5529ebf9d415a5dbdc86bda1820000009030629b2f31fbdcd559bda5bbc841d7fc7127e1fdcd05b92fef2dd6172ba516b3712c6c0919fea5c19246b15f5ece0e66ee60b84372b840b1e7b8b7e710f105b3406e167774acfa409263e612b92705475118cf88bf9bb02f87bfc8aa22602748f8b4dd0f60ffc56b4569ddfa8b2ea728a18f6de5bb6f67f302eb8284f7ee74b6ceb8343b52bd1bf47d478b3301c7dffc00000090219a86279f2a85edbb4d6f8431b1add2747a087197466d378490c9193749711b0bb59b38cb7fd15898272ca2dbef517963f6086978fda51cf685209158d6222adffc82ce8179e30ea9bf2661e10470f306835488e054e6b3253f78a2fe6959979ba5d7c27e3ce187fc6ad8d39e0575aa6ef7be38938bded99f596d09671890fdf64d98e4ac0c987228b144dcf6d3b3d9000001bc00000090b5680313dd737e26fb80af1b3a2652cab7da5447292c4317006f6699ecea9c48ed7cda8733edb6ceb0467610c4c454eb79779920fb67e1658e5cdbaa43780e0822997aa6341347fdcaa032bf10afc63c3e32c4ab0a79943d9069c2ee16c1ed6c0afb61b3b468e2dc389dc5255e53d29576e823d8a446c27146cf9edddad9cf73f800c123462852b2e5e4262db101a13400000090539c18db539b56c610e0ae6e65aff959cbbe87a2d1265e9641ac1c6e593a61e5430828e9cc6959ba079cd68372f5ebe403db4b3a765e6596118cb67b36ab498e09592873b5f65b5adf7ae22bdb1260a35d66eac4cec5ba2f25ea1aa098a014dc88b399e16d3bcbbdfba407ba23c652b8147e044a93b354b46ae70ff0132864d5da00cd9e3c3a3d3726698cd46813393800000090d689249495b3e90523cd0c7cfa1acd98c279a814ad02cead5651ca56edb9cff526005591fd5c5630035ba8383e59e11fccb45700e3f0f185ffdb7a2d6980e57536dc68d0f3f5ea5af29e04d3ab2a4cb396c6931839b74e6f516c13ab1c1705bce0c8bf55ac11796c0feee88162d3ca18daeb835c13d187dcf4494f582d5013b5b36cdfe0d8a01d2303f68e406643922e000001bc0000009033c59257596f42bcd14cc4931da340546eb7ed481e505983ea174a65f337e3ddd8694b4bc91fb9c6aecc02bb26bf4be45f7781d8c71268b898b0a88ab612969378e8746ededd98c2bf384005f182c002f356dc7e9f441aa18638f7cb970f68ff146335f746322443e427e941d567d8b2704e3369a4b7cafc3857e8f36fd05b3fc655dd4768421fad2db557b6c7c4fc4a000000904632ca5761f5e73e9c7c833817c97164030c0fa8b96816ac0d0240256c0b823ad8f114c1bf1da4785232cefbbaa1eb5c8e7148d795a8507f1878f04e61bc372413360ec0c89a590d82f66db9a7da440f04aac88af5e636d3316d211f44314469fe2bf49a563f73d4bf12b7b318fb30538c3dcbcf254e14cb686177c876e63a4f88868fb35289fa8de8a8d230ad7452a6000000904b24f06233a197ec6bad7cd38cf4bc9fd4268b7e1ec2e5d3e216b44c2fd39b7a091d74e4444021e4b2c34f7f6937c9c5eb60d20c2f5c3826ae13d21bbfdcabd5a1412cfb6e725ef24cfd96657034a248b4f9923f6e7ed377cb8082d928a0948f952eeefca63ad9fb5634dc801fc3d0a1552ce4d63b60f953c560e6a1ccc5dfd2ca0a91873b6dc19b5d16e4db432026c6000001bc00000090145a6a31edfe177e2a1f9722a3aeee99760da5a34a9b69ca0a23c351f41021478ee69c632627166c2e2bcacbfda3ed3e7274b0d71670bda552b51a53c98e334ef07f4f7ce8c1ec45010f4d875cd8a85ebe0af3c7644d564eed7b2909bbc7bfa0be1b43b65e660bd592476fe14e73478ea9e109473a89bce38e34a75d16cd09975a4043763fc1b17cc867e05888af015a00000090fc1864227ec8804b378b445c8d92eaf0935fc6e49a1bb5e62f5df74e576225a3ec1b98b06bff1ca40d896a0b3d1fd5da1592fb129528ba4d58f6f195866c7d6c48b26b475a0f72226099e52a51c2259b7ab9edf7765dba7454cee56064f27eeac649e798bb6353b2258b098cf8ba89f662075b9e3e7d5244df22b9a6f5d6c30e3da30db89aa20dfda1340667907efd3b000000903041f714a8934ad43722f849083e7a6585d66fddeea9be2f423e6d4f9a8b935d1a88c7e0394b53aac5bbe8606742dc2182be3e81be382fa0dc7506a120d7d832832b69f1094d04cd5b2c8613dc858963c5ef897758b5b5deefd5f8eeb76dc92dc996472cff8c2d8d2e840c843a7d7d44a7f7a7461b9819412fa8b93c1923b8a689ae21e8c6bc560cdc13455dd1ca74af000001bc00000090b3e2eec14675cfb9e6fae9e2839f095d822fd6181aea14152a4ea49cf7b89242da9ff57e0bf78e006dd3d83b0b8be5e884cee08bbc965f6953efd4ed3e86e25ea6048f35f4096c0f96503d21aa4990bfc28679707704e3b8a04be7fc25bdf4e509a0584c4772f9e08b1e9436ec371758298cb6a41a65fcfcdb333b12969e112ea444b6b1d1a32ed1f4498b1d3c8d990800000090f69263003adb1ebdadae02462f927195e4012704433ca265ae4302a17056e4ee1fde8ed8a24d804afc735761c06a5a0ed954ff73a9698e88aa68717a8055032cf0bf3d9eb51bf7c90dde3f8e351386c850281bcabe4da59e52582e05d64d74b4969e7480284bf8fd8062912d4cc469193ecad218a32fa941cd63761ed22b637a4401dd09847c9364389a8d780774a67d00000090e5dbafefb9b1634f77bb47a9183ede40562b5c9a0dc801d38d0b90fe57c0af4a5fa2a7a6fd5f079659e22b9aa6b79f9ff124df2ebba44bcf1942de81d7961420889728a12eb054ff6802fd4a20e5bd047addaad41b7d838cac5def04bfbae085b804c2caba0ba79df0230523629e59938442d6659a25d8a1d99e09a1397fa3768f57d79924ee76da4da67d008eaca622000033a000000ce40000012800000090639d486cdf8acd57ef037bd52e740d927260a038bbcbce4a25bde98af3f670bdc7368780be3cda17b9e8e1c825b02518927735957c6c50fc33f6083c635704a9cfe1d511917acf0f63b246303b2d782cc38fc32781d41e450dbea20b50c5cbf1a1b673c6326b538f94430f5db70085f3d9d01b328f165f0e790136b52e7ded86c38eeca0390ffb4463e537ddca0fbe48000000901d83225a50847a2925cb255c507dd38f4645f05d85941db543000b8cbf1252fe12a18668514c4565dea3f9b88f87fffc65a07af88a5f6ab57a79db7be69cc8d52a2064f511c7a2a04a85fff0e2688821b713c3994301835d056346690f9764e5a7d6991083b0484c5cbe7961f4bff6dc46658c8fcf3529e187d781990f2ad7459537733f81e8212205dde6a547409d900000012800000090cbe5f87209419bb150056d00d04fba5e7386c8d0926df7a3c619c1cb7285a80b542d105f55cab4a2929a1fa5fced09fd4391159d41bd97e3c48b8527f1a7fa720786f42e149ff3684b4602e9c721f841729c5240e02fbd72a69334f1fcae9925f661997b5a6f6885fb6fb35215570dc50accd2888b39a6edb340592c186a8f0c60ea6edb1c10fdecb84a6db4cab102f800000090a4057e4da28b2d51b0cb9a14ed984359df78af483ab432f408ed202c48c4b9cfe3d2bfbc69b3158ab635863f0cb918ce6f517be1a986235926174dc9f2e90752b1d4001accb4fd267f5ff6299d1831672848e7f17160c03364fb5a00e29822c884db91413bd63ae112db74a1fee36fd37709c5450548c1f11bd7274b518871cfc02606f22a0f47e2a0caaa158b4df7310000012800000090db4b8cdf217d4e8d5457bee548314bca5d7d83fc27aa60f87d459cfdc6ae82f757614de089da919dbae04ae77f9422bf1b008dce97058dae7a043cf1d9f82f6e3220ac8c8b5f1aced6bcbe786454e2156484dd8449e1633ace23b50b813d312b7be8a33c5e721730483d57a6a2ec3bb08da97a5ca5ca787ae34e4ffff000d9d001228941442dc2f3bcd9871a1dac37ae0000009065d2234018f4d38a5730ec5510036db0a1c6293e5ac5f5c97ee28729e2fe13357c1da0119880138d20e25590e624261b70794267f4433d4711adf2bac4c08757568c52d52e0cd182a40f3181a130fa4964886b5bdf34a102bda3b0e97830ee548a2e4ead76689aacaac714a62f640128165d477057b3c7b6c9b2448613c834decd7e5ef2ab4f50e9f32acd6d236a20fd0000012800000090a2fd7da86afaa8d81634276960ab4fc9b355c4fd2c3ea5114abe4caff0427f96f25cfdbee7cebf96d35d294b96c22a087c702a05914a24e5a115c69fbcbfd25e21c971cb3697127fdee46c11d4b9c30c2ce5de4259e41961522c4118c2ee00f2b70bd7d06c5422c26981683bd61a6ef754e087a9eeb53b16e3bcf087cbc8f390cfe97986f1ef6b0234493e9d8806275f0000009079d388084b1dad045b2f73306b13bf335be555ad14acdc26ae123224ada033592a2be1d2ad3a942c4c532ed1f0c1c1ca9316e10fe474e12dad4534eb8f4fa045803d50816bb9579304a7a00aef983b8fb834344fad8b4e572a766fde8676cab6f11436fbc448abcf88afad3969aaa988112a7c5b081416d4e70963f108dcad242fd5d15204d370b9ae2025c0f6faab620000012800000090e0156263f20bb92a39dd3049cf6f418143192d5904f2734340f55fea7854616030766503f2136688003134e058481035725434bb5a09b2f16a61ecd6f314368cb7e567ec36c42b17728f2d47d71b49d1853b4988d91dbd0fbabf36c98c327b19a267d56fad2dc1f05b2bee17002e3e00941af273c5e9f84a5cb3624a544abe94305c2d5e290fa0e8340a084825fcdd1100000090e755259e0e6fd3b0d8cfcdcc0a7ab644ecd780e405dc3996da1f784bb132cc34d7f800605d002a1fc88f9f49bcb408069b7f81e1f343aa1c6c3509fda4147b8cc2af53745e245f7d7bfbf177d49db1d6ffba6fec04c78f3556438ce455c18e9d54d1815229ed43eb4eccadb65162a90e0eccd7b628fa5649f3def35eb04361df8f863adb0ce47206df3b20fcbab8417d0000012800000090103ba4b387fd9e18befbe1321a17774de0a57791a98aa00ef7985afdfe51787931c2c20425516fd2474ad3bf2ea9a1dca54c7af84655cc99cba7c2bc82107809118d13fe2db6dd6e89304486c0ab9b2248628cd2a840cd379640bfb9c1125db845214c941bf00054baf2f7cde366ddfe94904277950663fc4ad23356875905a632d2f9b51135f6ee529fa7a0db622c8900000090a9f7c79016d72271446f8b8f28971a011db5e1c26dd313def999790a8b28b94165afb94360cc66edfec6afb41635cea260d3ecc87c0fdad7f7194e3b4b2e68b2ca1ccede1a7bbd9a1fa7cc75b3aea404052d0d158cc4be13757bc9f15c34f8326c2194ce4674fedfae84b0062f2fdbcbbaf3735191885d22eb23d7c37dbccb17c6c73bd6ce64e1b4efacf04b2bac202d000001280000009004bd547838a4f37fee8a1baefa39987c4c979636407bde403d8d4c132253e17d7a8582b5a0f883527c36c5b766b7e218e47cdf5867447ca50bd936c7d9d1443f06429beef8ef3cc0e3b4748bc87f65fc285fe5f34dd38207c9103418f9adc69427f697d1b2a10f8b80cd79224b64714ddfecb2ee3927a540bc0f14ff6c6f98d85397e4923c5ec144a1444fff4e7dc249000000905e80407b1c81e498717666a4ae03f9ca54ce14fb5ecb9322f0ca9214a2f35ec5475ea05f21b1b634b940169448ed2ec1d72c3ab9aed5ebbc3abeab2b5e1ed2b86db7940028e2125ab67427fc5399e605057f05642423c1618042318484ea12b7686b080a0162eaf692e3f8ed5729f9931c15a994127bbf8d9c2c3a2b41382a811804ea6eef3fd871505b44a43e1616460000012800000090be9b4fda861bf7888112ef635cdee9a91a3d21535b7362a6c0dd53f556681f20579748d7918f0dccd5752dcab5d3793e6f996af0ecc9d061686606dc42c1ff4f666473fc8091e1925887df5338eea6d50641af70b95cc5ac6c0f2d55005a6b4aa0c0358889cf9529e9fe997018ac9cb16b1186cf1a90fe071ae3bae3c602a6396db6ca6f499bbafdc8ac4610fbd33d94000000903498f0e293205cd2082af437d12d1619d59933be6f9d0d8563bf5c3926434ba6abc87b4056c775e78082a9a53a0357fc67eadf16643000af9c25a897de7a076b0dc6e73f5f39bb42a875e0121bfbf6d1c6817e970dccb8045e71e92ef1ed9ac033cafafec3ed0e61cf79b00b3917a7cc3e74d4eb6fdf4e4255185abbb966769fffa8c939e90805cba9c1d027f235eb12000001280000009072619021db2578b89f28361d759cb625b80707604a73e06e16da844e8e92953832a9d7d8703bfa56a6edb22fa80a55def20914c155f6576038437b26e348ef7613f4fd8616f6ca34eee1286c22b917337072c4fd7f056e2013c85d480b81b0295956f3413d532549f31bd5d1a7fff5928a68d6c808a21d12147beff79b97774dac67575e68654e0c9e4b0bdba043b0da00000090b96df6fc07703c2d4f7b60cc45c2ce90925465d435664666c162e2493fb6023a4472c5f6cada4017ae3fcfce8660c0872ae15efbdac00af8c391dc23d39fc94950b6b4254b8c8e64241976692a14e5a4c80bacf1a9091d76b3cb1b3ddec01d749c6469b28e55f457d44ed8540fbd9dec42b49e9b7eb3461b9e03b2b2db210fc9408bf399c69855bcbf5c94db97b0d6d300000128000000902bb67c2d333b2d72140e8125c20d524321de7130124c205c8033f5a52ef5751cbee212d1e9f8fbd55c9ab593bab90bd8d0fbbc74cfb7d2079f7fca70814457e1bd0f15193e3621e2ae2dcb4b666ffa95cd90f27ce22bacdf3c32bed9d1c077fa3d4b0029aeaaac7c0e21097573cac7833431105bd4f7cac41f950e81ce497d073fe041c0b267963d351e7f46bad85a2300000090989a5f287ba771b3c486594cb4e206a7fc8aba4e4b7894a5c95e92cf705983efe0dedcbf2966814be4a00aee6b386da748020ec285344fda37a0a533ce4a7161789a0c499b62b19c62bc80710f5d64dd8823e68b324a32e2b1c12335be5a8cfb55792f0f8dea993b24374838cbb74b1e067d79454b3753b758d12406fc63fb95887c8aeeef291add1091e21a21a531d90000012800000090086f352a63a2c15b771e0e95cc484d9ab851d45ece9022a2fc16979ccebdf6cd8a281d080d948dd0da7f84a3d037f11d57fa35a96a22f2b9d0ff7094e3dfb5b59b407bc65ab07c59c2b9738baf486dea809514987a7b46bdc7162db13c94a09580abb4ba31707e18fe0a83712de26f5d28b97877c9b4f6fb82521097d5fcee5159ae26c4e90f70b7b8a2ff3a0be9491e0000009025c7d37f4395d5a199c6c99fe93e7b7cf5c394699ca0564da5c668b1b4a0789681354ffa1142895c23a4115e7ca67ee112af0bcf0e5ccc798d9bd3eaf0fe14005b25256a460585325cd7c1f325edcc0e161c001fae73fbab5d24f9ee352c9ec770be8ba37ffa58c52b9e9ce3e5ef5a72d9e75a9dfe7e1237118eee1c6a8b21f0eaaa356fc29286ab04b212aa6d110bac00000ce40000012800000090dbb4d0d2a8ec9b5796f37e0276b93adfd82de35fa8ddedac71f24a3afcc1fc70cddb2f0d10966e8434bb4b7e5ea542b9fbf64f903effc84e1e089963e3aab331c4569d6d2ca5bcbe3ba69fce732432d3b7ff889c3c810e3a4fe597e10a1e51f9cd77e162887e3f12d0b2f1797e80c2c0ad744f4c78c290ea2bf3e3bf90251b5b304c7fe0e8881e9d6734da71614698dd00000090e15c9eef7b9c18bbddf844771bb2689cff590cd861b042087c7d5749e43bbf1b07c0a99a7db7fabc0f59f7e5f8c5e86f8867304654bc12e2ddcdf5066e3081348202c12fdeb0380f41bf7bf0bf12aef785960a82cab387ba3900e5efd50dbc7275452fb6b2a3c7e6d5905019b5627c3c9b177e8826a57737cca86a66ef73d541e80c25f2fa774f84117b434af3f03aa70000012800000090237b304e7115ef24ca0b6af4c6904442432c1653d1f91dda11667a3391e376a8c59b9494bd9fd8a3462a58a8ae2e43f38287965d68ff229f05db9ea2f05cb42621e99230c1b6eebec317dc511f75de10af0ca3f3d540ac79b4de653802d92487593d016741aac8d1e6f767c2632c80fc12b3fe9f84acb96f73f4e93573a0f9f4672356fb526981d00798e3d490ff622700000090d36abf7a4952bf867dd1c2d2ae4f5fd680a698e216c39969903b289cb79464bd00d28d7b81f3c19fd3870cea5d5152cea39d2b9ab6b00930075f258cc60b036150984914b301248279e5652d4ae7fd2767d574814ee68c9fb37a32532003e1bcb4875521e6a9f74b031cd71699689597753451dc29abc51026fdec1bf0b522e90071b356059ec3ca16d05047541581690000012800000090cb8402f03aa6f308556bf119609f6f02cc0d2aa1af938d6e56be76de6012a6ba66ad93d74a8be2e3758976c78a1d84352be6a8b1dc8deae64670304fd476d7d41e20e1b02ea33594014611ba725785fd0be257de48c00be120a5f233322741713f5da81edd9c6cba8afd48089d158d0dfe9eb236bae1290cffe993b9b8306c51ba8b6d88c2fdcd4cc5f3a94aa0be6a82000000908556eb17cbe123f2d0304c877536b7f6da54fe5c6a124b6df08098d77c7a79d7d871dae6f125410320f821dca432ed032ae877ac84f821568b7daf89631392f8186db2ebb30fa836234ef18d64aea7d13d2fd05aa3789c14c09a4938015343fc06a580a43fa333e6be0848f494e6fbc0e6c91ec752ee98e220897cc39808a1131c8f5811b4c60568755f1f419694673a000001280000009019bd42cfa2a996fc95214b0a1b7adbbd631dac971238e40a723b018b5a75787b34c00b7ee71f3d1cc2f160f6b395334543f03fe872d94cfc04c4570a9d3802362ad77d482d6c650696580ff7d50df656a14d82f9549a0c8c4b4a94d4b01730b50eafa7bf8348415b88dec562fa729e6cf4eb1192646d98c279ce586af89b0906c38ea22c1d7851c53639f3d598ff864800000090aef905153f7086f16d147b2ddcc9b602bdac77f4667032b7b874889fbdc7cda53099d931a61462d93a751ccaa750b3a8e55693a687cc02359177745540efb45f8355f5742f44bc19572ea9e5dc0c090288127569449d536728bddf98419cfb073cedc949b52cbf25e8d7371ec989708a452cc8819922688d639df27c5a6f1f89ad17b79a5345fefa4afb930b655170a700000128000000904d010d18bbc916ce1b9cf07a77761275b8452ee8432c84c45f2f477e964fc5bf1510da3445b0f879597fc2a1d0a6cda10c47c58313f76be11f9250e43082db2c2f2061a213c3d954141247ea2a6c7e4836ae3859b4be1b7e210d0f6174fcf171ba9d74991c74af9a6b188b56c7b86c08846880d5348b7522f31f15819b6db28434535142e1896f4063a84fcc40c9992a00000090716ded02fd483c28d914a74f40e01a1dacf169f6ecc39ff2769079726b77cc7dc3cfe9647970fda3ead30246f2bb8ce41e041a93b690c2c954c305aeef82193e086c1803c04ae989b9ac025ba9436fb36e855e2c7db6aaf202fe6cc400e78eef0d8471d1946b3b9103ba82bc0bbb3cbc22bdff6de9b614a08f3fa60695cf944f69f26ea7981dd80c39a78a4b6ab2e6170000012800000090482ddcea8042e342790b5636a5a253c4e2d242dff8aa93c4e42eaf144a7a43c645c3502bfd25b163904caefaf223321c08aff19bf387485183d163fbfbd2e4c4eb3851fb9c36ad06aa42eb3f77d02fc7d6dc85b104fadd34a87e1b1ff9f6888630e641f4110453f6ef24256db1e7f1a70e16bc995c5b4833b454876830d2337f884a2880bd3e851c7762343691fd642b000000909e394aa7821fba6dde93d161ad4d0a20fda7271f4e2f6e75e6aaa6e04879abdcdaeacb6a966c1377dfb0a9be44308338b5ce7eda23a9a132ef3dd00ad9e33aabf208014fa7d7eced6ee23094059a9c26a70777e1452ab451db4dfbd3701e04aaaa6ef712b609559504193c3e4f20ea1e7ffabd5d98d837722fa9633ddfb557dc2b28908364fbaa10ff224a6db2d759560000012800000090c298a805b2e680a8867e93addd9426e09d5570d808085b1c593da76a0400d27d559c39107d45e0ffc6d0737c8750605ea0ac4d8a339162f595c9b9e62488d921a22b120cfd1ccd2486cfdff659910b3cb3fdd671702b7540c85d27708f8ab86212816cc4c66624d9d1d9db16bc6d1272b277c887226c4dd3ea3d005b87196355f0e50eea16e4be3cc5993fc810228858000000904489997ef0faa1245cdd9d8c523aeb6710340f949b49edc38c89487f13a67e4c294a15957c598097d17155c07f67f5e3eb61f735dd5cfb4428f097696523942aa121ae82699fec94dde8b460ba6fde5113395b8fadd7ee8ff297b27b04745f73314a64f23c5e1d6a71a54c4c5d6f756eae8c17548bda4cc54b73a2efa316b7b85cbaa55e74bbc79a8f0c642059c8b2440000012800000090b99bcf815e1aa84e58f43e479149a40360fb1b016e51ee5af903e09e16afd3a1f43adccf0f4f7f6481f3725ff7dbc611ff78ed8589b37441e5bc4ffb51ee8c10cd8afdd2d4651a8723e00d42cbbddb31263269b8aec62bda4fd980942ccd3f2a0b2b7fd5e255e0e378635763d5007da49dfea0d93ed3feabd723daad70b689ca5d88f136018a755ba897ce4aff7a77e900000090cdad61ea71af30981f6a01c1c1f922d1006dcecd97d67ee300350c45c71bb02dd1cc93ff29ae59ee29f9a0b763fa0f184e5332d8b5c591acb33f384559460bef4c7cb663d37f15dbc321e2482d47a262923c2f9c121e0f8ad02b67e53963f0c00a4362c691f209039fd3fa4af613b447aed473c44f18a99a5f2e28f65c2fa11ccaaa88310f5dc64bbfd78c1301bef18f0000012800000090486fecef6b3ae95ac8e6ae9f636548cd2a1b3aba0710a3fd00a66cf0f4b7333b33944c0b0d0232bd8fd79b22daa745adf3a04314645ff0b6b984c152226931c0aa8b25a2e00d6406a3898b4957b45454c07d05c382529d7ebf344c77835dce02c49d0d55b56cca350cd2ba86659ee962909f9b72bc773806208af327f23b03f5b4014eb92f3fa476e85bf0b1343f33e0000000907bf2e48176476863d220b04a0b95b41f139fd6a2d1e8047f75e9010ff45fbd412a661ab30fa8549538fa4a69819cc2e7a2e2adc4eeca30c0aaee2403fa639035c535a7cfd331399569ee47d10df8f5faf860fd3193ad2d5c544cc91a6c753ef19a1f6c64e1e764b6b10ac4dcc40147571016a8371ff6601575956629a891b91dd238c262ba67705929b1edf4617162660000012800000090c3466ce7a4d524534483cc46fe71b134827ce2f7e313981ae63e7d6c0a433690db9c6f7564029066c585d50ebcb0e4a79280c4a31440aa66beb5fa6b1076c36630ff029c269ab377fbd32b8b2b46d337fc784b6ca7a8e150211fd5fd348f8495645940607733be947a216d4cb81c6f5147dd0b4cc5204f7600ec012273b312404d0f7088983a9da4851f32de157c526100000090664901ea78c6963fc43fa423d45f149992d9af67d74e3b49c9334becfd002e9ac159c7b4bfbeff96ffd74bc825a41493a2ddf1ec8154a3c6c9e3b6bd6af6c1cbc7e7e99a07c16538e5dcbb9864885e179ff5742d95d2a0bda32956c3d90d096eb9eb2c99746bbb66601700ed8536a126dd31986ea2b0299ed532b8dd623359453b20d821b27b712f3394db9619c496f0000001280000009067238c9e1a8236663c5d759d22f7c0b5571b4c3ce87609610e8c0b0c22513586b6091a099a865016383ac203315e83bbfba56380e251e40f460dd28d1f4f48847b1179f57912057e53b316301f603beb80f2fcc62e896c9fff553420163e005df74a455c6190e30b8a4276c7af0808c91bddab3f9dc147f6f31bea913ddc281647668e0521d44680cfac9748cf7fa679000000901554e014140980588ad1013f5514aa886ca1ffd5cb1e80f3ddcdf1652e9bcd2e418cd2b27d51a79658338c5c6e35d6e257e537d769357a0c565d766757b02ed40b720b751616d6408ebbc516271759fe0685feb6745da64dde0d7f95e85abf4dfdf7c1d98defacc660a6fb1a448bc6881e4d79869234f981095ad351b06e5f3bfc349b68affbdeeeceaf3296024d1e5900000ce40000012800000090f821f2e5485e3c0af4b84fae21d986dc642938632260220147ff8f0ec70c5f6f97e10343c0fcc465c93ad626a7112c96c9e29b9619e3430c79306697e4b79e28b2a0239a176a54234746e061b8859cd13329f145ede2524db4c02491a218ba19fca3149ad8919ded8aab2d9082594c666094ed5f3ed0296f5483194a86a6c09af2a1905020ee88ea4592f5891772da3e0000009083f8cf115bd237f940b6b6c0b070b835b3b1e16b004f565909845c1f775bd74479a0ffd4a260d337ca93253d9c15dacfdd648fe0be61716c8c8c8c7e6351ce8fc7555dc26409ca9633c3bb6cf126793f197fd40c3b80df76046f8e46bde2e11802c8a182468c8a900c612aa11a0edf37def572ff0ba72f1dc075b0aa5a9b37d9a3c2cc35663bf4e2d2a36f417a6a3fe90000012800000090fae3021c00189b073c016491925cbb782113fa0cd7559c94c8e2c12853689cf14da70ac3886a89f22e2f7b664fee4ecdce844163c3273a5112e33d709c1bb5138278512dcae2c767b90e178f102a0ef2540f30fa24cf05b7336952e34a4f4fc151aaa6d82fabe22a6baa5353684ed2bfbf0adfe7120ae8d1ed6c563bb2a87dc0e0c18298fa7a763f3aa2250f41228e0000000090620fe1d6a7da657aadd4e29e1bb09edb6f293a84f08055ee5e0568e2620ba4711cf8a0776b139ed24904139f442ce4390c988814b3b5b7b4afc27c4f8ca7c2bc1dfc9225e45afec25092031b38974666ff0db3fbe0082703eff4b153af602acdd9ee19e7023d2be09d6f567ce79929231e542eab9133b09d39b6cd149e8af3bd686d412afd06f2e88632a6098f3574400000012800000090dcaa62f948654f40d893c4a4c31662cc125b60c87075fae66b66a2183e781cf7beb587bf57437f9827a2b9fb78ab3dcdc5fe4867a4e8b8b4f012abf3626b64af0f552b9419d35d67aea4e48ec7ff8507de86e89b4354fba12751dba280f8a7f05d52449c5b4f5566fddf392e9e388d2b68b35df13454c60aa110b1a738e311d63eedc223421a48cd60bb0eb5cbed928d00000090d6bd5c8f5170af53e76f14b243f82a2c2b8b9d68bdd505c6c2fbfca36f53333b91c1f765d13b2b16ae48ab9b2d12ae0f1255f1f24c99692b71c19341d2e4776562dc543f5064fe9c7f0df630b0097dd62ef280f42b7ab50e53a42b31cf64064cd20ba1f044e24197b1eaeb1f53d5d7b3d7ef7de6ee682c5ae9f24993b11f42e627740af2e8e9c877b095b057d75714c60000012800000090f00a0370a0cd5ec57d9d79a44644cef128fd247847a671a4de662325cb879934430fdfb488edfee63fa4a177a76a5bbd7fea6aa4c3fbcd9d1926ac271ea7235fd3acd833d974be88a9e8df60c272a2a853d6a1876e84cb7857d2fab74086dfb7e56b205712d19a21e99465ada71395af3303ccb51417da3375faeef928696d9dd86cefd69cc400c166a75e7ccf78dd5000000090b085aacbaf54e57349dbce112679c344dfd54fde70c15d8c0e284c8c70f37dabf14207e638287f062c349e8b903a33f0046e6c5695a1c973223dd481cea29b899e80db83fc05380779664157dd9679ddf6e1ceda231712637b1e527bd5a0f14fa398cd793aba15a21a4776413e04139486b8e5b4924b0b5b0663b767dc5c44f3a3fb506616eb9627e72be73a445df38100000128000000904e04527a1fbc4918fb0f5dc938d33445bd450ad98eb25e3e1d34bf8aac57f60b2abab9fbe140c2784ceefc2e437a38ca309c9bfd2071f3809a28383e9faa063f57ad8667838dd1be75ea2b3e299cc4e417bb5705f1c22bb59e4a7254a6d408ae8f55772b4f2007ced955119173ce0e00a632de4a49e0a08414b308eb02da4a55231f8c0418131a63596955bf270f38350000009057b894cdba6c674382d0ca850af5dae67fd1f3dfc55cbdea681145d7bb6187ff3a0dba30eb41e19b3e6832c6beecff3350f116211f25c509918a4980c1c214bfee81f2aefc930c54004f0dd3263e106a002a12fb9c7796125ad555a1d7b37f5149bd1a27f28a7dd65ce85026647d18d10a0a3f56747e96f7b1e138a12bbbfe3b9001e0eaf0066c32a2d3687fc62116860000012800000090d4461f6118036ab697daf4e90fa5cff8c853f0b54e57aef00d9d4e81115576b4ab3a86cdc3653a3efe7dcb7fa650f176bd557b02b03cc139e9a3221cf7d3a7c2150bdbfb3c879d67e2460b69fec40a0e42ed5c0e359f6f91bebb6c506371b7338587e3d0feae6f7ce555e74da6e76302e62bbcac25d8509f3bda57e323ef7b166f1d2b391d2bb6860efdac1b809b9250000000909207e364faa20d0a1115a269393f9d98152e0019ed33b3c7156d0ef9113be7138f900c4d72e379426bde9b98e1aedc8aeab18ea9e756fa4eac2908038f003435e987d22132cadfaa9e430e452d78032e82a7ed64815063d08b4274c7cfac1a9520d10ff8140565f5986c9c2a135afee4f4d4bf19b1904acb3318d720584e3936de56aca310dd26b714f0a7dec1939b040000012800000090781ae925b7e0ebd9cb87e718b7c7ffeae45651552404fffdbc1df7d85686dd227cb4c1de22650479d3bc359ec4f9e81c79da28757035088b0ba2d1f7b2a321d1abcd3a4bb8b9010906dc7450b8d012dbee1d41e5314a7d094f797425ddfafc8728c6422c58805c0f9d698be9fc320ded25d0466880988f2dad98e0256fa89c288d8e99569f588cdab93ccf67cfab691a0000009092aa76893b5cf1b10cecea31187de1b6190aca3c4941659f077cd00ab9946f3192a2e9cff6a743b51d2217dee81a68541ce18b321fc30d4f5017f866dbab792dd00cd676ef3ac107b0e02420172a92d9f4b252a6cc4dfd4e6d506d1cdfac701ba017d16f692702e2d960c0c7e27794d30aced94c9661109af94d2381decc99211e8bc4dd401c6f2e197ef3057930655d000001280000009069825afeae91c9a0e5db75e73f9d1a1a24ff8398a6b8fce60791b611953a12eef7f0bdd08847bf4d7041aef2a144d2038aa8fbb78fd51a745b6967293dafdaa4f46cd6d0d06d53801cb9cd95c192c96183603c45c304a3332353411d8efd1f79a974f8993fe4e283975e9eef3b867cb60995a74b83383b688c102a4e0d78c6af78ed45a1f028bea71914d9d57c7ae79300000090fd9decd929d5172e46f45ba17fa6c49e4d265fb231e26df16e3f9a1baec1bd6c76a304217741ee8e638dc21c2a019d5d0cba632e13ddfdc7bfc615fde3895aec4ca4ab22291f5dcfb88f27b5d739d549d08d0db6f8fd27a095b6ab9d11728ece355a764e06f0822927716e589ec35d12123b316f1849deb6a9581502a2abd08d4a37b76400c65358d30cf4c4baa3a1e500000128000000902106ead6df33bd10b164d22be5509b1e0afdc774f1e1ff78ae3937c49c8a58c59c89ab7a254fdcc2260f641da11954b053d1869f8aff87c4ca2efb626e1a7f84c10533c1e65ddcf7e7cff35e1c3cd6e696317a1a37783a13cff580b2c614d797a03392c98f19bffa927dbb45de09a3dc25adf76acf2a041e253eef08fac1cdbf8e603383166b7a774f7175070e6c6a600000009072a7e284d2e397b224c4b8f8a20a52403abb3b28a8b788e4a091090c0b6fcbc1fb3539ad4458307722f696580048c4a492d201aab14dbd1af074d002858c522d195ee0bd0786c834a6f6445b476df280c5bea5d01e6369bc12cc2c3ac6e697de844671056cd7263f5604a835aadb448f79300cf927246b8b5220341fa78a6f3dbcbac09550a6ce546131822cad0621810000012800000090dd4294cd8f8c449ad02c6ea497fa35bb7111cccf47686d0b90d118145c1e04dcde092cdf362d408d95ef8925c9dde1ded107c16f4ac9ff46d39d96da2d7ac35e2b3e70583c3cfd6c34c9a9f5ae4a437b49510397a419f5e546ba3456763fdd8252ad584ffdbd5fd4ffda3adac48b8375255def1f7131eff0617799ce406733579c856618ad0db4b4523970c75e95de9100000090af2fd32856e57805ca74674c9d8e6147df5fd4e9367b7d43948d593fd825e10a09ec6066c96ed49ba88d680d7d2a8fe6a7d5518d3fed621fd71f37fb8ee851356ebf4d7efc2905693ce37641397880ffddb16bddd170b29a062e42b76b54171ad1b92c16dd50770cf954905e90a194c4bbbc580a13b432ba581a8456ebb371d337efd1b2f24c2812d51558c88adede8100000128000000905807262584c7578162ce616409b887dd2c861b7cc4e8f19853c008bbd4acaf0f19db1e572398ececfdef22aec0ae7030e7247fe8451984233c12b61b4afaf5804551d46100937b25b7023e5ce39a4f1d0babd330384e38030c2757abf5a7ec092c26349e1d54b83a6c0263a441e24090806168a061b708136f54a949598359283853f4c3c4abead7f6985d4fc393677b00000090ee85daf522efbc2636c7ce5c2a0ec0c99e3e905b753c34d5e6c5db2ff50c82c5aa57de538c88b78bce4c2c1b3f9a412aeaccc8a243694452962647fd3c8a0d53a2eec14ef97e1e224894d3e6db522850ac5c55d0b244bb4aea84143426ba6bfa4f5572a1ba7ba91f34e28bfe68107e34a552f3676c53b34e609675533fcc293d6e6e56ca9648f614cee0c52cbf6e03f900000ce4000001280000009008d66dd316e03c11f2f6f80d3970dc8c516fa76840e4074f4e19e0b95b59a0aebc11492effcdb0c820647a729c67ed95bf500412059c80ea48d48a26705115e659b893ef589d37268fac8809ce28919a4be38cc9e1f564ae77258a4147de79ead0d27dd159679f0f795b096e133eaa2bfff9900462c766b12b9d727c9f1981b4cbe1df4ca5da89bd4283dc4589a0642000000090c47110c0f4fae3f396a2b362bcf4e3c8a9d65fe0a21cb68d3841654a594561c12bfea7e3be27ca5a2ec93fdcff6258dc8215fed3305818baa19067acb03fccb46650250b15fd18a23f4cc1e3e62becb3df759030f92493baabc546feddb86fdea8f42749f994cefef3662465290dab5e53614405c899e27ee60b884823aa06daf2c18ffc69777040fccad493d1e5c84200000128000000904cfd8f43502458ab8ea4b7ed39a2768cd125681210de2ef0cefa30eee2c408642821bf9b19085330d22b43763c3b815dea6fe6396d3c8beaa80a795eb0ffa71e5af496632d65ef83ef4cc14288d20dd1000f6b024b26f5ed3006c6b1eeb67a3049b36fec9c76dd973745bcfe3bb6f37ecb6d08f698cac4da7ce4c781903e3b4e0fc3f3d15000e364adddcd15eaf961f2000000903efe093939d9ff98a01a5e8fd0ab75ee6476d77e279bee266831f6b15061278e9486e5d7d5c627969845f5344607a2eb666a0fbf8de1b24d1fdbd98287c037efa5877e20a4a53163a0c86f6603fb139118a93676525e98a105cc6b1e19ad925d9e131360a74aae10b31104f823e74ca6b16d485bcc131ac037aaba2b972fd445d1cad14efd641dd41a483236239c3cf80000012800000090604771ddf429cf224d4356e7446ec9cd85463670428be3e71568c06f6a9bbfeb9312f5b9cd803c9d36b9992f142a23b56c1ccd0f72b42a1bdc733ea0aa9d71531bffa31ffd6f0a2bd62155531c9ff88b9335846f76052c80bbf28fa854f8739d30e5eb965cc76d52577eed0aacdf17b49692e419cb2b3caaec46db1139e4c970244b030dcb61055d7b7db90bede37c0b0000009042e6ab0a6d746538d1bb5ad5594c60b28d89daa57b2b77c9a40090f69cfead34eccd04efd05d612586841b266c692d2f383a743f8a0ea860ed8129e7a2bfd916290021fc80fdc8c701ecab322cd98b1a1d0446d553da699ba8e672e90fad07ada6acf10d12653745581dea923b1d86b970966fa1d364890acffac86956efc5b30a11cb0f44bca296014e9a33af4ea5690000012800000090a7a6e87fd0cdb332a67c397b738c80deb4e3ff72cd7a1b3aabb891ffb5ce3d25f74e8b75816ba2b1ac000ec3034bc8da4b598d635d8f54d04c595d216b6e037f053d43233da9cf6f672ff6ffc6f6b729d6b0aac4a5ec4d5f847a717e75d027ed0dd660e502258408a639519fced9a1bc9699643f8b52582738c9243537d0945381c416af9d6d2e773add87b4942bb9460000009047e32fe86a0742d9473b758910c78e49372efe69852d111dbbc7da54b9bcf522087c4ee5e7396f2b4702bb5379c21c5a9400b7ddd1d40ee77c9ab05898fcbcf4ea65288f1b73c45267bbbde0540e2ad4af121924eefe85a3d54cabc7b10fb63b9fe3c429b75c9989e59f033df3e064b6c6237779303140bdfcf25653fe92348516f2651d6d0bb18faeea85b94bb660b9000001280000009078b9e99817350a9491dc6867f0cda5fdd9b39d1fe0a9ed58548978cfcc637957ab82784d3b2c30829c7edd6118bdf0a877635660a1d183a010d31390839af04587346dde9980e5b824a71f4e4148012d089842e4e59d5d9a89d6d78e7ec0e2513e6322b0977e3cd7b5f08d5d18cdcbf5dbcde57b87768a860cd76613fe40da8efc0618c34c12e409626b9c577fc00e4b00000090487671868ac16596ec7de56e973381703fe43929e74ff073e9c963aa22bda9d6f1a04e093a379e586f3d76954e318b6df1a823897ee5e4d7c5063597e130a81eeb4c9535a227c45974e78da48e0f7026f1e689ade61971444a449995919cc7431fc9e900129866c3a2ab7174f72cc8ed74b91e6e4c025f693045259f8c9e4cb1d32504c38443236025c37c4c7c0a5adb0000012800000090e734aaa308d6b54f9d7a52fbe20503bf80c73d593365fece0bf1aaaabbe87770833e54bf425e71ffe12ecbda6e9e1df258f94541f0d7f94fddd506653cf122f7c5386c659dadcdb6e6e92bdf9824aa69f775d39caf5b99b73226cbcbd95b82d070c2400fdbf0996937e67a5c513c3946e667fba983561b48a931e3cf3f68254e4f2fd86034fee3abcd82c97ecf88348700000090b96d8f7757738f0f7f58de967313433e3fe1733bf4d5c15a2078690187a1acde17ebc915b23cbc6dcf74219e3cd63362fa003391f19a3a92bf26390d441c1a1c69809270fc9d61da00d0695dbf73d67f37050d622c773829e929b8285955e82f16361fbbe9113658235b9afd0b7a784781b5bc6251126453aa973943410f16a85910376f0b609292e9b9e46104054f5f00000128000000904282cb9ca7cec0bea85b1a8e83379b5365bc8a843a3d79afe1e9d5dfe92184920e375d084c5c03d3d27d4aa4f142ccf6c89ceffaeb3068745e2c9dddebd6ce7dad36b0e76ae97feace5939660ad9dd79f8d75fbcb740a2254c39b9bf2787517cfb2cb48a0e26228f085e85dd15b7e873058334594d9fbb8e877ee498fc11ad0e430e3be518bc9e0c1afb4ad652ed2f9a000000909824f3e20d39014fe1ce0c25d27af4d1fc16aede6aa127d241ab74b62aeeff33691377f976b31216fe4d36161da0f8c7549047c9dfde650a5c9ae9a5357fb15c3e7dbe296ea10d76b46612bafe7824410bb297eceb346111a42b36663015e421a976697df83943d2365bf559b7406e147403547f78ac7b8fbc797275800eb6d46078e862c501eaebc40f16c837b4bba80000012800000090d78151e7a08ad4e11b8a2fb201f83ae713fdac255819cb3c024620025484b20fc3748b713279b0dd26b37b2e38933ea7039534b4e0f5974a4f96ab01d8181dfc988b9f5f495bac0a6ae67df7053157249f7baaf0c91a284db4d1d4345602134382388b5b4a3449214fed2956b221526e2e0dd60320449b4d725af164b212b69b8e0c4b7089c3a030407b9e861ef132c200000090a0539b668cca6c01fe2ed23f6f2d5df8145a48af96d7dd3dbfe6e675af044114c69c44ad4f150b889cbfba7eea026e9ea0f599c4d035d7b709ece6ad5988040a4d51ab2029d9cd88e4b791fdd0cbb6ac36fb943ad0b80e6b2bf4ece885b1048dd8d9b1524f44b75ef82d3fef0826c5d043b2fcf253758cf5e372a5b87d1cb94eb4cbabb547a28d3b8ee124ca5581bb9c000001280000009077ac86a4406764a86f704ff7139ee1f7a2f7e10253ea15f544502be3dd4eb0f4fc2a75653bb060ccc4d03c442f13361ab492775ea71761e90a7113ba55e3d5a10bf43f23fbce60e453aa76ef098b9c93560cf002bf2a52040f12a1b54cfb0c1e47384e91a05d774f558c47a01508e1b0b102ec96c16c2be6ea6d06c8fa1b29aecd8beff997fc4f0ea947c41be6dc7afb00000090be51c1520c12abb9c70648e88aebd75f67f72da3b12e7450a780ea1a8e3082b5bbe7db2ddea227fdd56d3312a3e440f3c1de5d7a1cbd17ed1e71b263fb50e6722c48d5005df3a9fc8b524c64a2de0cbba8dd04fec097af10540a193e0ceb30380c1e127931d154f19310644472722de34551b100eabb2146354debd5dc72f4dda786b3efc42fa91daa612f4986ca4733000001280000009005f1417483ec00421bd576190ca8d530a8b0ebca2abb3995897ba2fe24320056312adc6d898c0c8dcabcae7aecae0970e5640b9664479948de28fa79ca53c232044f5e97331d53dc4c177cc5df9bb46b9a9752b3846de4a72524ee262fbc12f2b25b57ea1da2d1b05ef5a250af84f5f1fdaf2157ec8dad2ed3bc1e5169fd9866be39bb91961bda0fd7fa1ec3e9b08bb4000000907f8517ea4d3422fc85946ad1e31e8f25d2a2a1374ec8b76917efe37eae76771c416cea99423ffac5ee56772105b8203db836ae6c5c33f8ccf371668f516eafc891e4ce29e6c055b473c27330e9e40adedc722c043e9aa74d64d98ce7e363fe2c36eafd9f92add125e075bcf6464d4d3cf35d335a0a70f07ee53e736d282004f45879f9015f0da7a1ad200a3eef7ba0c60000012800000090eaba354a29c93d1f132a1e369079a6db3ba8387cf8f02e36355b5b0997eff35d167ec7c07a7b20013d7665632ae9f5ae2e46671dc912ddfbe3e0b5c7c1db56496f3d464b7a741e764142cda0e2d2d5809c9c4ff4a095cfcf5e8f6b6b52aebf94e2454a7041aa434739b7c98e937cc62877e7ac129f07ca626e71a126880beddd01506d8c7d71b3d35679565eebad27c6000000903129008169633e4de7fc916e6dc182da1d8748aa8b736120f9498c842ef44a3a0540f78e2f5a0c817f38fdde511d5830a0bc185fb760d3581c127038546032768c0ca4d57821496f147047aa7a401171a4bfe3475c8dee1ae60d6752044946ab8181430484b0bf8537e17ec9856129776fb730cd06818524d3d96f8c8c0625b7e51e86f1308adff7423443ff0853ff3b'; + + - bytes internal block_mixed_1 = - hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d000000200668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e15000000002e04e54c3675ba6bd68f104ce19d391c57488f31736639dee94d707989843f110000000119c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb671000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb0668938c4a4167faa2b5031e427d74d6e38638d2eef68834b70480c5a93f8e150000000019c36f7bc2e4116d082865cc0b4ac8e16e9efa00ace9fb2222dd1dfd719cb67100000001242440bb6a4cba1d719e5fffa6d5fbcc0bd922ec70f00da8f6e1e23aaedbb88a0000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000601578dee3629aa301b877887a478484ab676934bd9f8228be7c5cdb5873f97558000000040144f7bcbcded272bdd50475ae0e017d487e184e66630b29968b31214eb45f2d00000002091367641fbcfd08d2b16d6ec75bb365bd807a436fce9163516a1de3532e8de3000000022d9b8d2353587ca56bdf967b4bb8847af3671bd6901e9e28f82c240c6e33129a1b3ab03f9b9fb0f8a31ed10a930e476c7b8bfcc9018d6dfbe20eb15838a701e9000000103036ed03e75f4893197d647af9e8f5dae3659ac9003c6b144dbb86b71820307400000002000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d00000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000e1000000380000001bc00000090f21fa38445a09b3855af8539b818332b0cef11e3e6ddae06267dcf1953f526969a4b3089d62ae012e3ea2f135de7ed894e39715824002fb1bbf2e219758fd7a29e39ee77d412544315ad059f91c50ba6b6089aff12ef4f081f6ea81450f35437bf47970969a9e6996190fe130c21a1105e9cb2140869cb36022ffd737122d3e34fcb7b264d366a1eaef3bdf7301f16c7000000901050ee850e5b7e4852b04d14378b9e62a2d01ea2cde9d54ce58c3c8796112adb7893cf9e1c88cdd05a45b3d4eaa2d56aa47bb3045311c2e3ba90ca91c140e2adbf6aab51ac52c108c89cccdca5e96bf1d1fb64f70f76dd0ffb5a80eb5fbb0ec0e3c211d880eb0e58f28e7bcbe3fbacd2e40cad2e12f94a88bc215ce56e5942982b1eef9fd695d2ed2cb896894746e86500000090e46d0d6a97d4b7aad44eeb433974ebb8744db1403649c48f7fd051659a9150ceebc7cfd002a65d2576adf0f47390490281bc30e6772141ebcde7278d9c22ad4a6019445580e35b37b2b4c9f18de59dcc69cf9b48a12f147db3fb9839faae8945248527910be911d9c947a9ddc15da3422950f2553a929ef8810be79f316fc46fa2b4a7732e8f53139086f235155bf21b000001bc00000090eddfd2b61a0f2f5a8c058e5de37fe557f352626d31f20971f0e4abeffd339f07292965b240e4180d7324b31f38338136992070391d027bfcdbfd2500ea48f01c4118cb4c0343ee94b79b1bec82fa9a13c1699d9082042e4ca0cce04bb919afaa3380ad7966aa1fc23a4f8fb379537e5823b43379179632b9578f5f8b4b5a8623c1e0a3ea73680413544550faa20e7467000000907efd26757319985f114ae6c93a96b01d3094458cfc94a1abf63a107ee6de54e8a6a582fd177dbdd6289fd5835c2ad25dd36f9ecd7ec7b81d889050c65e3c934948f81480f7ec4e192fa8fc67b5761c61c7f815028fa6aaa089d31aab9d97fb006abe28afd6c30ff01e78d6a37945cd7b55d6fa4f8c38c41789fae8a2f7000dc1a76bb40851c75518436572239186a60d0000009061ea102e02927ac017a5350527462d5f0801130753e5eee35b0040fe0a38d418ae55f5a8f12ae578d88b58b3993c7767a98cd280d606dd8d792e3ce69be001c277fd81342937dd728ffa0dcd4ed1e20669582a436fe61e8c4d2189d383bda18d03a56280d96814539d5b541c0c6bee120f1f3d0930305768f99408642ae924068d5023cb9d630be52a6c99ff49a6f56c00000380000001bc000000908d89dd62f1a9e8efeeffb5783d79925676208dbb2da5fc9d763eb6dc55ff53788132e6dd1ddc3620fbc6b112010e705071c7938fa0776053a51b9806dc6b4bbb78685fe1b6a9d71989b9b5c9fcaaf353eb8e0b7f5355585f881f14797a97dd70b6a9dfaaeecc5237a1cd72c999355702f9fcfe47ca4390976f55c47d4c7896836ac4967b7edd9a29683c0746a434a71a00000090f87eb5f7213825c5302ca14fd08cdb888a7305a2b89f99d91d70650e8c28e97dbda23cf38603440434f7a12deb50d1504b4ec95543e346c191c64a401f94ddc56aaf71a0d890a923214f8407c236aafd5e338b9bd8d9a816e2d1a15096a99c3033e7af3518810f37f48b8181395cdd9fed563036d3d0f6c2bdfaa782ec4d47d32d469d6792c024afed5855985670308200000090e303a876f0ede03a95d81028cf9d0d6e1adffe1794bc47b8def60ac28e649bedd1134cf9477a8fc678af5350342bd1717a610f843d9faa13e20d78a8ee5beca0f8d2ff84ea1bda582d8f738e09814150404cbcf8271918994bb95f8add7308ea474555d85305adfd7db53140c36ee34c9515b46c28b817baaf26415b2578d6a52f2f817a1c8b1181c3c6cba8058a3cbc000001bc00000090fff0205387dc89eb6266969c890aacc8a8d59999b8987bae7a2bf7fe973a5aae5603a966be5ed08a6a5c3db164a3104cbdc4a19b018ecf599e0169d89ed23e1c344acef85021215ca0c1c13bc06b880ee6583999abe9f46b8833c2acde156cbc0509ce46e0f73d3109da346c48d1ddd578a7a7d309ee3b99e48decdd6b4f4be1d1f230fe29e769b7aa2948b8fe98eef800000090c449ea62e5cd6c02fe0fb57a42872087a2b68e0108e34f4e833a736c97f7047987aca10af787769db659c6461e75f332aa435b24d762e60a584db62dccb4fd1a01beb1b41b9de47c503b4638e7463be159cb774ce98fbf40e859d850e25561516968c57aa0765298dcf7ba7a57303f5c03504f3eeeaba538c2793e17f77d309d65fd150c703b050abaf6dbed43072dd300000090828e250313368bdf9c5d09d7264ebd64d64441ee6b563fabe80dad3c89716ff2096bf4ad372920f3505770f7f4acfaab7c5e66d9e0faee355c673ddad1f6976aa1cad2487c514f2ec06d8b3acfd7ddaef64e7a6a981148448793b9fb1d5d796ccc214c98a2d32291458d4236302e210bc03dbc85e4b64d66649afd0a23f0261b8e68341926a5aadea633e438d16ec32100000380000001bc000000904eacb6cb59c1a33adf2690038cf379d466d1b32961adc7601071a0767b71ecf7b90d9aa6aaf6d839b5d26754723c6aec83daed2bb792334ef264e7c540599732048cdd0a761f6b22ae86a2415a7eb833f26aee9cf4398df43b108125361467c1ae23a67e2a5ece87c76027d27a9db961718aff7e79c3eab3be5b72aada786756708914685359d46810d18b160cb40b8c00000090a4e27900119abdfcc87f9568c372ded71ff1ff4ffb4d57118a5831c5307bc3b38e613b939db6b0b62e5a36778768668fad6e8b6286f942bd89a19119524379ba7ddfa9d8a4e1875143d9efe84f33c42a08619e98067e5703c4917d66f57b3ab5919e4beda65707dae2ce67e3aa728ec06c4a282b77766c70438ef2cb0ab185f75a987ab12472ba789cad84aa5a84b347000000903f4087602a05e0271233a89a7250d639b556a58e976eb72fb7c4202aeb0c8da66dad81d098d9b3dd103371409aef5916af78d4f764417c743eae2a647e97cac0b3f5ce2721f965f84fc353606a3a0e9a8d58bb2655128d4409c19a4ecfe16e19161ae6519c22ca0c7e3a45449296869e2c8e3753d337527bafeef204e979f83b41737dfe7e4dad8236099043a50a68e3000001bc0000009048aa18b754fc1544d35051fa4c61bf0bd94801f44dd426b747577082666c2966733e1edd7b7ef9568a32bd695d4b1e5b4b79fc31af9792ce914547eca11d2e07a4bc3fc26b7c12bb40d1b6ae78e48c597775c3318b0173ee168e4b63c72873363f303e7c254826239f569f6dcb8ca20dbc4484e66ce4beb5cde45c3c2c8acd930d35b1b1995b3fabd1c553607b4a0b3e00000090694ecb347804cfe4fd7270b20e2127e17e84ad8be47634623f40aff39276a33f290727156c37b97537f5a584f94fdc26a1b442e69510ded48756893f6c440658126cd4dcf0b8c5ebbd5f5b37000eaad205058a941f28f1340c4b4396db48972a2b768cd5ffbe3c3222b70f068bf70a30ecced926a2a6e552abff8bf3ece2af2aafbe4fe1de64853f1a84edf2bb5875460000009034a5d72f382f83769f48b44e7e3afb47d4c21aaec2e2b1ef6bd12ee8d623ae284678462241026016f43e4720a8d4a63e46b19c323b3e2434f83dbcae72d7f798e57832ec4975ed563b3a9fe34f77cbb70e78153878fb33e40ee5cd8b8ca2bd26f2762cb81d2242263df384f882b63bc0e8f7c673db86220628ad0f8bdd3f00e879ee0036349a1731c471945aa00c6af100000380000001bc00000090ef0f4d6a0057d777cebc56c808a6c3a50c70737b0735fbe33fdc004bea7cdd82d5b9e70c73b07dcf2027f01da3d86314fe58ed5955d1208b1425cdbf2f8cd9a0e7006f2ae02bc2f443ab75f8ba99fe7df8e48d9c30dc8f65fc1632d3c482783fc3f67261ac2213c23203f2053cec1d065ecdd1820daf446b9a8ff8be4bb8f94ca9b819585b149fd63fb50654fbe6bdc500000090074c924696ee8b9a02f205017a468b9272d911c86f62f961aad7ae468d8c371738dc8b31b927d53d9b036756bd6b2dadd074bb1441e02ee31ec78e429a84eafd2e86d8a6ab9c1bdeca68c3deb5dbc2f1226b627d7f174408206e7de1be9ce968628bbed166994e971e000fa55c9242e33a0c85b640fbf83a382b04945eb2808d6ff3a4767b9cd725f663471e85f8559900000090ea019a9677bc4489c290f36debb0c9939c845e6a6a1e317d00691d1aca708aa502b4d1ba67e802afd147570d4778be6395987cbb5db7e77fc74bc2f9fbf409417bc87e451a379b2b41107f53583b5f0a3c25aa772dce2b2615be7cce8bfbbecdf4790067de830ed6564f0ce855c56fe9066d7e77153a434ccc5f006b3b31fecd05bbbac2405af45808d528ea76e54567000001bc000000904970a7f50be3526216d3e6283ae0870cf3cd97f26d930cb6fe9a1803967053521c790105652c0f1d0a55f613318f8ed4ef5e7fc2c194f23b36524f3296a18cf6cff846bac6b50dfb14d1c1e39a590429bb85032cb107b060033ca0ae44afa299f304ed77af63d3d6efb4a6eb61acec8d408be7c844c1264362e05ad4f50fce9b23f22ab5ae96aa9c6f18c0faebe5691c00000090429644fd52c43f5b88410a2eab1c88c2f2d334e515d8d46e61ce1dd39fadf652d41ae8be999eada275d856672e1dcaf9a9c6cd61e8e18bd01804dc64bbc0b657d4635df57cc7f86273802804d1bf84166dc2a4266b4a2d389d98348708a952e34ba252d868072931472ea364e82cdcf281990da7aae85ae12de35d1ff0b7ee88f59b04d42ce42831bff0fbd23f55dfc2000000907c078d86f8d38b15dadb22cd5688119141b32934361d94d337334d5913bad13b253144d7e9dd81f4c1df9ed8afeabae972873f1de62d8cd8f0c8d20205a2209005a477906d5cf282bdf0a631cacc93396df37edc1c211576922eda972bec75d1a9bf5ca4c823ee5ff3f39a60ae1cb06479f2470ff6764749adcbf43a057d8f82730871fb33601a637c7aa9215912cdd3000000400000000c0000000000000000000000000000000c0000000000000000000000000000000c0000000000000000000000000000000c000000000000000000000000"; function setUp() public virtual { helper = new DecoderHelper(); @@ -68,17 +69,17 @@ contract DecoderTest is Test { assertEq(l2BlockNumber, 1, "Invalid block number"); assertEq( startStateHash, - 0x24478b1db4779386486486617b4f4782d6944eb577f5f36048dc1df6e1a954ce, + 0xee92c70197159de635a227de74fcfd5fcf36ad07fca32b16f1714bf390bb461c, "Invalid start state hash" ); assertEq( endStateHash, - 0x9efc32b00d21e5f939c25063208804ec35049a7cbc007d4853d3d6763eeef358, + 0x173011f69ad87076762a588bdaf7cccc9e5dccf2aed60b70b62773db03b64348, "Invalid end state hash" ); assertEq( publicInputsHash, - 0x0485d38c108a89400e87936d3f29484bfd067857c3118c6dd75d8ce8bec558cf, + 0x121bff9d33e9dee94e5ea8d536d8e6aeca5c899711db653eda48ddc7284984d0, "Invalid public input hash" ); @@ -106,7 +107,7 @@ contract DecoderTest is Test { assertEq(l2BlockNumber, 1, "Invalid block number"); assertEq( diffRoot, - 0x68b62af526714af2f997d81e479990d40db54853a52e88521033581c73963580, + 0x77fb0c04b4d4a7cf3a680d5d6caef1c7f9d91e1c4d46220b22d20fa633f3e14c, "Invalid diff root/calldata hash" ); assertEq( @@ -116,17 +117,17 @@ contract DecoderTest is Test { ); assertEq( startStateHash, - 0x24478b1db4779386486486617b4f4782d6944eb577f5f36048dc1df6e1a954ce, + 0xee92c70197159de635a227de74fcfd5fcf36ad07fca32b16f1714bf390bb461c, "Invalid start state hash" ); assertEq( endStateHash, - 0xa5ffcd9610b1aec5f5c13c6fd4c289c976f18ebd0f03d09d4428749522115780, + 0x71b79f5d82c94fe5dbf89e5fa219e4338191bc35b10127a56e3ef49c467ba207, "Invalid end state hash" ); assertEq( publicInputsHash, - 0x0d7f318632079607ef72211a10718cd460ed7d86939b7f94eda460a849d94ce7, + 0x097fdc3b87eec47728e91f71cc57919387eaa7c3c2aae57bc88279e8c372bc90, "Invalid public input hash" ); diff --git a/l1-contracts/test/DecoderHelper.sol b/l1-contracts/test/DecoderHelper.sol index 18dd4be77bf..57063ee13de 100644 --- a/l1-contracts/test/DecoderHelper.sol +++ b/l1-contracts/test/DecoderHelper.sol @@ -8,7 +8,7 @@ import {Rollup} from "@aztec/core/Rollup.sol"; contract DecoderHelper { function decode(bytes calldata _l2Block) external - pure + view returns (uint256, bytes32, bytes32, bytes32, bytes32[] memory, bytes32[] memory) { return Decoder.decode(_l2Block); @@ -16,7 +16,7 @@ contract DecoderHelper { function computeDiffRootAndMessagesHash(bytes calldata _l2Block) external - pure + view returns (bytes32, bytes32) { (bytes32 diffRoot, bytes32 l1ToL2MessagesHash,,) = Decoder.computeConsumables(_l2Block); @@ -25,7 +25,7 @@ contract DecoderHelper { function computeKernelLogsHash(bytes calldata _kernelLogs) external - pure + view returns (bytes32, uint256) { (bytes32 logsHash, uint256 offset) = Decoder.computeKernelLogsHash(0, _kernelLogs); diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 05f30bf468d..8d2ce242729 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -19,104 +19,104 @@ import {Rollup} from "@aztec/core/Rollup.sol"; * Main use of these test is shorter cycles when updating the decoder contract. */ contract RollupTest is DecoderTest { - function testEmptyBlock() public override(DecoderTest) { - (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = - helper.decode(block_empty_1); - - vm.record(); - rollup.process(bytes(""), block_empty_1); - - (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); - (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); - - assertEq(inboxWrites.length, 0, "Invalid inbox writes"); - assertEq(outboxWrites.length, 0, "Invalid outbox writes"); - - for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { - assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); - assertFalse(outbox.contains(l2ToL1Msgs[i]), "msg in outbox"); - } - for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); - assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg in inbox"); - } - - assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); - } - - function testRevertInvalidChainId() public { - bytes memory block_ = block_empty_1; - assembly { - mstore(add(block_, 0x20), 0x420) - } - - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337)); - rollup.process(bytes(""), block_); - } - - function testRevertInvalidVersion() public { - bytes memory block_ = block_empty_1; - assembly { - mstore(add(block_, 0x40), 0x420) - } - - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1)); - rollup.process(bytes(""), block_); - } - - function testRevertTimestampInFuture() public { - bytes memory block_ = block_empty_1; - - uint256 ts = block.timestamp + 1; - assembly { - mstore(add(block_, 0x80), ts) - } - - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector)); - rollup.process(bytes(""), block_); - } - - function testRevertTimestampTooOld() public { - bytes memory block_ = block_empty_1; - - // Overwrite in the rollup contract - vm.store(address(rollup), bytes32(uint256(1)), bytes32(uint256(block.timestamp))); - - vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector)); - rollup.process(bytes(""), block_); - } - - function testMixBlock() public override(DecoderTest) { - (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = - helper.decode(block_mixed_1); - - bytes32[] memory expectedL1ToL2Msgs = _populateInbox(); - - for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox"); - } - - vm.record(); - rollup.process(bytes(""), block_mixed_1); - - (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); - (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); - - assertEq(inboxWrites.length, 16, "Invalid inbox writes"); - assertEq(outboxWrites.length, 8, "Invalid outbox writes"); - - for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { - // recreate the value generated by `integration_l1_publisher.test.ts`. - bytes32 expectedValue = bytes32(uint256(0x300 + 32 * (1 + i / 2) + i % 2)); - assertEq(l2ToL1Msgs[i], expectedValue, "Invalid l2ToL1Msgs"); - assertTrue(outbox.contains(l2ToL1Msgs[i]), "msg not in outbox"); - } - - for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - assertEq(l1ToL2Msgs[i], expectedL1ToL2Msgs[i], "Invalid l1ToL2Msgs"); - assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed"); - } - - assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); - } + // function testEmptyBlock() public override(DecoderTest) { + // (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + // helper.decode(block_empty_1); + + // vm.record(); + // rollup.process(bytes(""), block_empty_1); + + // (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + // (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + // assertEq(inboxWrites.length, 0, "Invalid inbox writes"); + // assertEq(outboxWrites.length, 0, "Invalid outbox writes"); + + // for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + // assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); + // assertFalse(outbox.contains(l2ToL1Msgs[i]), "msg in outbox"); + // } + // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + // assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); + // assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg in inbox"); + // } + + // assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + // } + + // function testRevertInvalidChainId() public { + // bytes memory block_ = block_empty_1; + // assembly { + // mstore(add(block_, 0x20), 0x420) + // } + + // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337)); + // rollup.process(bytes(""), block_); + // } + + // function testRevertInvalidVersion() public { + // bytes memory block_ = block_empty_1; + // assembly { + // mstore(add(block_, 0x40), 0x420) + // } + + // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1)); + // rollup.process(bytes(""), block_); + // } + + // function testRevertTimestampInFuture() public { + // bytes memory block_ = block_empty_1; + + // uint256 ts = block.timestamp + 1; + // assembly { + // mstore(add(block_, 0x80), ts) + // } + + // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector)); + // rollup.process(bytes(""), block_); + // } + + // function testRevertTimestampTooOld() public { + // bytes memory block_ = block_empty_1; + + // // Overwrite in the rollup contract + // vm.store(address(rollup), bytes32(uint256(1)), bytes32(uint256(block.timestamp))); + + // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector)); + // rollup.process(bytes(""), block_); + // } + + // function testMixBlock() public override(DecoderTest) { + // (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + // helper.decode(block_mixed_1); + + // bytes32[] memory expectedL1ToL2Msgs = _populateInbox(); + + // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + // assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox"); + // } + + // vm.record(); + // rollup.process(bytes(""), block_mixed_1); + + // (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + // (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + // assertEq(inboxWrites.length, 16, "Invalid inbox writes"); + // assertEq(outboxWrites.length, 8, "Invalid outbox writes"); + + // for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + // // recreate the value generated by `integration_l1_publisher.test.ts`. + // bytes32 expectedValue = bytes32(uint256(0x300 + 32 * (1 + i / 2) + i % 2)); + // assertEq(l2ToL1Msgs[i], expectedValue, "Invalid l2ToL1Msgs"); + // assertTrue(outbox.contains(l2ToL1Msgs[i]), "msg not in outbox"); + // } + + // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + // assertEq(l1ToL2Msgs[i], expectedL1ToL2Msgs[i], "Invalid l1ToL2Msgs"); + // assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed"); + // } + + // assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + // } } diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index e2651f4fa1b..a7b13312d84 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -59,7 +59,7 @@ const logger = createDebugLogger('aztec:integration_l1_publisher'); const config = getConfigEnvVars(); -const numberOfConsecutiveBlocks = 2; +const numberOfConsecutiveBlocks = 1; describe('L1Publisher integration', () => { let publicClient: PublicClient; @@ -287,14 +287,14 @@ describe('L1Publisher integration', () => { expect(await outbox.read.contains([block.newL2ToL1Msgs[j].toString(true)])).toBeFalsy(); } - /*// Useful for sol tests block generation - const encoded = block.encode(); + // Useful for sol tests block generation + /* const encoded = block.encode(); console.log(`Size (${encoded.length}): ${encoded.toString('hex')}`); console.log(`calldata hash: 0x${block.getCalldataHash().toString('hex')}`); console.log(`l1 to l2 message hash: 0x${block.getL1ToL2MessagesHash().toString('hex')}`); console.log(`start state hash: 0x${block.getStartStateHash().toString('hex')}`); console.log(`end state hash: 0x${block.getEndStateHash().toString('hex')}`); - console.log(`public inputs hash: 0x${block.getPublicInputsHash().toBuffer().toString('hex')}`);*/ + console.log(`public inputs hash: 0x${block.getPublicInputsHash().toBuffer().toString('hex')}`); */ await publisher.processL2Block(block); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index d2ada0b618d..346f9c8b006 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -240,6 +240,8 @@ describe('sequencer/solo_block_builder', () => { startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: rootRollupOutput.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: rootRollupOutput.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + startHistoricBlocksTreeSnapshot: rootRollupOutput.startHistoricBlocksTreeSnapshot, + endHistoricBlocksTreeSnapshot: rootRollupOutput.endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, newContracts, diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index d36d378e8bd..310846ee0b6 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -92,7 +92,7 @@ export class SoloBlockBuilder implements BlockBuilder { startTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - // startHistoricBlocksTreeSnapshot, + startHistoricBlocksTreeSnapshot, ] = await Promise.all( [ MerkleTreeId.PRIVATE_DATA_TREE, @@ -122,7 +122,7 @@ export class SoloBlockBuilder implements BlockBuilder { endTreeOfHistoricContractTreeRootsSnapshot, endL1ToL2MessageTreeSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - // endHistoricBlocksTreeSnapshot + endHistoricBlocksTreeSnapshot } = circuitsOutput; // Collect all new nullifiers, commitments, and contracts from all txs in this block @@ -169,6 +169,8 @@ export class SoloBlockBuilder implements BlockBuilder { endL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + startHistoricBlocksTreeSnapshot, + endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, newL2ToL1Msgs, diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index b3fd3333ff8..1f89bb16097 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -86,6 +86,10 @@ export class L2Block { * The tree snapshot of the historic L2 message tree roots at the start of the rollup. */ public startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, + /** + * The tree snapshot of the historic blocks tree at the start of the rollup. + */ + public startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot, /** * The tree snapshot of the private data tree at the end of the rollup. */ @@ -118,6 +122,10 @@ export class L2Block { * The tree snapshot of the historic L2 message tree roots at the end of the rollup. */ public endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, + /** + * The tree snapshot of the historic blocks tree at the end of the rollup. + */ + public endHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot, /** * The commitments to be inserted into the private data tree. */ @@ -200,6 +208,7 @@ export class L2Block { startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), startTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), startTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), + startHistoricBlocksTreeSnapshot: makeAppendOnlyTreeSnapshot(0), endPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot(newCommitments.length), endNullifierTreeSnapshot: makeAppendOnlyTreeSnapshot(newNullifiers.length), endContractTreeSnapshot: makeAppendOnlyTreeSnapshot(newContracts.length), @@ -208,6 +217,7 @@ export class L2Block { endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), endTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), endTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), + endHistoricBlocksTreeSnapshot: makeAppendOnlyTreeSnapshot(1), newCommitments, newNullifiers, newContracts, @@ -266,6 +276,10 @@ export class L2Block { * The tree snapshot of the historic L2 message tree roots at the start of the rollup. */ startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot; + /** + * The tree snapshot of the historic blocks tree at the start of the rollup. + */ + startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot; /** * The tree snapshot of the private data tree at the end of the rollup. */ @@ -298,6 +312,10 @@ export class L2Block { * The tree snapshot of the historic L2 message tree roots at the end of the rollup. */ endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot; + /** + * The tree snapshot of the historic blocks tree at the end of the rollup. + */ + endHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot; /** * The commitments to be inserted into the private data tree. */ @@ -346,6 +364,7 @@ export class L2Block { fields.startPublicDataTreeRoot, fields.startL1ToL2MessageTreeSnapshot, fields.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + fields.startHistoricBlocksTreeSnapshot, fields.endPrivateDataTreeSnapshot, fields.endNullifierTreeSnapshot, fields.endContractTreeSnapshot, @@ -354,6 +373,7 @@ export class L2Block { fields.endPublicDataTreeRoot, fields.endL1ToL2MessageTreeSnapshot, fields.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + fields.endHistoricBlocksTreeSnapshot, fields.newCommitments, fields.newNullifiers, fields.newPublicDataWrites, @@ -374,6 +394,7 @@ export class L2Block { if (this.newEncryptedLogs === undefined || this.newUnencryptedLogs === undefined) { throw new Error('newEncryptedLogs and newUnencryptedLogs must be defined when encoding L2BlockData'); } + return serializeToBuffer( this.globalVariables, this.startPrivateDataTreeSnapshot, @@ -384,6 +405,7 @@ export class L2Block { this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.startHistoricBlocksTreeSnapshot, this.endPrivateDataTreeSnapshot, this.endNullifierTreeSnapshot, this.endContractTreeSnapshot, @@ -392,6 +414,7 @@ export class L2Block { this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.endHistoricBlocksTreeSnapshot, this.newCommitments.length, this.newCommitments, this.newNullifiers.length, @@ -435,6 +458,7 @@ export class L2Block { const startPublicDataTreeRoot = reader.readObject(Fr); const startL1ToL2MessageTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); + const startHistoricBlocksTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endPrivateDataTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endNullifierTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endContractTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); @@ -443,6 +467,7 @@ export class L2Block { const endPublicDataTreeRoot = reader.readObject(Fr); const endL1ToL2MessageTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); + const endHistoricBlocksTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const newCommitments = reader.readVector(Fr); const newNullifiers = reader.readVector(Fr); const newPublicDataWrites = reader.readVector(PublicDataWrite); @@ -465,6 +490,7 @@ export class L2Block { startPublicDataTreeRoot, startL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + startHistoricBlocksTreeSnapshot, endPrivateDataTreeSnapshot, endNullifierTreeSnapshot, endContractTreeSnapshot, @@ -473,6 +499,7 @@ export class L2Block { endPublicDataTreeRoot, endL1ToL2MessageTreeSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, newPublicDataWrites, @@ -533,6 +560,7 @@ export class L2Block { this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.startHistoricBlocksTreeSnapshot, this.endPrivateDataTreeSnapshot, this.endNullifierTreeSnapshot, this.endContractTreeSnapshot, @@ -541,6 +569,7 @@ export class L2Block { this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.endHistoricBlocksTreeSnapshot, this.getCalldataHash(), this.getL1ToL2MessagesHash(), ); @@ -563,8 +592,8 @@ export class L2Block { this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.startHistoricBlocksTreeSnapshot, ); - return sha256(inputValue); } @@ -583,6 +612,7 @@ export class L2Block { this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + this.endHistoricBlocksTreeSnapshot, ); return sha256(inputValue); } @@ -766,6 +796,7 @@ export class L2Block { `startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: ${inspectTreeSnapshot( this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, )}`, + `startHistoricBlocksTreeSnapshot: ${inspectTreeSnapshot(this.startHistoricBlocksTreeSnapshot)}`, `endPrivateDataTreeSnapshot: ${inspectTreeSnapshot(this.endPrivateDataTreeSnapshot)}`, `endNullifierTreeSnapshot: ${inspectTreeSnapshot(this.endNullifierTreeSnapshot)}`, `endContractTreeSnapshot: ${inspectTreeSnapshot(this.endContractTreeSnapshot)}`, @@ -781,6 +812,7 @@ export class L2Block { `endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: ${inspectTreeSnapshot( this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, )}`, + `endHistoricBlocksTreeSnapshot: ${inspectTreeSnapshot(this.endHistoricBlocksTreeSnapshot)}`, `newCommitments: ${inspectFrArray(this.newCommitments)}`, `newNullifiers: ${inspectFrArray(this.newNullifiers)}`, `newPublicDataWrite: ${inspectPublicDataWriteArray(this.newPublicDataWrites)}`, diff --git a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts index 27f5a4c3663..9f7990560ee 100644 --- a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts +++ b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts @@ -80,6 +80,7 @@ const getMockBlock = (blockNumber: number, newContractsCommitments?: Buffer[]) = startPublicDataTreeRoot: Fr.random(), startL1ToL2MessageTreeSnapshot: getMockTreeSnapshot(), startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: getMockTreeSnapshot(), + startHistoricBlocksTreeSnapshot: getMockTreeSnapshot(), endPrivateDataTreeSnapshot: getMockTreeSnapshot(), endNullifierTreeSnapshot: getMockTreeSnapshot(), endContractTreeSnapshot: getMockTreeSnapshot(), @@ -88,6 +89,7 @@ const getMockBlock = (blockNumber: number, newContractsCommitments?: Buffer[]) = endPublicDataTreeRoot: Fr.random(), endL1ToL2MessageTreeSnapshot: getMockTreeSnapshot(), endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: getMockTreeSnapshot(), + endHistoricBlocksTreeSnapshot: getMockTreeSnapshot(), newCommitments: times(MAX_NEW_COMMITMENTS_PER_TX, Fr.random), newNullifiers: times(MAX_NEW_NULLIFIERS_PER_TX, Fr.random), newContracts: newContractsCommitments?.map(x => Fr.fromBuffer(x)) ?? [Fr.random()], From 458009315643bde53408f1fe5802ecf5896db602 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 25 Jul 2023 17:40:01 +0000 Subject: [PATCH 02/58] feat: use constants to represent offsets --- l1-contracts/src/core/libraries/Decoder.sol | 35 ++-- l1-contracts/test/DecoderHelper.sol | 6 +- l1-contracts/test/Rollup.t.sol | 200 ++++++++++---------- 3 files changed, 127 insertions(+), 114 deletions(-) diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 20ecf12a5c6..975cae48282 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -77,6 +77,19 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * |--- |--- | --- */ library Decoder { + + // Where the start of trees metadata begins in the block + uint256 constant START_TREES_BLOCK_HEADER_OFFSET = 0x80; + + // Where the end of trees metadata begns in the block + uint256 constant END_TREES_BLOCK_HEADER_OFFSET = 0x01c0; + + // The size of the block header elements + uint256 constant TREES_HEADER_SIZE = 0x140; + + // Where the metadata ends and the block data begins. + uint256 constant METADATA_OFFSET = 0x0300; + struct ArrayLengths { uint256 commitmentCount; uint256 nullifierCount; @@ -136,8 +149,8 @@ library Decoder { l2BlockNumber = getL2BlockNumber(_l2Block); // Note, for startStateHash to match the storage, the l2 block number must be new - 1. // Only jumping 1 block at a time. - startStateHash = computeStateHash(l2BlockNumber - 1, 0x80, _l2Block); - endStateHash = computeStateHash(l2BlockNumber, 0x1c0, _l2Block); + startStateHash = computeStateHash(l2BlockNumber - 1, START_TREES_BLOCK_HEADER_OFFSET, _l2Block); + endStateHash = computeStateHash(l2BlockNumber, END_TREES_BLOCK_HEADER_OFFSET, _l2Block); bytes32 diffRoot; bytes32 l1ToL2MsgsHash; @@ -158,11 +171,11 @@ library Decoder { bytes32 _diffRoot, bytes32 _l1ToL2MsgsHash ) internal pure returns (bytes32) { - bytes memory temp = new bytes(0x0300 + 0x20 + 0x20); + bytes memory temp = new bytes(METADATA_OFFSET + 0x20 + 0x20); assembly { - calldatacopy(add(temp, 0x20), _l2Block.offset, 0x0300) - mstore(add(temp, add(0x20, 0x0300)), _diffRoot) - mstore(add(temp, add(0x40, 0x0300)), _l1ToL2MsgsHash) + calldatacopy(add(temp, 0x20), _l2Block.offset, METADATA_OFFSET) + mstore(add(temp, add(0x20, METADATA_OFFSET)), _diffRoot) + mstore(add(temp, add(0x40, METADATA_OFFSET)), _l1ToL2MsgsHash) } return Hash.sha256ToField(temp); } @@ -193,14 +206,14 @@ library Decoder { pure returns (bytes32) { - // 0x20 for the block number + 0x140 for the header elements - bytes memory temp = new bytes(0x20 + 0x140); + // 0x20 for the block number + TREES_HEADER_SIZE for the header elements + bytes memory temp = new bytes(0x20 + TREES_HEADER_SIZE); assembly { // Copy block number mstore(add(temp, 0x20), _l2BlockNumber) // Copy header elements (not including block number) for start or end - calldatacopy(add(temp, 0x40), add(_l2Block.offset, _offset), 0x140) + calldatacopy(add(temp, 0x40), add(_l2Block.offset, _offset), TREES_HEADER_SIZE) } return sha256(temp); @@ -225,7 +238,7 @@ library Decoder { ArrayOffsets memory offsets; { assembly { - let offset := add(_l2Block.offset, 0x0300) + let offset := add(_l2Block.offset, METADATA_OFFSET) let commitmentCount := and(shr(224, calldataload(offset)), 0xffffffff) offset := add(add(offset, 0x4), mul(commitmentCount, 0x20)) let nullifierCount := and(shr(224, calldataload(offset)), 0xffffffff) @@ -264,7 +277,7 @@ library Decoder { // Data starts after header. Look at L2 Block Data specification at the top of this file. { - offsets.commitmentOffset = 0x0304; + offsets.commitmentOffset = METADATA_OFFSET + 0x4; offsets.nullifierOffset = offsets.commitmentOffset + 0x4 + lengths.commitmentCount * 0x20; offsets.publicDataOffset = offsets.nullifierOffset + 0x4 + lengths.nullifierCount * 0x20; offsets.l2ToL1MsgsOffset = offsets.publicDataOffset + 0x4 + lengths.dataWritesCount * 0x40; diff --git a/l1-contracts/test/DecoderHelper.sol b/l1-contracts/test/DecoderHelper.sol index 57063ee13de..18dd4be77bf 100644 --- a/l1-contracts/test/DecoderHelper.sol +++ b/l1-contracts/test/DecoderHelper.sol @@ -8,7 +8,7 @@ import {Rollup} from "@aztec/core/Rollup.sol"; contract DecoderHelper { function decode(bytes calldata _l2Block) external - view + pure returns (uint256, bytes32, bytes32, bytes32, bytes32[] memory, bytes32[] memory) { return Decoder.decode(_l2Block); @@ -16,7 +16,7 @@ contract DecoderHelper { function computeDiffRootAndMessagesHash(bytes calldata _l2Block) external - view + pure returns (bytes32, bytes32) { (bytes32 diffRoot, bytes32 l1ToL2MessagesHash,,) = Decoder.computeConsumables(_l2Block); @@ -25,7 +25,7 @@ contract DecoderHelper { function computeKernelLogsHash(bytes calldata _kernelLogs) external - view + pure returns (bytes32, uint256) { (bytes32 logsHash, uint256 offset) = Decoder.computeKernelLogsHash(0, _kernelLogs); diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 8d2ce242729..05f30bf468d 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -19,104 +19,104 @@ import {Rollup} from "@aztec/core/Rollup.sol"; * Main use of these test is shorter cycles when updating the decoder contract. */ contract RollupTest is DecoderTest { - // function testEmptyBlock() public override(DecoderTest) { - // (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = - // helper.decode(block_empty_1); - - // vm.record(); - // rollup.process(bytes(""), block_empty_1); - - // (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); - // (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); - - // assertEq(inboxWrites.length, 0, "Invalid inbox writes"); - // assertEq(outboxWrites.length, 0, "Invalid outbox writes"); - - // for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { - // assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); - // assertFalse(outbox.contains(l2ToL1Msgs[i]), "msg in outbox"); - // } - // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - // assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); - // assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg in inbox"); - // } - - // assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); - // } - - // function testRevertInvalidChainId() public { - // bytes memory block_ = block_empty_1; - // assembly { - // mstore(add(block_, 0x20), 0x420) - // } - - // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337)); - // rollup.process(bytes(""), block_); - // } - - // function testRevertInvalidVersion() public { - // bytes memory block_ = block_empty_1; - // assembly { - // mstore(add(block_, 0x40), 0x420) - // } - - // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1)); - // rollup.process(bytes(""), block_); - // } - - // function testRevertTimestampInFuture() public { - // bytes memory block_ = block_empty_1; - - // uint256 ts = block.timestamp + 1; - // assembly { - // mstore(add(block_, 0x80), ts) - // } - - // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector)); - // rollup.process(bytes(""), block_); - // } - - // function testRevertTimestampTooOld() public { - // bytes memory block_ = block_empty_1; - - // // Overwrite in the rollup contract - // vm.store(address(rollup), bytes32(uint256(1)), bytes32(uint256(block.timestamp))); - - // vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector)); - // rollup.process(bytes(""), block_); - // } - - // function testMixBlock() public override(DecoderTest) { - // (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = - // helper.decode(block_mixed_1); - - // bytes32[] memory expectedL1ToL2Msgs = _populateInbox(); - - // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - // assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox"); - // } - - // vm.record(); - // rollup.process(bytes(""), block_mixed_1); - - // (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); - // (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); - - // assertEq(inboxWrites.length, 16, "Invalid inbox writes"); - // assertEq(outboxWrites.length, 8, "Invalid outbox writes"); - - // for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { - // // recreate the value generated by `integration_l1_publisher.test.ts`. - // bytes32 expectedValue = bytes32(uint256(0x300 + 32 * (1 + i / 2) + i % 2)); - // assertEq(l2ToL1Msgs[i], expectedValue, "Invalid l2ToL1Msgs"); - // assertTrue(outbox.contains(l2ToL1Msgs[i]), "msg not in outbox"); - // } - - // for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { - // assertEq(l1ToL2Msgs[i], expectedL1ToL2Msgs[i], "Invalid l1ToL2Msgs"); - // assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed"); - // } - - // assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); - // } + function testEmptyBlock() public override(DecoderTest) { + (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + helper.decode(block_empty_1); + + vm.record(); + rollup.process(bytes(""), block_empty_1); + + (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + assertEq(inboxWrites.length, 0, "Invalid inbox writes"); + assertEq(outboxWrites.length, 0, "Invalid outbox writes"); + + for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + assertEq(l2ToL1Msgs[i], bytes32(0), "Invalid l2ToL1Msgs"); + assertFalse(outbox.contains(l2ToL1Msgs[i]), "msg in outbox"); + } + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + assertEq(l1ToL2Msgs[i], bytes32(0), "Invalid l1ToL2Msgs"); + assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg in inbox"); + } + + assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + } + + function testRevertInvalidChainId() public { + bytes memory block_ = block_empty_1; + assembly { + mstore(add(block_, 0x20), 0x420) + } + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337)); + rollup.process(bytes(""), block_); + } + + function testRevertInvalidVersion() public { + bytes memory block_ = block_empty_1; + assembly { + mstore(add(block_, 0x40), 0x420) + } + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1)); + rollup.process(bytes(""), block_); + } + + function testRevertTimestampInFuture() public { + bytes memory block_ = block_empty_1; + + uint256 ts = block.timestamp + 1; + assembly { + mstore(add(block_, 0x80), ts) + } + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector)); + rollup.process(bytes(""), block_); + } + + function testRevertTimestampTooOld() public { + bytes memory block_ = block_empty_1; + + // Overwrite in the rollup contract + vm.store(address(rollup), bytes32(uint256(1)), bytes32(uint256(block.timestamp))); + + vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector)); + rollup.process(bytes(""), block_); + } + + function testMixBlock() public override(DecoderTest) { + (,, bytes32 endStateHash,, bytes32[] memory l2ToL1Msgs, bytes32[] memory l1ToL2Msgs) = + helper.decode(block_mixed_1); + + bytes32[] memory expectedL1ToL2Msgs = _populateInbox(); + + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + assertTrue(inbox.contains(l1ToL2Msgs[i]), "msg not in inbox"); + } + + vm.record(); + rollup.process(bytes(""), block_mixed_1); + + (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); + (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); + + assertEq(inboxWrites.length, 16, "Invalid inbox writes"); + assertEq(outboxWrites.length, 8, "Invalid outbox writes"); + + for (uint256 i = 0; i < l2ToL1Msgs.length; i++) { + // recreate the value generated by `integration_l1_publisher.test.ts`. + bytes32 expectedValue = bytes32(uint256(0x300 + 32 * (1 + i / 2) + i % 2)); + assertEq(l2ToL1Msgs[i], expectedValue, "Invalid l2ToL1Msgs"); + assertTrue(outbox.contains(l2ToL1Msgs[i]), "msg not in outbox"); + } + + for (uint256 i = 0; i < l1ToL2Msgs.length; i++) { + assertEq(l1ToL2Msgs[i], expectedL1ToL2Msgs[i], "Invalid l1ToL2Msgs"); + assertFalse(inbox.contains(l1ToL2Msgs[i]), "msg not consumed"); + } + + assertEq(rollup.rollupStateHash(), endStateHash, "Invalid rollup state hash"); + } } From 1991a57062c3e7ac2e7eefd7e3492618aff148b8 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 25 Jul 2023 17:43:28 +0000 Subject: [PATCH 03/58] chore: forge fmt --- l1-contracts/src/core/libraries/Decoder.sol | 10 ++++------ l1-contracts/test/Decoder.t.sol | 9 ++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 975cae48282..967083390c6 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -19,7 +19,7 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * ------------------- * * | byte start | num bytes | name - * | --- | --- | --- + * | --- | --- | --- * | 0x0000 | 0x20 | chain-id * | 0x0020 | 0x20 | version * | 0x0040 | 0x20 | L2 block number @@ -77,7 +77,6 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * |--- |--- | --- */ library Decoder { - // Where the start of trees metadata begins in the block uint256 constant START_TREES_BLOCK_HEADER_OFFSET = 0x80; @@ -288,13 +287,12 @@ library Decoder { offsets.unencryptedLogsOffset = offsets.encryptedLogsOffset + 0x4 + lengths.encryptedLogsLength; - // load the l2 to l1 msgs (done here as offset will be altered in loop) assembly { let l2ToL1Msgs := mload(add(vars, 0x20)) calldatacopy( add(l2ToL1Msgs, 0x20), - add(_l2Block.offset, mload(add(offsets,0x60))), + add(_l2Block.offset, mload(add(offsets, 0x60))), mul(mload(add(lengths, 0x60)), 0x20) ) } @@ -412,9 +410,9 @@ library Decoder { } offsets.commitmentOffset += 2 * Constants.COMMITMENTS_PER_TX * 0x20; - offsets.nullifierOffset += 2 * Constants.NULLIFIERS_PER_TX * 0x20; + offsets.nullifierOffset += 2 * Constants.NULLIFIERS_PER_TX * 0x20; offsets.publicDataOffset += 2 * Constants.PUBLIC_DATA_WRITES_PER_TX * 0x40; - offsets.l2ToL1MsgsOffset += 2 * Constants.L2_TO_L1_MSGS_PER_TX * 0x20; + offsets.l2ToL1MsgsOffset += 2 * Constants.L2_TO_L1_MSGS_PER_TX * 0x20; offsets.contractOffset += 2 * 0x20; offsets.contractDataOffset += 2 * 0x34; diff --git a/l1-contracts/test/Decoder.t.sol b/l1-contracts/test/Decoder.t.sol index a2951920314..58c06e1eb1c 100644 --- a/l1-contracts/test/Decoder.t.sol +++ b/l1-contracts/test/Decoder.t.sol @@ -24,12 +24,11 @@ contract DecoderTest is Test { Outbox internal outbox; Rollup internal rollup; - bytes internal block_empty_1 = hex'0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda5410000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000006027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000040050f7a38e7222792175befc9d6af3433c94309b86f3d2cccb3d9dafb178071a000000022bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f119000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000102bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f11900000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000'; - - bytes internal block_mixed_1 = hex'0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000235f4e41a2440aa28f9ac14e7eed447ddd2e539179cee4c0941e6e408d2443e50000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000600b6abbab461cfb072b267bfc1ecf8dc3c943736341baf11c5c829e345c49b509000000041c1b17b2cb59cc2314fb65fe31dcfdb1b014630fab522a263d9935601ff78a5c000000022d02c42204d7182da24e9ca1e3244fbff1e00efb8c85ee3a1ac9488fe2e3aa9d000000022d9b8d2353587ca56bdf967b4bb8847af3671bd6901e9e28f82c240c6e33129a2fbbd267a1c9b23b3ac1609b2c2a7961a0338c56d62607d5f8d6b6a29e7fe4cb000000101d223d0a7bbe8cd9eace6507ee0fa9dbf84565685a1c6ceb978cdd46c47025ea00000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d00000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc000000906eb2b444212e7fc5426b585fe92da7a94010f06dc82f8ae57dd4dc91cac317e141462fbe15290e7da75db817402d54bb34c3e36b82b681103e75a06b53742b0b225f76d3e207d15147eb3fa760d364422d4bb6a9ec10df5ac9b8fbedada4b6f97045637edc6c78f389dfd44a466e10e2cbfd84b112515666452a25e6877921275cc60bda20061ed54e6775087bd44cae00000090b3f361eebad14c9843114c3e6e2bd810b17a1381953eb6cbb0920e5412435c42cb36efa2ddf219d289c394700893caed500cb13b1d5724d57cb97922ec555d7fc40c94889a666bced531fbda4f9aff016a6b4267972abbd9f60287f6c1676f6b2b20577f3781e34a8cc4dd36cc6e2725d1b8f6f9aa612fc43358c1fc167a56d9bcb3a463fb9abf152723c36020393f5d00000090e084263ed67cf75ffbcf9f9922716125423be3ae02c0c3729c564a7d4209afe4534a20db0dc79f85a69ec8676eaa7b094857b5af72dbd40346c7bf2f79cb39bbbf37e977fb595639e0585abc2bc6ad67b097c23a286a2c4c62380ee2d496222ddced1e4d329d5fb47a9545927466e8c663e2a559d4fd78af3845efa3c09ebb3d6d01582609371337d6d83ecb704ce2e2000001bc00000090979ac1a9ccb8fa6b9f8d1747232ea8e8864f3cf83ac87f780d923d33e97a85f6265276e47faac640a966272722bbd297083a0c65244eb2af13e1606259957c60a88e03366a96fc328b0702cd760a399e1c3a1aaea86e4dea5ee70213ff3cec470cd54c52097126ba8556b129d085d5e393c78dfb03b4c3626a77cd5b0d2f42acdd3b5e975a06cc2582ce355071364a0f00000090359b86b1136c91f98136d693ca665141f5f7adf0ddc0b3d24ebe39ed6e4e41b9d239e64256b0609710419eff5f183af46cdb7407aec40ff9d3d291befc3e23e65fd6254b68848954eee73e0ff6964789f04ec290cc99421d4e0e56821a8a312a67970a7ebe83173b49ed73d8840b89a9d9cb0dc98fe9f4feaae4fa92b060a935d8c1406da1a627653baba6a8267cc62c00000090c194828fe951f3090d5c36d57dbe3998258d521b01ab426864e64d06e29e126a3ad8bf44eb471f87b57ab7a4ae675696029cd9ebb22d0531b43d8768a2c6426a1dce65ef024e065ea151a865b0c85a176d8c1e6f882fbe4d67d91820b6d412466f0dad365b4a824700c697093f14e8dd6c6262d7d377d014f64c941ebc6cbf9f6edc9d695fde67204b98c24c4975a621000001bc000000904bdaadd47d29131302d4a29451be409a04d7dfef42764e84acea034f5997dcbe37cb01583b3e82cb83e5c6f66818dc340b00d9e3a89c9b43045a69ed33478bf28bb11cce3ef0f7af62f96b40e80bbba69f3672751c10958bc365f2285c16012675d00111f440bdca78403ccc5411412c66e4e4da0e786295bc665b891221254152b8af23424761cdb74b45b4a9da854b000000905ae0304af7a3c27c9ea281ccc1f646de7110b4c4ed43e3739324c42dcc84d93fc6c6b4325bb3c081cd7159315060af0c6b2d1e60956ca9210ef483f7ec880282606f8a6ec48556f3badd07a2a0859bade234daba4801ca7c2b55766a4e62b3492c16e2b4077dcbeb2a3cd33fab95774791d743dba7dd5572d76d58cc65a95161d1c46fe75c05ba2cd1e8a994d9b2caba000000904314d956bc3d4990810346da528a4f7af2994e5a41e969346e41617b8a6cddb91268f8f471847037fc84388c60eb4cac3d15e774a3e243f151cdce2ce60bf348b1fabddb3adeff2f669172cd67eebd8ae153423391241572e335b54922c21f9db35c717babaec2c746ad769603696eaf7f4a7037893de3c4a2d7afbe6f8374ae39f1eb65835c02e41b176cde83fbc469000001bc000000900d2c37ba80eb50fa643e8bb1b2be6abfcb87e67b9a3199aa54911d35fea3f6e918b7d19c876d978c6af8d9416d334a02a380d5067d016d1c38e72efdd1dd82f89fc0ccf03ed4b02ecf0430f19c8f7d036a4ca56654acb8a6cca6aed4ef70e69226a73ff44595e59920650a1b1c4507efeb2540949a053bd59bd3225b7683d04eb845e22b4c2854f4ce3ad69404b8517a0000009046adc2c903a76594df533c486b5f0213e1bfb5ce70b22034e328d2b40b0c3126919fde6536d823bdd4b6429e3418199c5cdaab29240d4bf6466118f526c193d3cd8d7e9ec4e829271c230d3b558c8503b1e22d71a9e72473e18feb31ca5de0d9d57e77fb27c8f28c11b5e07dd8c2254540e3ea20650ef88d221732a4a9164bfdcebfc77a9f2badbba68231f5ef4ea3040000009062878ac127eb51ad6bb82e75f3d0d003c664b2010bcaf68e8b2cc6001a8911b57ac81fa23591d33248c0babdc70b53f53955ba124a852dc866ca6f32db37a4fcb0c39309e80f73c59ab0d76d41671aaed89b54ed6a85d306cef2c65afc2042893d6f858f8c5555a4e64180c3629acaeb813598f7b08328cefb69b413d5583ac0c4c5571e856bf556ba0c01d4af59f5e7000001bc00000090ff2435a0b914f0faebbd91d4473d7c139e093fb7fb5a7fbfd3976a36731bcf8bc1ceee34a855f3646e37f07c05bbfdc304c8b4e4105fe1ba8f620cac6ad84344ae67c9a98270792c376248abc54a3887fed1aa32da71444ef85cb0c5bf6754d067e543b18cfddb2a2bf05782018afc649a8d40cccc2cef80819321359ea87ed2840e321bafe6f6df4ce11895b969230600000090f01ef0a085fcda6760980143ece14b530125bfcd9c38b6ca47961cec36698d684a520168b9092ecb88d0384f90cb0262add2ee8a6c9752a1dab7f73738d95b87c2f4acbc816672097635bfe14f61937cb5baa0574172a2d84271e6c4dab145c3fda63e7099ea0e3949af3642e6d00d41c19d3d48d86455e6f6f168d9009d8780e81d3f9a125f360079aa0ea5774e44cd00000090303d2297696cd74d806fa47bcb234b1224a624737e75db864007d03a4d006c857384de3b141e2f0846f2c4cb2ff4db2cce6d75e727e02ac0d8bcf7185a00d7f177bd856967359edf67dbd6c41097dd03bd51d1b5523c54c2794e4d1323f4ecec113f36c7384b14e3cf95bfa98ff5357be32226a1825968b50fe076821f5afcb320c8ee22da0a669326cdee408481c431000001bc000000906cce662bc89f0e2bfc073f7fb02b5e4554c04245864b2f8602b3b5b8ce869b0b80809dd2abd376f7689aebf4eb9a9ddf4c1b45204f38eca18d00c03a6c1a7ee006b51552f21ef587bf99f532f0b9289f8e9378a8e70c04affcd6653339149435f6392edddd8631fe099e48a14a3f714a636a820243919b24c28af14eb67b949b3efc7bb1fc8592549f7cf417596ff50a00000090cf301578a705479b2c666d95ba9c33e6b446216ce84ebcb5c692cd64b70b5ff911a6a110725e656b5da4f5559c3fdbf660544f979fc6afde525bed51dcecef52e0d7c786c10dae116109ac08d0d42cb2417fe2e221cd8e195f82c859713f535ac972c169759aa3017a916cade68fd0fbf12ab770072571828122daea5e755e47eb2bb9c17858753d6fb7b50465554a58000000905b43550bbfc6b90c6c71e4e852d5c5965fad0bad906e057d7fce52b4931f46162925b802d2c59930528850130a421e5dce1b5a5b31f9dd5856dd11fb1265b64e6df9d3576b9b1b5492752a39f0941556df29a41d1ebd53b6e3a4076034b2b22a4572fbb47811d8cec4d811fb2f44ecba5c9e31ce6f24de219646a85d9535317828aa378309793ecf6d3955aeb9fef712000001bc0000009002d5ac96e04b1354d51222d6d525e6ba31104b2d19e076f1389f8a6cff3ecb73dd21c8161e41b470bb995cad44e7a4f4c61d0ae08c6acb6e4ec4a38c1e4957fe7b0f385a655164401c7a4f6e50de8c0588e83d37df12b64a79acba23f7ee0a6a0a7818fea578680d50ee7e289d911617a42f9728cce2bbc7f4a2cdf22f3e64dc697871edd0c33ce1c9b179b793a89c810000009006dae99b741eb1404deb4f716aa6b153d9e05ee4f1ca76b2495d9559b1d408939bac110c8dbac10957a5f709367885a802c9df7ae0b4dbf29b74e53b1d182639d2ed888a4e8c250ed8a6f4acefeab665e2a8481da550dee1ced20fae158e99d993a034fa78054330793a31574fc1d469b6689ae9d8d54162d82a6982f4ebd239f152ed0c53f962cdc7611a298c1d1592000000904ae4fb51433228123b9b6110d0cf7536ff9c13daba8e88ea129e44d451bafa159ae0c73e148f91b0b7f04e43230dc4860532d8b1bb623d0ef7e5636ea43fc8edf5a31135f50a0eb7b57a0a431c3531a80d354f9f199a9e36ce690946e8ac360a652b68c56c7df4ad623f10d99650ab6bdc95b401657481352a4aa5f48610d76c236f78b2b64e9799a338a7b18993a625000001bc000000903c5e8cf037296bef39b34178fc6704de6be6b9c4c977f13b9040a369b85b7579564bfbc3ef32baf2d59d016be685f44851f43ec4fc7a39417e4bc16278193c97776bc2bc06178d5dad9747e5a6eb8283ff8b3ac8b11299f8022ea8afedfb356c814c3cd9fb989d851d9e6722382e1b184d7fcae98f122dc70dcb57ef5536850a266c6c3061c0bc501a081531abd0335c00000090be24b50850949a6fb272128474fb4c9e44c4e9f21235c43134f06e36a8d5432724daf0258ffb72863d934b189725a9fb2ee95dfacc5d5568d0f70b7de4140befb4496fdf54e02d215e98b06b0fc32ad6ec2f9397b324c153d5d3dc88a988308460fcb61192b89021848e19f0efb11f6de7d9a344d696d292c960c567f4e2f3f3a45d30c7fc1b28b762476e613a45bb0500000090a58b1f5a78bae600267b40964f867160741759b2db895253e6629306741e9629a1d6eca76350864f297ca566a3ba2c707e3f7ac5633178a517de20edf98a9ae237474de5012f88ab0ed68ce79ba0cc9af44313bca966d78c44f76798775ab86123a53224c43805e4d668574646374c3b5d944a8583bbe508cf6516e68f5a21f1bf5f591fd1e965422ac31a07960249ce00000e00000001bc00000090f9e56638daabd6fc1023090b32bedcf471261843722a57589df71ae6a6fb9068fc9f7fd1a2746d7a3696b7e4552c6a6fbf8a709ad295ea66afd3201783748f5fec2ab3f2516703404e1149360415d8166646796b117adb6aa3294c81795dddad2ffc84d88828d21a751619c15d804dfa695b23298f03b1ed6f0b1b5aa5076c284fcf2d268a181c195d62c83cd6bbe15800000090ef28121a593a23b9575a043dbf21b4f7004de19f7f9d8b43b8685911aca0728843c35ea6ec86bf567e12414e458ba0c4eb73ad926d1c9834b0fe095cf0375a736a131bcdb899c59c46c9b6323f8468b118818e941ceca4af4b1235f6eb2fa0d1e9b6f9f5225a424fc95448d3249d3e672fc868b5b9cc2550f0b63ce2932a31e1c15fc4c8bcec304cd7dc5c91b21197b200000090e7812aca513f0efbaeb1f26d0dd854f2d959e8462a3df8510ef9151e027e4f6e0022c0fa5a5ae9b2fe2b07cf9737d5d3e3c14302ee2e0b7f94fb7c5a22b4f0768bfe97c8f292df7746f468569b93071072ee308dfc981df098886e07495f5545e69f5566b6b2049cbce7030decdb2b5cb7b41f0b6dff5cccbb90321752986fd36856a38e466e521fd4b2e0219dc11200000001bc00000090af74c11a88f7c49a1f09874652ba9ff762cf886bdd68768c15dad92b6f9e121e4337f607c653ac7527a675c4ae43fa036b11b3f401c49b0bd4b6c30e21d20ea4145e357279338288fa4f91ea704e8a5cdb739226b24b268f842c062554cdd33272f62fb85bc76c9545a9989dbaf9b7962c56812b8a972fc4142e97d02745b716576ad36e242813eb32b0d78a64a1fba2000000903d20a276fd09c048d101c8d78e69ec6ca4055f68e0b3ff07fda4cf6bfdf4b0be29d235a77951e58ab7c184554ae31f3e50331dba55308646321cf17c473cf2e8fd37f08cc65451a3e498d22256855afa8f1be99c5d7023363fa700f3acdd5a354035fd19633197559766a56f49222704f16ae8755e01aa305077f1ff2e1fb381db6ee2d45d60a2daf03489428defd79800000090561ca53af312ded7a6d1a45f6d93aa1b1079f2de66713b4a6a2c303ce78fd26fe6e9bc0f61b3a86a82e95ff52ea020a581dd45e2dba70bf76b474e752c260fba9b676e9dcd0a84f9aaa993882d584a0aba6282985a46eafba41305ac5767b163ed2a590d84629bc3d402b21f4c2ed4621dbdc432ffab8b2b4591d7ef05bdf11c0a34f9354189dbbd779617c765073876000001bc000000904ce42b5eec11797c1f8afc79114c6ea9cedd82426075ddfd8a6dbbca559c60094fe58300bf1a7107370f8c6bed505cd3bcea1aba6dc2be4367c69f1f79f45514118830b1424fb0e8ce93de8bdcbb95280169924700023e4f98aaf6419da9b08cd1a792c726434a03ef7b3059c4757d6e3e7328b4876b13bd0fcf7dbc7134ec3d92ddfa8846d014f09b04cf7037b901f90000009050b61813c794d0bf68daa228a05a5f6a95456520afed8a5a0c07ebb4ca7242a7594462868b811c95d65bb08a3c369162f6bc6fb1fc8b9267586dc03f411953e700ab00cf55764d79f429d21fac45539dff80233566854493d4159e35cd15d02840fec6cf5eea625b82c390df073898f3854f3c9f19d14a3f155118b91d629098ca8388ad5f260fac5dea06a5449b917a000000904bc2c01e9e4e3a2f2f148a881b87e635785c7b440d634a8ae7f894c732aedeb8f87367117b6b5ebb585282e3dcd53c42362c962af14bd4e370133ce2387ecc5102149a62089aeb02c8ffab68df211bbde384d0d9d5325c8e85de847b5d810eee257d18ddd970cf4ec90396d34725f691d2b21e0b6ca8debb8c2f894980ce2db28fe97c8c00d4182346cd335219d8c014000001bc0000009080d739bf38be185bab1564dc36940e345491b0ba1a0d519301f946ff88cd36c8ab9bae17bae9828c5aa4608851b9ea14cc6de10f8338bfdeef0890a31282fc30d1459e0f43c63ee33e150d9069b090b573857a013db7442b4147639d91768ce87a93e560dafe84e975f24b8967a91009cb5555fb2e3ca35e25ba3246cf307d00d050d906a8f1427da6eb0e49236e66320000009052160a2b2b01d3adb6ace0f043523e0baa2fee091941ff5b95ddf66db5170b22b8ba578f09fd8c8cf127920c5da841bd7c5d439fe6ab222ba2f7cbb69b0e34ca217afd282d4a1d85c76d8a108970528731c1e4f32703e0ee92410eedbd52d0fb7d2d7797c038e887d69c2e4016c56a4cf9a98df0fecdffe16be815b94b1a5cb382fd02c2ad91a49a5d1ec5882cc574ed00000090102ef5abafe1a801f359491349a458cc2b0bc567c7752fcae65a0408230fbc88334098c5c8ae4cde42d383eba6832d71abe6f4c450f5c14b6f56dd9e0c02d818d912a893ac1694dcab0cf9ec29fdb378b95fa3179a82757312ddf0d7852bb9f1a380f20e8851a2b7313900fbea3e07a3ae18e457ddf5639a0b1f3e7dbce05d8e42db93082774587393b3daf59ffbba7b000001bc000000905f9d5406ea0521e54cc2918df8c5b6b97473424f4d0107a32d0aa31ea5453a8bed2f4f455892d61bed404080577e7744bbcdd880f418d4a091b9f8482514ad04674abb41585d5558d36c03be687ea2be36a493ede581eac13fc309f0b3c74a2edc152217cc24c45fcb48bca15ef00900fd62429786c725a99d1b9edb9b03bc7cdb177909c0a8c3e6822f2e32269cc96900000090c927d7dc259777e39ac2a14352dd6a3743403cdd15c154c3d44d15014018603356e926eb1efe597d34708527cd952eba7a9fc1b3c527427d4732ab4830cbfdb10f315e4e11ec1eae6440dc7f5aa4f53b95a2921f19be7a5f9acabeee51d7d73af893305bb86855559e8bf31bdf56cfe732a504e5b4a2005a75c607031da39ec02a783d92222beb4aa8c4ca142d33bb5600000090c1a905e2bb0dd6c444a2f3f909be4e7d338651ed45be1ee8d55caef42b1df59cc1b2324db5fc9c999b94e14b1f0447ce0a42443028e2207f2df5f5a87a3e2f44390755f9908681a74703197b78d7c95d1a2771e8782388975e8e0eefa35a14cd6ea38bbb117632e8d4f3b4ddcffe3dfa4d63b86b51240e7d7d10f437b9495aaaf1270731bffe191410f6a90668f09deb000001bc00000090bab929e7b47f9ffc56a6698a8586afb23a4aa1c135394fc784dae3798fb20ba90a120b82855688b82f24f1ed8786b6364df9a68e2f0798704c17145749e9e1e4be89447f9cae3a4266199652501f57a779ee3649be8adc4c4e515e2bb5eb6b7662688fef126aaa71429e5c7a06c831d6a3b4fe014084e76c332b02be583144528799385b1adb5a227006e516c7c651c200000090b97b9efef32a05892ac56dce7dbd53422e989e83691ca29d8b33c2be35873522fb4618a8670a13922212d7e552915def6c707d8c7d5b7bf2c27eb86c1745bc79ab35f331c2f7d47bbf973f5e4061beab3d0363416bc6d512f1d3bcc01fe8b2200d690392bddeda24b48651ed9fc04fe54af774b6a474e2b4726d50b1068ace093509adcac756800a16af821d54ec7d1c000000909226c5084e16e186bd9e541267ee3d429c15bb43dbf0b763b357d5320de671721292478be795f2161612269c46f198116b4fc074fa67c80f18d1b4e357961645275e12a098aa4c2491c88033e83cec70998c0490b185fadfd1a5ed843b1f67de377a733e70b96f9a283739eb6a6cb91e3a0ad6cef9f36fc79a8c137e391ad860235728abb7d32d359e61a7c81d1d5e9a000001bc00000090cc0215e729382d3444ad0f362c10056bf719c015218de84e473dc849791d970f9eef969e1e029bcf044160e4b86c8de4e86a615a8826a4337775ae718f0c5249da0b7ced10a9097a6f5ce151b7256c2a901b827c57f6f0ce0574c366dbc01cf1349fb660ad93693d4cdeab0936e38498378823c74e1e6c905d503609b1705481589d96412b8dfed83d65f3c6292614f9000000909934e72118bae1be1466cf7aa6a7fff16e7b7ad069e0803caeed5c89fcc2962159bc74a1ac5798d03622e679750b324bd7e046c5b893cfe79b91da241b65800d912434f58bee9fb242c4c99ddbe6694f4f0a8777d7aa71e3bfdf5c207add86e13d6e96b3998ca754b3b1ab566f5b72a8229e85ab4acd20574e82849ab399ad2bbd593a35d2fbb284522ac11d5abd3df700000090896c70456c2b313d7af3ed9a5c2c525bda692a4eaee80933d90db9e96a419f4f7c89fbe5d578a12ff8e9825b245431f76b851f33a8e353f3267f8252bb4522165b6c4bf96fa512302ebdf8ff64bf1cc283236e096edcb7d3b726f96bd1c7cb2e91abcc042e3ec5e06e74d748fe76b432fade0eb0a9cb20b06806f71415fc8a27e3d803bf1ba923c090b509dde7168318000001bc0000009020562ad9bf630b1d12fefc8c620f2a403f54813c295e87c7e90f527ab1a83f2ca6e9e92d4896597a0aebfb3f63059b413b29f61ebd672aee82b842cd1c41c6e56378c332552195c3a924a4fcae0616f117bffd90494105c3358d9aeb389e1350bbae80dfa5b7bbc7c3a30422f177eae6297a332ce4d78ab39383f8983db42d78f7ba2e78137dcb3bad3964a4e287ec02000000908d9737b8984f04ac7c553973a24c6e3b42c916e97512ebb783a07d7cc71f39cc316c89a37a6ac719a050e31867aebf4dc15884ab4aa256e3bd7e85144f9ffaec76c3dddd8326974d55b4fdb20c1d09818c2241bf3094744e5da9d95e931d76d896241d07edf58792c6f272c4b8e67530fe4f05c662ad8b3239ad450cc084ae0eacaea4c928a730d98982773c8a9cfba4000000902d21ea94707238e11327f310cc5a1d61bcf3b230dd8358c66534dd1e61141a3e8f6eb32018fb065de3e271d2f58e93a73d3343ada4788dcbc38458e908a3236ac828b6260f81ba94e4dd8b361c695272575fccc0dbefc5c37ee856177898dfc6bf745e8e856e0bdc0f8ed1460ef0d31600ef32af4a5efa05d3c1dfc71b80087afb2c6356354e92953cb28285632a5e2700000e00000001bc00000090b6b785a893c9c0c4368bcd283bd218703dcc8f2ecc9f721af430d61dabc087c4e0b0c3c575b9dbb67bd9b18eb7ea50838216d8fffce548aefccd802598cf68ec879632163d9d3f424f5cde402f2e90c6aafdbff67f1d76138bdf0f07aa66f218d7fa82d5b71c96c428086521f0a1b3d99f6570c10c1570def6ebb734ce38fba2d31df12e13fafea1903d8059cea3b38a00000090379a72abb0a5df1331e887d28e17eb23e3868c552d316db9d6630362d9a9f0b18eec57ce9854d860a772b2b25bb7138b79bc060c7d426c6c08b3c850d8db8d96500704f9b43ee791c28c24ee4dcf55f66f4205d46208f33365f534f4d24e0240dee79567fa3959bcce06b3e4431d6207a1a01c97d3adbf3383c8ef83618bfa92e87c57b00fc5188b9092bf5ada6ce3200000009057cc225fc73ba28aea06a45d52d711e347438edde7f1cb29eb308515818601cbe5f722ec0e59b1be58a2db33ac0740bd9c726824cc807a0b6f84817c61c339c2fd95fdf0ebf4d31b3e713ad261bf09745821334d718216ea8c2feeb0d21e31bb6f695b6ba86f8ce95af1169727d3c83434305ebf2a5800ef53395addd383aa6a860f2ca133e7c173a02807ea8248f5d8000001bc0000009090438b8cbaa0fe2876ee6560b32b396f688f9a76e7968d1f81350d8ce0a94e0239940ba0c1a79dcff2e7b0894111ae4969f5b82a9d602fba69377f582be4ba8d1dfed2f84574ee6375c6317f8734a547f6dd457c9027e32bb9c807fcdd23d2beebc622ad99659610852a3f3ae3cf55fb4e5689147ca3329931df0ba8d69f44f9db5a2eee4fed51b3602d0ddc2ee2e1b0000000904679f91e736276795fddaa7f672ee5329fb2b2805ccbdd3344ead6beddc96e33cb9ecfd683b9f90997c47f4fdb8d1aa34c9b2e259d778956736a640cc6b3c49f43d012682b8966605d17066d490187f9fb7ec62e0ac58c151365ff968f5672ce87f5152181252407d6cf5fcf72aee330382c05f284c9bfa40048726d829d715675b02b1bbb158099ed76de7732dd87a300000090171df1386679177b3caaf165a29d44b91172ab5ba6e11e73abba018a0712fb7216150d9914802d24af90df73b5d10e5cfeee085ba89dc862e131675351e2fe066b5edab3ef380d47c225134aa6696c96fc979781acd6d92c1bf1d6fe5a22952fce22b40f9abab339e8c824ca182f5b564f852d5022cec42c1e5808063cad2c0a6899dc91f4b4e0f014d41ecf30b0733c000001bc00000090f73cda38e1011799114681aec8676d15cf04e1996f7bebd9620b3899d2a88fadd31bf6c00de4b90d3d33631049e855eb455a0af7b258a3c87c30c737972ac5240c474d9e18fba22dfb6cb19113b7af3646fa5b0c4cc78129e064ed53a5dfce38aee2cef0adc1ecc9526947508a0525ed50dcf5a64a6a34c8035e46f154b3dbc91d3b62396072e48b7927ceaf80a948a500000090a2c90c3fd62e6c3b9236753c545563ab765db750c0d46fb03313eb289c16e21800ea14b8461d404ca2a3c132e15a2eebdcdfda6fb26a53e1c543a9c15b223533b1647f7aca04960a0fe6f18ada9dd4013a0976129cfe596f6de5c0eabd25b48b582fc782a503ba4ec03a1cc0e07213b9a43b13551261e65fb070f85e226b2521ad441db4038781eed1185bc63ce3dc7b00000090e4da73a3e62cfd1e71baef3b802a0b10ccb723bcf26f6115ab679724e6e08d1a589baca7fc9b1088e8bda527540e3d2d37c06341ce746b8c4f4d6133375f7fd13d0ea62b1f99fe88b143a5731be5f648e8db78b0352b87bc7c114676ecbf14790f5e328ad74e914ceb0d87c7dd9908a8e012ae04d037bc0ddc5c582cebf384aa6553fa166b8c639046910afcbd64ad68000001bc00000090857e1aee424f91f5699f41b2b6f3bf426eec3b2aac6f23f18df162c275c5c981a1f1c50cdaaf71172438bf825711ff7ca25c98e693027bc89aabfe189498b4f5a3fb62aebe2428924afd861410d87ef97254e972470c67f4d60a4c4ab6f3619b151ff6384b4d969f41f9ebc7068940b006fc39dac0c91cc0e867a39bfb65b855fa75cce185ecd028ee9ec9e79534a9cf00000090167a6241e3a93f0138b987eac85ae919534d16dc9a80bd86ea97ffdb0b9b6042d75a6fd0db555bb907336f013dc8ebb30c42990c97fb0a770742fb27cec4e37b909788ce1338151890dcbcbc8c5af9916bec77f98d4cd2c358a72f3662eab1dd157fdb71b58ea8c95e44c6f6e842c107ea4042fdabeb88cd7772bb01939449b3a84c95589b7fbfc8b65275af7561537f0000009071d5c3c0bf428b360fa2d5b119e112662503032cddd90044d840d6230cd305bc1ef5629c4bdc326df89baa9b27f8ba45d932d8b193c01ef48659a4706c4f00ee893fc062155c71ee0a07d964106e57f8d4fa6fe30b75d32fc85cbb6bb51bfaf86c24842d317ff4fe76663ab6ab358ccd52d81d4ca5e1f51d2c63269c1667f6788d0a2ef5abee5676692c32c63eab63e8000001bc000000905447d0488946ca5c41b79d52ef05da1889d794eff409b97f7c0ba11327cee35fe4481a454324cddb7dccf17ea311fe6aaf0d7d5a8b813a5ae9796eb447b4e080e5e96420503f3ce734879dd26a945fcf3c0517a8fff0501034a03c12f8fe328dfb4179db4e9ebba66a1a4ec52e63c149159d0c7d85390fd7b458860afb0706bf6a9d4b4cf7bb519b105dcbdb69a8e47e00000090bb17f41eefaebbd2e8a125e590260bd565dd1160b71761a311d35e1fb466be6b4edfe197c926b16b21ec942637a24d5cba7b0a97ed452c8abfbaeea57f84f9147d85059d020805dd39e9a382707c6c50e3db9740a25c1cc806acd0f2b3b348732d0b40d230efd56be31b6c14c8db7f323872f465a8c8c2883d802b537cd033fa22dd2d94d41dffb719209c7066faf76800000090fb1d99c034031173cf99df92d2c1466c06bd9fd2ddf61d80c7764ec2e9b3fc39e3754f8385d47c7cbc91853a2e230d68c43ecbcdc05148c54bf4bdd589c0de19234f13628c5173e59e73a21009df9cb2ed5fb9c2f572f3b6eddbdf12140f810bbd0d43b740b45f16a6571e3890b7d0daf91382c6df2a6cf694f755a3a54f2ad7d4e08a3c34d136981ecbe959a88a10b6000001bc00000090394bd2a4044e0fa016de48eaf444b3166f1155216741ca6cddeb4a8635bf438146dc5d98811ba76954928ed4aca1ae6df227525a888987d4d8ba94b7c8616326ec01b5f37da8c4af05b846737a1ca500cb2865a53eeba6cff09cd48cb1ef61dd56adf08f0d02d6cb792db82dbf92b24b4fb3e6ee985fd11f2521dd4eaf6e208d76998c8d8ee2bcc58382e8e403a6061e00000090ceaebed596c0d16e317d6bbeefc1256611ecc3711ace9376cc4204cacff94326588f0f3114653d57af1d1c72ed28462e6820b3fc7392131938b575e04712c03216f04d2a8fc6d2413ade9058dfec7f5e36cc943ab8a741873017c17c57869929df35739e7b7ff6aa64182ed1d21beecc3c7c884746fb05eff157a60c13da5a04ee701972f5103422b5b20f875ead5fd600000090164177fa3d9453fbd6c7cb4884d3b7a77e056a7e2962273c809411486775c93e06b6e2f067a1b1da7b7deb8d1cb1cb3eaaea0880d2a898591d12e6656c44db58b466489f58567f88f9d5e1f19c26935fa13fc182a358b7067af8a9fad9265d3b05f1220ebda17412e2a5f579d58c7727d5d151d99530c5a68ca290c6014ad665eac46eccf1dd4beab4add602ee4a0b3a000001bc0000009013f0191618599cd9a94329b8941fcdac9e8f2c843cb1ad35077c6312c089d53369b012990d86772aab4184f99dab44d4dabcab6894c540ae40c03f3c97f0739d98dc70c26f3b2ec3ff78621f9e255f095448117aae033cfafd752da06b13bf47db123018a68019c84ea43ac1d534fd8b6ab5b160d5764d920cb896c2ccf492d713d6495a1f5507d26866b8d8ad24fe8e0000009088a2599f38885350473ee05bab6679aec3fd6753be0b0029d3ded6f1a7d781e6828c47a0c800da06454f58c27383aa7e6ca6dbe57453a74ec6effe58b52b0b36e972a1fc5b3d965f8d849dcde51921a6b0755e7e3dd1cb7ff046cf1496f3dded3bbe5bda67b253d6e09ac2ead6ae8d7c2b763831d67bf238756cf9feda6a0078dbf8404268be7c950a2be61e1726ef330000009094d580c24085ec765663c6290fcd6b482893e572d671dd593a8ac82e50c2899db396a0474cfa5ba8d6b8ed16dc32f95af966916ade952275b586589a81d0c7fae4462e5f7569002eee9e419369dd1f7585feab27fd512d387ec76c4a38a3008691bb586210d1f006aecf9f5053362341994b414a0afd445c9192368596000f3528002e99747a94749be62520a9941419000001bc00000090ab299d12da5d4400c0fb7ede1ce9a277dfefb8ac60ef4822a5d3f2e2cece137e0d386dbfc29d9e612821b416028b692eea91374c805d368c233bf6acb49c8ca1d814a95863ef18a0aaa6351550205a065010b875e2802729f30777c6442a9f3a725de94b37025c070de6ce4ec381e6bd2462bc35010939e34a13b802cb58455ea56c994263367e6d9d5c30c94fc3cea10000009085327a7bde96de64cf1ec0dd4ae3f6fe4893bb14ba8a8f210032294c990cf6b8532f184c440f93d61eeb66b7f8f4900026d77e3c7fce28e5e8479aaccdad7fd97792199b48289ee96021f658f9542994ca61997d4e3ce8de1ece2eeddcc76c745b4de2a263246f98a6c120d4c896c1cf1dbfda47b149f41523a6ac90883c32d41a82210ae996907d5215f87c20010a4400000090b9297568777df8232be5498e8608b7244657c6240ec9b869ca97ffbd5cca719f0a18759e2fa4b37a7cf41c753adfd4a4803e2c9439cbfa4420776dba88391c9c5a18c05111fcae73dc406a731e9d2296758d195b6823c5853772b44583059794fee392be61e2523602befa969cd93915e2a2354eaf942a28dee21baf732016656ebe18812de6682dcafd4b43a5ffdb4c00000e00000001bc00000090801ef9c2577ec82636d3cd9bddf8fe9faa1916f076983c1eb61db7cdf5284a554b54c708549f4a16fea0a64a7509a7656d7ff04c0b6dd5b92b76641930d3ecbf22c0c96082a97cad9030dbb6287e5c4c9ac5078e55f4f8a1bdcbd55a42d9c882c1563509b06f4484a793be80ecfe0e42cd3acf1f33fab869b03690d0e2c8995e3fef9bc8a02f4cb7e9d076ba2cb0e8aa00000090c932ad01f8bf981f307cd0678be81a254fcd35fe1dd01d89f4dbc1a08aa1b6d7821e4599904894618943195181dda479755864f7bbb228795182ce13ff45656bbca9f56112e7d630bd48f8490b013067141e69379d4ccc05f08c357f8e54b10bf8ac4731da861cea9b509b90c0f76fdd834371a2de507483b09b9d402065fa038b4591acc7c3a1726616c368d64ef87600000090875924116fbfe13068edea36b4029e0f8684bd7921447fd7cfb85f2ce489b755934b81eb2dfb0d318cb390cefead098c670756c2204a29d8b53f6284618638950529a0c5c6bc9e927efa083b460a275c69923a91038c0089470cbdab7fb51d7ac7b05e20bef690eaf28615d5de31b260257239137bceefac894dd3803070ebcf0a743b06accbe856b7785d0815427796000001bc00000090c1524c555d1de312b4d6dfd4498bb6f0689f10df8814c31dd2cc9f9e47cae78f4cf612c9de50d777cabf50e738f3076a1d4464e3d51631f72adf16337c02d58da83591df58291f8edc2055376691623215a04d791b2f70d724b4999523352553eebeb5a815c66504d1f6be97ae94c778e606d4ff110fad07a919469eba144602ad947f2f1cf21063d666f700bcdc152f00000090a4f0fa4eda04c3269acb3b63bd19447076a8df4d3c7f4ed3775da5c54afd384d84b0dcff3a2afc5dd9d9c604f0716208b997a22a7f0ebc3794dee40ae80031b4ae1e695636fd8675eeea73abe669097e05df866fde70faf4cf15c9d9eb01645ffb7fa40a8ec963802a6b838b47fd91466c838102ea392c72d20d1cd2e2cd525be013551576dffa28bb6fbf2bde78b6e20000009031a6d25d6b5bf8d27fcd97cb17614b487ae1fc7a3296a0e56c34492b7cfe3b52d542b80b0114fb19b7527a8b7fc497a0d88fd8e29e8d86552cf56e773dae95ad63502b0fd6d487cf69b9c23b808698ce7b707a40b5b765da987905f0979b836aaf6fec136f7427c9f53273c7145c1cf8236f43ea369ed0ef4250512935073d11e9f1a2605b9e6fdaf9953c89ebd1296a000001bc000000900f346de1f80bebd75770adeec5e1b40134cbb2c6d8f71bcecaddc6a162646a7dc1b546e104294f9d399e0b07274babe75668f43cf1bc1390c6c7f03479135102d76810e3006c7a1c5691a677f441380b3749e616b1853ae1086c2f9de1ec1158a5966587d30fc7a062a98b77de490774366ac4bd55176ae71ebcf97380e3458f99a64c68858d9a542d787c419407480c00000090afc3a982e9b18074b18f8e9241af438e78e8ac319bd7db91a3cc42b095e12a18dd961b24b8c863a0994234adbfc2d6e7483a79e4d54481048d90cccffc9465218ff5f5d901203764b62af6b4db57e2602543585602e1f94f4c086dd69c5c9b37edbc03abffdfe322f353c5abf54ce07eb8ed5e805a5bec7d59d15256362230beac173d50d74e67226306ffd589b5c0d5000000908c9f222581c07fb644955af88c1a00a64c28e97433755fb8d2b824a045ef3ef9718e05c4ef36217d6bf5167ad0a5f17798cbfc967d8db658d369d2ece607d90374f295103ae9d79a0695c5def30bd3a43c4e04d2d915f347f444225e75f01ad2d68492efd52ecb47064ff9632f5e47a8d35122a170d5d95428aa035584ea80b6ffe3e499ea40492da1d7e469a030ee11000001bc00000090f3aa49be1ef2da782a3a250d14a09a4571b0b2875223e27ecf0701a757e03405d9ec08c8bb839dea797c25693021bb0695d2e5629a2568ddaa8d79b3316a5ff059388a49c33c70e4ff39cbd33dde9f049c3a9aa1dc9f5c0d8143641736d572c1e3486a58835a47adc0d8fb9710f1563229892d45e055aec29e9531fccbe7b46ceb68ea5529ebf9d415a5dbdc86bda1820000009030629b2f31fbdcd559bda5bbc841d7fc7127e1fdcd05b92fef2dd6172ba516b3712c6c0919fea5c19246b15f5ece0e66ee60b84372b840b1e7b8b7e710f105b3406e167774acfa409263e612b92705475118cf88bf9bb02f87bfc8aa22602748f8b4dd0f60ffc56b4569ddfa8b2ea728a18f6de5bb6f67f302eb8284f7ee74b6ceb8343b52bd1bf47d478b3301c7dffc00000090219a86279f2a85edbb4d6f8431b1add2747a087197466d378490c9193749711b0bb59b38cb7fd15898272ca2dbef517963f6086978fda51cf685209158d6222adffc82ce8179e30ea9bf2661e10470f306835488e054e6b3253f78a2fe6959979ba5d7c27e3ce187fc6ad8d39e0575aa6ef7be38938bded99f596d09671890fdf64d98e4ac0c987228b144dcf6d3b3d9000001bc00000090b5680313dd737e26fb80af1b3a2652cab7da5447292c4317006f6699ecea9c48ed7cda8733edb6ceb0467610c4c454eb79779920fb67e1658e5cdbaa43780e0822997aa6341347fdcaa032bf10afc63c3e32c4ab0a79943d9069c2ee16c1ed6c0afb61b3b468e2dc389dc5255e53d29576e823d8a446c27146cf9edddad9cf73f800c123462852b2e5e4262db101a13400000090539c18db539b56c610e0ae6e65aff959cbbe87a2d1265e9641ac1c6e593a61e5430828e9cc6959ba079cd68372f5ebe403db4b3a765e6596118cb67b36ab498e09592873b5f65b5adf7ae22bdb1260a35d66eac4cec5ba2f25ea1aa098a014dc88b399e16d3bcbbdfba407ba23c652b8147e044a93b354b46ae70ff0132864d5da00cd9e3c3a3d3726698cd46813393800000090d689249495b3e90523cd0c7cfa1acd98c279a814ad02cead5651ca56edb9cff526005591fd5c5630035ba8383e59e11fccb45700e3f0f185ffdb7a2d6980e57536dc68d0f3f5ea5af29e04d3ab2a4cb396c6931839b74e6f516c13ab1c1705bce0c8bf55ac11796c0feee88162d3ca18daeb835c13d187dcf4494f582d5013b5b36cdfe0d8a01d2303f68e406643922e000001bc0000009033c59257596f42bcd14cc4931da340546eb7ed481e505983ea174a65f337e3ddd8694b4bc91fb9c6aecc02bb26bf4be45f7781d8c71268b898b0a88ab612969378e8746ededd98c2bf384005f182c002f356dc7e9f441aa18638f7cb970f68ff146335f746322443e427e941d567d8b2704e3369a4b7cafc3857e8f36fd05b3fc655dd4768421fad2db557b6c7c4fc4a000000904632ca5761f5e73e9c7c833817c97164030c0fa8b96816ac0d0240256c0b823ad8f114c1bf1da4785232cefbbaa1eb5c8e7148d795a8507f1878f04e61bc372413360ec0c89a590d82f66db9a7da440f04aac88af5e636d3316d211f44314469fe2bf49a563f73d4bf12b7b318fb30538c3dcbcf254e14cb686177c876e63a4f88868fb35289fa8de8a8d230ad7452a6000000904b24f06233a197ec6bad7cd38cf4bc9fd4268b7e1ec2e5d3e216b44c2fd39b7a091d74e4444021e4b2c34f7f6937c9c5eb60d20c2f5c3826ae13d21bbfdcabd5a1412cfb6e725ef24cfd96657034a248b4f9923f6e7ed377cb8082d928a0948f952eeefca63ad9fb5634dc801fc3d0a1552ce4d63b60f953c560e6a1ccc5dfd2ca0a91873b6dc19b5d16e4db432026c6000001bc00000090145a6a31edfe177e2a1f9722a3aeee99760da5a34a9b69ca0a23c351f41021478ee69c632627166c2e2bcacbfda3ed3e7274b0d71670bda552b51a53c98e334ef07f4f7ce8c1ec45010f4d875cd8a85ebe0af3c7644d564eed7b2909bbc7bfa0be1b43b65e660bd592476fe14e73478ea9e109473a89bce38e34a75d16cd09975a4043763fc1b17cc867e05888af015a00000090fc1864227ec8804b378b445c8d92eaf0935fc6e49a1bb5e62f5df74e576225a3ec1b98b06bff1ca40d896a0b3d1fd5da1592fb129528ba4d58f6f195866c7d6c48b26b475a0f72226099e52a51c2259b7ab9edf7765dba7454cee56064f27eeac649e798bb6353b2258b098cf8ba89f662075b9e3e7d5244df22b9a6f5d6c30e3da30db89aa20dfda1340667907efd3b000000903041f714a8934ad43722f849083e7a6585d66fddeea9be2f423e6d4f9a8b935d1a88c7e0394b53aac5bbe8606742dc2182be3e81be382fa0dc7506a120d7d832832b69f1094d04cd5b2c8613dc858963c5ef897758b5b5deefd5f8eeb76dc92dc996472cff8c2d8d2e840c843a7d7d44a7f7a7461b9819412fa8b93c1923b8a689ae21e8c6bc560cdc13455dd1ca74af000001bc00000090b3e2eec14675cfb9e6fae9e2839f095d822fd6181aea14152a4ea49cf7b89242da9ff57e0bf78e006dd3d83b0b8be5e884cee08bbc965f6953efd4ed3e86e25ea6048f35f4096c0f96503d21aa4990bfc28679707704e3b8a04be7fc25bdf4e509a0584c4772f9e08b1e9436ec371758298cb6a41a65fcfcdb333b12969e112ea444b6b1d1a32ed1f4498b1d3c8d990800000090f69263003adb1ebdadae02462f927195e4012704433ca265ae4302a17056e4ee1fde8ed8a24d804afc735761c06a5a0ed954ff73a9698e88aa68717a8055032cf0bf3d9eb51bf7c90dde3f8e351386c850281bcabe4da59e52582e05d64d74b4969e7480284bf8fd8062912d4cc469193ecad218a32fa941cd63761ed22b637a4401dd09847c9364389a8d780774a67d00000090e5dbafefb9b1634f77bb47a9183ede40562b5c9a0dc801d38d0b90fe57c0af4a5fa2a7a6fd5f079659e22b9aa6b79f9ff124df2ebba44bcf1942de81d7961420889728a12eb054ff6802fd4a20e5bd047addaad41b7d838cac5def04bfbae085b804c2caba0ba79df0230523629e59938442d6659a25d8a1d99e09a1397fa3768f57d79924ee76da4da67d008eaca622000033a000000ce40000012800000090639d486cdf8acd57ef037bd52e740d927260a038bbcbce4a25bde98af3f670bdc7368780be3cda17b9e8e1c825b02518927735957c6c50fc33f6083c635704a9cfe1d511917acf0f63b246303b2d782cc38fc32781d41e450dbea20b50c5cbf1a1b673c6326b538f94430f5db70085f3d9d01b328f165f0e790136b52e7ded86c38eeca0390ffb4463e537ddca0fbe48000000901d83225a50847a2925cb255c507dd38f4645f05d85941db543000b8cbf1252fe12a18668514c4565dea3f9b88f87fffc65a07af88a5f6ab57a79db7be69cc8d52a2064f511c7a2a04a85fff0e2688821b713c3994301835d056346690f9764e5a7d6991083b0484c5cbe7961f4bff6dc46658c8fcf3529e187d781990f2ad7459537733f81e8212205dde6a547409d900000012800000090cbe5f87209419bb150056d00d04fba5e7386c8d0926df7a3c619c1cb7285a80b542d105f55cab4a2929a1fa5fced09fd4391159d41bd97e3c48b8527f1a7fa720786f42e149ff3684b4602e9c721f841729c5240e02fbd72a69334f1fcae9925f661997b5a6f6885fb6fb35215570dc50accd2888b39a6edb340592c186a8f0c60ea6edb1c10fdecb84a6db4cab102f800000090a4057e4da28b2d51b0cb9a14ed984359df78af483ab432f408ed202c48c4b9cfe3d2bfbc69b3158ab635863f0cb918ce6f517be1a986235926174dc9f2e90752b1d4001accb4fd267f5ff6299d1831672848e7f17160c03364fb5a00e29822c884db91413bd63ae112db74a1fee36fd37709c5450548c1f11bd7274b518871cfc02606f22a0f47e2a0caaa158b4df7310000012800000090db4b8cdf217d4e8d5457bee548314bca5d7d83fc27aa60f87d459cfdc6ae82f757614de089da919dbae04ae77f9422bf1b008dce97058dae7a043cf1d9f82f6e3220ac8c8b5f1aced6bcbe786454e2156484dd8449e1633ace23b50b813d312b7be8a33c5e721730483d57a6a2ec3bb08da97a5ca5ca787ae34e4ffff000d9d001228941442dc2f3bcd9871a1dac37ae0000009065d2234018f4d38a5730ec5510036db0a1c6293e5ac5f5c97ee28729e2fe13357c1da0119880138d20e25590e624261b70794267f4433d4711adf2bac4c08757568c52d52e0cd182a40f3181a130fa4964886b5bdf34a102bda3b0e97830ee548a2e4ead76689aacaac714a62f640128165d477057b3c7b6c9b2448613c834decd7e5ef2ab4f50e9f32acd6d236a20fd0000012800000090a2fd7da86afaa8d81634276960ab4fc9b355c4fd2c3ea5114abe4caff0427f96f25cfdbee7cebf96d35d294b96c22a087c702a05914a24e5a115c69fbcbfd25e21c971cb3697127fdee46c11d4b9c30c2ce5de4259e41961522c4118c2ee00f2b70bd7d06c5422c26981683bd61a6ef754e087a9eeb53b16e3bcf087cbc8f390cfe97986f1ef6b0234493e9d8806275f0000009079d388084b1dad045b2f73306b13bf335be555ad14acdc26ae123224ada033592a2be1d2ad3a942c4c532ed1f0c1c1ca9316e10fe474e12dad4534eb8f4fa045803d50816bb9579304a7a00aef983b8fb834344fad8b4e572a766fde8676cab6f11436fbc448abcf88afad3969aaa988112a7c5b081416d4e70963f108dcad242fd5d15204d370b9ae2025c0f6faab620000012800000090e0156263f20bb92a39dd3049cf6f418143192d5904f2734340f55fea7854616030766503f2136688003134e058481035725434bb5a09b2f16a61ecd6f314368cb7e567ec36c42b17728f2d47d71b49d1853b4988d91dbd0fbabf36c98c327b19a267d56fad2dc1f05b2bee17002e3e00941af273c5e9f84a5cb3624a544abe94305c2d5e290fa0e8340a084825fcdd1100000090e755259e0e6fd3b0d8cfcdcc0a7ab644ecd780e405dc3996da1f784bb132cc34d7f800605d002a1fc88f9f49bcb408069b7f81e1f343aa1c6c3509fda4147b8cc2af53745e245f7d7bfbf177d49db1d6ffba6fec04c78f3556438ce455c18e9d54d1815229ed43eb4eccadb65162a90e0eccd7b628fa5649f3def35eb04361df8f863adb0ce47206df3b20fcbab8417d0000012800000090103ba4b387fd9e18befbe1321a17774de0a57791a98aa00ef7985afdfe51787931c2c20425516fd2474ad3bf2ea9a1dca54c7af84655cc99cba7c2bc82107809118d13fe2db6dd6e89304486c0ab9b2248628cd2a840cd379640bfb9c1125db845214c941bf00054baf2f7cde366ddfe94904277950663fc4ad23356875905a632d2f9b51135f6ee529fa7a0db622c8900000090a9f7c79016d72271446f8b8f28971a011db5e1c26dd313def999790a8b28b94165afb94360cc66edfec6afb41635cea260d3ecc87c0fdad7f7194e3b4b2e68b2ca1ccede1a7bbd9a1fa7cc75b3aea404052d0d158cc4be13757bc9f15c34f8326c2194ce4674fedfae84b0062f2fdbcbbaf3735191885d22eb23d7c37dbccb17c6c73bd6ce64e1b4efacf04b2bac202d000001280000009004bd547838a4f37fee8a1baefa39987c4c979636407bde403d8d4c132253e17d7a8582b5a0f883527c36c5b766b7e218e47cdf5867447ca50bd936c7d9d1443f06429beef8ef3cc0e3b4748bc87f65fc285fe5f34dd38207c9103418f9adc69427f697d1b2a10f8b80cd79224b64714ddfecb2ee3927a540bc0f14ff6c6f98d85397e4923c5ec144a1444fff4e7dc249000000905e80407b1c81e498717666a4ae03f9ca54ce14fb5ecb9322f0ca9214a2f35ec5475ea05f21b1b634b940169448ed2ec1d72c3ab9aed5ebbc3abeab2b5e1ed2b86db7940028e2125ab67427fc5399e605057f05642423c1618042318484ea12b7686b080a0162eaf692e3f8ed5729f9931c15a994127bbf8d9c2c3a2b41382a811804ea6eef3fd871505b44a43e1616460000012800000090be9b4fda861bf7888112ef635cdee9a91a3d21535b7362a6c0dd53f556681f20579748d7918f0dccd5752dcab5d3793e6f996af0ecc9d061686606dc42c1ff4f666473fc8091e1925887df5338eea6d50641af70b95cc5ac6c0f2d55005a6b4aa0c0358889cf9529e9fe997018ac9cb16b1186cf1a90fe071ae3bae3c602a6396db6ca6f499bbafdc8ac4610fbd33d94000000903498f0e293205cd2082af437d12d1619d59933be6f9d0d8563bf5c3926434ba6abc87b4056c775e78082a9a53a0357fc67eadf16643000af9c25a897de7a076b0dc6e73f5f39bb42a875e0121bfbf6d1c6817e970dccb8045e71e92ef1ed9ac033cafafec3ed0e61cf79b00b3917a7cc3e74d4eb6fdf4e4255185abbb966769fffa8c939e90805cba9c1d027f235eb12000001280000009072619021db2578b89f28361d759cb625b80707604a73e06e16da844e8e92953832a9d7d8703bfa56a6edb22fa80a55def20914c155f6576038437b26e348ef7613f4fd8616f6ca34eee1286c22b917337072c4fd7f056e2013c85d480b81b0295956f3413d532549f31bd5d1a7fff5928a68d6c808a21d12147beff79b97774dac67575e68654e0c9e4b0bdba043b0da00000090b96df6fc07703c2d4f7b60cc45c2ce90925465d435664666c162e2493fb6023a4472c5f6cada4017ae3fcfce8660c0872ae15efbdac00af8c391dc23d39fc94950b6b4254b8c8e64241976692a14e5a4c80bacf1a9091d76b3cb1b3ddec01d749c6469b28e55f457d44ed8540fbd9dec42b49e9b7eb3461b9e03b2b2db210fc9408bf399c69855bcbf5c94db97b0d6d300000128000000902bb67c2d333b2d72140e8125c20d524321de7130124c205c8033f5a52ef5751cbee212d1e9f8fbd55c9ab593bab90bd8d0fbbc74cfb7d2079f7fca70814457e1bd0f15193e3621e2ae2dcb4b666ffa95cd90f27ce22bacdf3c32bed9d1c077fa3d4b0029aeaaac7c0e21097573cac7833431105bd4f7cac41f950e81ce497d073fe041c0b267963d351e7f46bad85a2300000090989a5f287ba771b3c486594cb4e206a7fc8aba4e4b7894a5c95e92cf705983efe0dedcbf2966814be4a00aee6b386da748020ec285344fda37a0a533ce4a7161789a0c499b62b19c62bc80710f5d64dd8823e68b324a32e2b1c12335be5a8cfb55792f0f8dea993b24374838cbb74b1e067d79454b3753b758d12406fc63fb95887c8aeeef291add1091e21a21a531d90000012800000090086f352a63a2c15b771e0e95cc484d9ab851d45ece9022a2fc16979ccebdf6cd8a281d080d948dd0da7f84a3d037f11d57fa35a96a22f2b9d0ff7094e3dfb5b59b407bc65ab07c59c2b9738baf486dea809514987a7b46bdc7162db13c94a09580abb4ba31707e18fe0a83712de26f5d28b97877c9b4f6fb82521097d5fcee5159ae26c4e90f70b7b8a2ff3a0be9491e0000009025c7d37f4395d5a199c6c99fe93e7b7cf5c394699ca0564da5c668b1b4a0789681354ffa1142895c23a4115e7ca67ee112af0bcf0e5ccc798d9bd3eaf0fe14005b25256a460585325cd7c1f325edcc0e161c001fae73fbab5d24f9ee352c9ec770be8ba37ffa58c52b9e9ce3e5ef5a72d9e75a9dfe7e1237118eee1c6a8b21f0eaaa356fc29286ab04b212aa6d110bac00000ce40000012800000090dbb4d0d2a8ec9b5796f37e0276b93adfd82de35fa8ddedac71f24a3afcc1fc70cddb2f0d10966e8434bb4b7e5ea542b9fbf64f903effc84e1e089963e3aab331c4569d6d2ca5bcbe3ba69fce732432d3b7ff889c3c810e3a4fe597e10a1e51f9cd77e162887e3f12d0b2f1797e80c2c0ad744f4c78c290ea2bf3e3bf90251b5b304c7fe0e8881e9d6734da71614698dd00000090e15c9eef7b9c18bbddf844771bb2689cff590cd861b042087c7d5749e43bbf1b07c0a99a7db7fabc0f59f7e5f8c5e86f8867304654bc12e2ddcdf5066e3081348202c12fdeb0380f41bf7bf0bf12aef785960a82cab387ba3900e5efd50dbc7275452fb6b2a3c7e6d5905019b5627c3c9b177e8826a57737cca86a66ef73d541e80c25f2fa774f84117b434af3f03aa70000012800000090237b304e7115ef24ca0b6af4c6904442432c1653d1f91dda11667a3391e376a8c59b9494bd9fd8a3462a58a8ae2e43f38287965d68ff229f05db9ea2f05cb42621e99230c1b6eebec317dc511f75de10af0ca3f3d540ac79b4de653802d92487593d016741aac8d1e6f767c2632c80fc12b3fe9f84acb96f73f4e93573a0f9f4672356fb526981d00798e3d490ff622700000090d36abf7a4952bf867dd1c2d2ae4f5fd680a698e216c39969903b289cb79464bd00d28d7b81f3c19fd3870cea5d5152cea39d2b9ab6b00930075f258cc60b036150984914b301248279e5652d4ae7fd2767d574814ee68c9fb37a32532003e1bcb4875521e6a9f74b031cd71699689597753451dc29abc51026fdec1bf0b522e90071b356059ec3ca16d05047541581690000012800000090cb8402f03aa6f308556bf119609f6f02cc0d2aa1af938d6e56be76de6012a6ba66ad93d74a8be2e3758976c78a1d84352be6a8b1dc8deae64670304fd476d7d41e20e1b02ea33594014611ba725785fd0be257de48c00be120a5f233322741713f5da81edd9c6cba8afd48089d158d0dfe9eb236bae1290cffe993b9b8306c51ba8b6d88c2fdcd4cc5f3a94aa0be6a82000000908556eb17cbe123f2d0304c877536b7f6da54fe5c6a124b6df08098d77c7a79d7d871dae6f125410320f821dca432ed032ae877ac84f821568b7daf89631392f8186db2ebb30fa836234ef18d64aea7d13d2fd05aa3789c14c09a4938015343fc06a580a43fa333e6be0848f494e6fbc0e6c91ec752ee98e220897cc39808a1131c8f5811b4c60568755f1f419694673a000001280000009019bd42cfa2a996fc95214b0a1b7adbbd631dac971238e40a723b018b5a75787b34c00b7ee71f3d1cc2f160f6b395334543f03fe872d94cfc04c4570a9d3802362ad77d482d6c650696580ff7d50df656a14d82f9549a0c8c4b4a94d4b01730b50eafa7bf8348415b88dec562fa729e6cf4eb1192646d98c279ce586af89b0906c38ea22c1d7851c53639f3d598ff864800000090aef905153f7086f16d147b2ddcc9b602bdac77f4667032b7b874889fbdc7cda53099d931a61462d93a751ccaa750b3a8e55693a687cc02359177745540efb45f8355f5742f44bc19572ea9e5dc0c090288127569449d536728bddf98419cfb073cedc949b52cbf25e8d7371ec989708a452cc8819922688d639df27c5a6f1f89ad17b79a5345fefa4afb930b655170a700000128000000904d010d18bbc916ce1b9cf07a77761275b8452ee8432c84c45f2f477e964fc5bf1510da3445b0f879597fc2a1d0a6cda10c47c58313f76be11f9250e43082db2c2f2061a213c3d954141247ea2a6c7e4836ae3859b4be1b7e210d0f6174fcf171ba9d74991c74af9a6b188b56c7b86c08846880d5348b7522f31f15819b6db28434535142e1896f4063a84fcc40c9992a00000090716ded02fd483c28d914a74f40e01a1dacf169f6ecc39ff2769079726b77cc7dc3cfe9647970fda3ead30246f2bb8ce41e041a93b690c2c954c305aeef82193e086c1803c04ae989b9ac025ba9436fb36e855e2c7db6aaf202fe6cc400e78eef0d8471d1946b3b9103ba82bc0bbb3cbc22bdff6de9b614a08f3fa60695cf944f69f26ea7981dd80c39a78a4b6ab2e6170000012800000090482ddcea8042e342790b5636a5a253c4e2d242dff8aa93c4e42eaf144a7a43c645c3502bfd25b163904caefaf223321c08aff19bf387485183d163fbfbd2e4c4eb3851fb9c36ad06aa42eb3f77d02fc7d6dc85b104fadd34a87e1b1ff9f6888630e641f4110453f6ef24256db1e7f1a70e16bc995c5b4833b454876830d2337f884a2880bd3e851c7762343691fd642b000000909e394aa7821fba6dde93d161ad4d0a20fda7271f4e2f6e75e6aaa6e04879abdcdaeacb6a966c1377dfb0a9be44308338b5ce7eda23a9a132ef3dd00ad9e33aabf208014fa7d7eced6ee23094059a9c26a70777e1452ab451db4dfbd3701e04aaaa6ef712b609559504193c3e4f20ea1e7ffabd5d98d837722fa9633ddfb557dc2b28908364fbaa10ff224a6db2d759560000012800000090c298a805b2e680a8867e93addd9426e09d5570d808085b1c593da76a0400d27d559c39107d45e0ffc6d0737c8750605ea0ac4d8a339162f595c9b9e62488d921a22b120cfd1ccd2486cfdff659910b3cb3fdd671702b7540c85d27708f8ab86212816cc4c66624d9d1d9db16bc6d1272b277c887226c4dd3ea3d005b87196355f0e50eea16e4be3cc5993fc810228858000000904489997ef0faa1245cdd9d8c523aeb6710340f949b49edc38c89487f13a67e4c294a15957c598097d17155c07f67f5e3eb61f735dd5cfb4428f097696523942aa121ae82699fec94dde8b460ba6fde5113395b8fadd7ee8ff297b27b04745f73314a64f23c5e1d6a71a54c4c5d6f756eae8c17548bda4cc54b73a2efa316b7b85cbaa55e74bbc79a8f0c642059c8b2440000012800000090b99bcf815e1aa84e58f43e479149a40360fb1b016e51ee5af903e09e16afd3a1f43adccf0f4f7f6481f3725ff7dbc611ff78ed8589b37441e5bc4ffb51ee8c10cd8afdd2d4651a8723e00d42cbbddb31263269b8aec62bda4fd980942ccd3f2a0b2b7fd5e255e0e378635763d5007da49dfea0d93ed3feabd723daad70b689ca5d88f136018a755ba897ce4aff7a77e900000090cdad61ea71af30981f6a01c1c1f922d1006dcecd97d67ee300350c45c71bb02dd1cc93ff29ae59ee29f9a0b763fa0f184e5332d8b5c591acb33f384559460bef4c7cb663d37f15dbc321e2482d47a262923c2f9c121e0f8ad02b67e53963f0c00a4362c691f209039fd3fa4af613b447aed473c44f18a99a5f2e28f65c2fa11ccaaa88310f5dc64bbfd78c1301bef18f0000012800000090486fecef6b3ae95ac8e6ae9f636548cd2a1b3aba0710a3fd00a66cf0f4b7333b33944c0b0d0232bd8fd79b22daa745adf3a04314645ff0b6b984c152226931c0aa8b25a2e00d6406a3898b4957b45454c07d05c382529d7ebf344c77835dce02c49d0d55b56cca350cd2ba86659ee962909f9b72bc773806208af327f23b03f5b4014eb92f3fa476e85bf0b1343f33e0000000907bf2e48176476863d220b04a0b95b41f139fd6a2d1e8047f75e9010ff45fbd412a661ab30fa8549538fa4a69819cc2e7a2e2adc4eeca30c0aaee2403fa639035c535a7cfd331399569ee47d10df8f5faf860fd3193ad2d5c544cc91a6c753ef19a1f6c64e1e764b6b10ac4dcc40147571016a8371ff6601575956629a891b91dd238c262ba67705929b1edf4617162660000012800000090c3466ce7a4d524534483cc46fe71b134827ce2f7e313981ae63e7d6c0a433690db9c6f7564029066c585d50ebcb0e4a79280c4a31440aa66beb5fa6b1076c36630ff029c269ab377fbd32b8b2b46d337fc784b6ca7a8e150211fd5fd348f8495645940607733be947a216d4cb81c6f5147dd0b4cc5204f7600ec012273b312404d0f7088983a9da4851f32de157c526100000090664901ea78c6963fc43fa423d45f149992d9af67d74e3b49c9334becfd002e9ac159c7b4bfbeff96ffd74bc825a41493a2ddf1ec8154a3c6c9e3b6bd6af6c1cbc7e7e99a07c16538e5dcbb9864885e179ff5742d95d2a0bda32956c3d90d096eb9eb2c99746bbb66601700ed8536a126dd31986ea2b0299ed532b8dd623359453b20d821b27b712f3394db9619c496f0000001280000009067238c9e1a8236663c5d759d22f7c0b5571b4c3ce87609610e8c0b0c22513586b6091a099a865016383ac203315e83bbfba56380e251e40f460dd28d1f4f48847b1179f57912057e53b316301f603beb80f2fcc62e896c9fff553420163e005df74a455c6190e30b8a4276c7af0808c91bddab3f9dc147f6f31bea913ddc281647668e0521d44680cfac9748cf7fa679000000901554e014140980588ad1013f5514aa886ca1ffd5cb1e80f3ddcdf1652e9bcd2e418cd2b27d51a79658338c5c6e35d6e257e537d769357a0c565d766757b02ed40b720b751616d6408ebbc516271759fe0685feb6745da64dde0d7f95e85abf4dfdf7c1d98defacc660a6fb1a448bc6881e4d79869234f981095ad351b06e5f3bfc349b68affbdeeeceaf3296024d1e5900000ce40000012800000090f821f2e5485e3c0af4b84fae21d986dc642938632260220147ff8f0ec70c5f6f97e10343c0fcc465c93ad626a7112c96c9e29b9619e3430c79306697e4b79e28b2a0239a176a54234746e061b8859cd13329f145ede2524db4c02491a218ba19fca3149ad8919ded8aab2d9082594c666094ed5f3ed0296f5483194a86a6c09af2a1905020ee88ea4592f5891772da3e0000009083f8cf115bd237f940b6b6c0b070b835b3b1e16b004f565909845c1f775bd74479a0ffd4a260d337ca93253d9c15dacfdd648fe0be61716c8c8c8c7e6351ce8fc7555dc26409ca9633c3bb6cf126793f197fd40c3b80df76046f8e46bde2e11802c8a182468c8a900c612aa11a0edf37def572ff0ba72f1dc075b0aa5a9b37d9a3c2cc35663bf4e2d2a36f417a6a3fe90000012800000090fae3021c00189b073c016491925cbb782113fa0cd7559c94c8e2c12853689cf14da70ac3886a89f22e2f7b664fee4ecdce844163c3273a5112e33d709c1bb5138278512dcae2c767b90e178f102a0ef2540f30fa24cf05b7336952e34a4f4fc151aaa6d82fabe22a6baa5353684ed2bfbf0adfe7120ae8d1ed6c563bb2a87dc0e0c18298fa7a763f3aa2250f41228e0000000090620fe1d6a7da657aadd4e29e1bb09edb6f293a84f08055ee5e0568e2620ba4711cf8a0776b139ed24904139f442ce4390c988814b3b5b7b4afc27c4f8ca7c2bc1dfc9225e45afec25092031b38974666ff0db3fbe0082703eff4b153af602acdd9ee19e7023d2be09d6f567ce79929231e542eab9133b09d39b6cd149e8af3bd686d412afd06f2e88632a6098f3574400000012800000090dcaa62f948654f40d893c4a4c31662cc125b60c87075fae66b66a2183e781cf7beb587bf57437f9827a2b9fb78ab3dcdc5fe4867a4e8b8b4f012abf3626b64af0f552b9419d35d67aea4e48ec7ff8507de86e89b4354fba12751dba280f8a7f05d52449c5b4f5566fddf392e9e388d2b68b35df13454c60aa110b1a738e311d63eedc223421a48cd60bb0eb5cbed928d00000090d6bd5c8f5170af53e76f14b243f82a2c2b8b9d68bdd505c6c2fbfca36f53333b91c1f765d13b2b16ae48ab9b2d12ae0f1255f1f24c99692b71c19341d2e4776562dc543f5064fe9c7f0df630b0097dd62ef280f42b7ab50e53a42b31cf64064cd20ba1f044e24197b1eaeb1f53d5d7b3d7ef7de6ee682c5ae9f24993b11f42e627740af2e8e9c877b095b057d75714c60000012800000090f00a0370a0cd5ec57d9d79a44644cef128fd247847a671a4de662325cb879934430fdfb488edfee63fa4a177a76a5bbd7fea6aa4c3fbcd9d1926ac271ea7235fd3acd833d974be88a9e8df60c272a2a853d6a1876e84cb7857d2fab74086dfb7e56b205712d19a21e99465ada71395af3303ccb51417da3375faeef928696d9dd86cefd69cc400c166a75e7ccf78dd5000000090b085aacbaf54e57349dbce112679c344dfd54fde70c15d8c0e284c8c70f37dabf14207e638287f062c349e8b903a33f0046e6c5695a1c973223dd481cea29b899e80db83fc05380779664157dd9679ddf6e1ceda231712637b1e527bd5a0f14fa398cd793aba15a21a4776413e04139486b8e5b4924b0b5b0663b767dc5c44f3a3fb506616eb9627e72be73a445df38100000128000000904e04527a1fbc4918fb0f5dc938d33445bd450ad98eb25e3e1d34bf8aac57f60b2abab9fbe140c2784ceefc2e437a38ca309c9bfd2071f3809a28383e9faa063f57ad8667838dd1be75ea2b3e299cc4e417bb5705f1c22bb59e4a7254a6d408ae8f55772b4f2007ced955119173ce0e00a632de4a49e0a08414b308eb02da4a55231f8c0418131a63596955bf270f38350000009057b894cdba6c674382d0ca850af5dae67fd1f3dfc55cbdea681145d7bb6187ff3a0dba30eb41e19b3e6832c6beecff3350f116211f25c509918a4980c1c214bfee81f2aefc930c54004f0dd3263e106a002a12fb9c7796125ad555a1d7b37f5149bd1a27f28a7dd65ce85026647d18d10a0a3f56747e96f7b1e138a12bbbfe3b9001e0eaf0066c32a2d3687fc62116860000012800000090d4461f6118036ab697daf4e90fa5cff8c853f0b54e57aef00d9d4e81115576b4ab3a86cdc3653a3efe7dcb7fa650f176bd557b02b03cc139e9a3221cf7d3a7c2150bdbfb3c879d67e2460b69fec40a0e42ed5c0e359f6f91bebb6c506371b7338587e3d0feae6f7ce555e74da6e76302e62bbcac25d8509f3bda57e323ef7b166f1d2b391d2bb6860efdac1b809b9250000000909207e364faa20d0a1115a269393f9d98152e0019ed33b3c7156d0ef9113be7138f900c4d72e379426bde9b98e1aedc8aeab18ea9e756fa4eac2908038f003435e987d22132cadfaa9e430e452d78032e82a7ed64815063d08b4274c7cfac1a9520d10ff8140565f5986c9c2a135afee4f4d4bf19b1904acb3318d720584e3936de56aca310dd26b714f0a7dec1939b040000012800000090781ae925b7e0ebd9cb87e718b7c7ffeae45651552404fffdbc1df7d85686dd227cb4c1de22650479d3bc359ec4f9e81c79da28757035088b0ba2d1f7b2a321d1abcd3a4bb8b9010906dc7450b8d012dbee1d41e5314a7d094f797425ddfafc8728c6422c58805c0f9d698be9fc320ded25d0466880988f2dad98e0256fa89c288d8e99569f588cdab93ccf67cfab691a0000009092aa76893b5cf1b10cecea31187de1b6190aca3c4941659f077cd00ab9946f3192a2e9cff6a743b51d2217dee81a68541ce18b321fc30d4f5017f866dbab792dd00cd676ef3ac107b0e02420172a92d9f4b252a6cc4dfd4e6d506d1cdfac701ba017d16f692702e2d960c0c7e27794d30aced94c9661109af94d2381decc99211e8bc4dd401c6f2e197ef3057930655d000001280000009069825afeae91c9a0e5db75e73f9d1a1a24ff8398a6b8fce60791b611953a12eef7f0bdd08847bf4d7041aef2a144d2038aa8fbb78fd51a745b6967293dafdaa4f46cd6d0d06d53801cb9cd95c192c96183603c45c304a3332353411d8efd1f79a974f8993fe4e283975e9eef3b867cb60995a74b83383b688c102a4e0d78c6af78ed45a1f028bea71914d9d57c7ae79300000090fd9decd929d5172e46f45ba17fa6c49e4d265fb231e26df16e3f9a1baec1bd6c76a304217741ee8e638dc21c2a019d5d0cba632e13ddfdc7bfc615fde3895aec4ca4ab22291f5dcfb88f27b5d739d549d08d0db6f8fd27a095b6ab9d11728ece355a764e06f0822927716e589ec35d12123b316f1849deb6a9581502a2abd08d4a37b76400c65358d30cf4c4baa3a1e500000128000000902106ead6df33bd10b164d22be5509b1e0afdc774f1e1ff78ae3937c49c8a58c59c89ab7a254fdcc2260f641da11954b053d1869f8aff87c4ca2efb626e1a7f84c10533c1e65ddcf7e7cff35e1c3cd6e696317a1a37783a13cff580b2c614d797a03392c98f19bffa927dbb45de09a3dc25adf76acf2a041e253eef08fac1cdbf8e603383166b7a774f7175070e6c6a600000009072a7e284d2e397b224c4b8f8a20a52403abb3b28a8b788e4a091090c0b6fcbc1fb3539ad4458307722f696580048c4a492d201aab14dbd1af074d002858c522d195ee0bd0786c834a6f6445b476df280c5bea5d01e6369bc12cc2c3ac6e697de844671056cd7263f5604a835aadb448f79300cf927246b8b5220341fa78a6f3dbcbac09550a6ce546131822cad0621810000012800000090dd4294cd8f8c449ad02c6ea497fa35bb7111cccf47686d0b90d118145c1e04dcde092cdf362d408d95ef8925c9dde1ded107c16f4ac9ff46d39d96da2d7ac35e2b3e70583c3cfd6c34c9a9f5ae4a437b49510397a419f5e546ba3456763fdd8252ad584ffdbd5fd4ffda3adac48b8375255def1f7131eff0617799ce406733579c856618ad0db4b4523970c75e95de9100000090af2fd32856e57805ca74674c9d8e6147df5fd4e9367b7d43948d593fd825e10a09ec6066c96ed49ba88d680d7d2a8fe6a7d5518d3fed621fd71f37fb8ee851356ebf4d7efc2905693ce37641397880ffddb16bddd170b29a062e42b76b54171ad1b92c16dd50770cf954905e90a194c4bbbc580a13b432ba581a8456ebb371d337efd1b2f24c2812d51558c88adede8100000128000000905807262584c7578162ce616409b887dd2c861b7cc4e8f19853c008bbd4acaf0f19db1e572398ececfdef22aec0ae7030e7247fe8451984233c12b61b4afaf5804551d46100937b25b7023e5ce39a4f1d0babd330384e38030c2757abf5a7ec092c26349e1d54b83a6c0263a441e24090806168a061b708136f54a949598359283853f4c3c4abead7f6985d4fc393677b00000090ee85daf522efbc2636c7ce5c2a0ec0c99e3e905b753c34d5e6c5db2ff50c82c5aa57de538c88b78bce4c2c1b3f9a412aeaccc8a243694452962647fd3c8a0d53a2eec14ef97e1e224894d3e6db522850ac5c55d0b244bb4aea84143426ba6bfa4f5572a1ba7ba91f34e28bfe68107e34a552f3676c53b34e609675533fcc293d6e6e56ca9648f614cee0c52cbf6e03f900000ce4000001280000009008d66dd316e03c11f2f6f80d3970dc8c516fa76840e4074f4e19e0b95b59a0aebc11492effcdb0c820647a729c67ed95bf500412059c80ea48d48a26705115e659b893ef589d37268fac8809ce28919a4be38cc9e1f564ae77258a4147de79ead0d27dd159679f0f795b096e133eaa2bfff9900462c766b12b9d727c9f1981b4cbe1df4ca5da89bd4283dc4589a0642000000090c47110c0f4fae3f396a2b362bcf4e3c8a9d65fe0a21cb68d3841654a594561c12bfea7e3be27ca5a2ec93fdcff6258dc8215fed3305818baa19067acb03fccb46650250b15fd18a23f4cc1e3e62becb3df759030f92493baabc546feddb86fdea8f42749f994cefef3662465290dab5e53614405c899e27ee60b884823aa06daf2c18ffc69777040fccad493d1e5c84200000128000000904cfd8f43502458ab8ea4b7ed39a2768cd125681210de2ef0cefa30eee2c408642821bf9b19085330d22b43763c3b815dea6fe6396d3c8beaa80a795eb0ffa71e5af496632d65ef83ef4cc14288d20dd1000f6b024b26f5ed3006c6b1eeb67a3049b36fec9c76dd973745bcfe3bb6f37ecb6d08f698cac4da7ce4c781903e3b4e0fc3f3d15000e364adddcd15eaf961f2000000903efe093939d9ff98a01a5e8fd0ab75ee6476d77e279bee266831f6b15061278e9486e5d7d5c627969845f5344607a2eb666a0fbf8de1b24d1fdbd98287c037efa5877e20a4a53163a0c86f6603fb139118a93676525e98a105cc6b1e19ad925d9e131360a74aae10b31104f823e74ca6b16d485bcc131ac037aaba2b972fd445d1cad14efd641dd41a483236239c3cf80000012800000090604771ddf429cf224d4356e7446ec9cd85463670428be3e71568c06f6a9bbfeb9312f5b9cd803c9d36b9992f142a23b56c1ccd0f72b42a1bdc733ea0aa9d71531bffa31ffd6f0a2bd62155531c9ff88b9335846f76052c80bbf28fa854f8739d30e5eb965cc76d52577eed0aacdf17b49692e419cb2b3caaec46db1139e4c970244b030dcb61055d7b7db90bede37c0b0000009042e6ab0a6d746538d1bb5ad5594c60b28d89daa57b2b77c9a40090f69cfead34eccd04efd05d612586841b266c692d2f383a743f8a0ea860ed8129e7a2bfd916290021fc80fdc8c701ecab322cd98b1a1d0446d553da699ba8e672e90fad07ada6acf10d12653745581dea923b1d86b970966fa1d364890acffac86956efc5b30a11cb0f44bca296014e9a33af4ea5690000012800000090a7a6e87fd0cdb332a67c397b738c80deb4e3ff72cd7a1b3aabb891ffb5ce3d25f74e8b75816ba2b1ac000ec3034bc8da4b598d635d8f54d04c595d216b6e037f053d43233da9cf6f672ff6ffc6f6b729d6b0aac4a5ec4d5f847a717e75d027ed0dd660e502258408a639519fced9a1bc9699643f8b52582738c9243537d0945381c416af9d6d2e773add87b4942bb9460000009047e32fe86a0742d9473b758910c78e49372efe69852d111dbbc7da54b9bcf522087c4ee5e7396f2b4702bb5379c21c5a9400b7ddd1d40ee77c9ab05898fcbcf4ea65288f1b73c45267bbbde0540e2ad4af121924eefe85a3d54cabc7b10fb63b9fe3c429b75c9989e59f033df3e064b6c6237779303140bdfcf25653fe92348516f2651d6d0bb18faeea85b94bb660b9000001280000009078b9e99817350a9491dc6867f0cda5fdd9b39d1fe0a9ed58548978cfcc637957ab82784d3b2c30829c7edd6118bdf0a877635660a1d183a010d31390839af04587346dde9980e5b824a71f4e4148012d089842e4e59d5d9a89d6d78e7ec0e2513e6322b0977e3cd7b5f08d5d18cdcbf5dbcde57b87768a860cd76613fe40da8efc0618c34c12e409626b9c577fc00e4b00000090487671868ac16596ec7de56e973381703fe43929e74ff073e9c963aa22bda9d6f1a04e093a379e586f3d76954e318b6df1a823897ee5e4d7c5063597e130a81eeb4c9535a227c45974e78da48e0f7026f1e689ade61971444a449995919cc7431fc9e900129866c3a2ab7174f72cc8ed74b91e6e4c025f693045259f8c9e4cb1d32504c38443236025c37c4c7c0a5adb0000012800000090e734aaa308d6b54f9d7a52fbe20503bf80c73d593365fece0bf1aaaabbe87770833e54bf425e71ffe12ecbda6e9e1df258f94541f0d7f94fddd506653cf122f7c5386c659dadcdb6e6e92bdf9824aa69f775d39caf5b99b73226cbcbd95b82d070c2400fdbf0996937e67a5c513c3946e667fba983561b48a931e3cf3f68254e4f2fd86034fee3abcd82c97ecf88348700000090b96d8f7757738f0f7f58de967313433e3fe1733bf4d5c15a2078690187a1acde17ebc915b23cbc6dcf74219e3cd63362fa003391f19a3a92bf26390d441c1a1c69809270fc9d61da00d0695dbf73d67f37050d622c773829e929b8285955e82f16361fbbe9113658235b9afd0b7a784781b5bc6251126453aa973943410f16a85910376f0b609292e9b9e46104054f5f00000128000000904282cb9ca7cec0bea85b1a8e83379b5365bc8a843a3d79afe1e9d5dfe92184920e375d084c5c03d3d27d4aa4f142ccf6c89ceffaeb3068745e2c9dddebd6ce7dad36b0e76ae97feace5939660ad9dd79f8d75fbcb740a2254c39b9bf2787517cfb2cb48a0e26228f085e85dd15b7e873058334594d9fbb8e877ee498fc11ad0e430e3be518bc9e0c1afb4ad652ed2f9a000000909824f3e20d39014fe1ce0c25d27af4d1fc16aede6aa127d241ab74b62aeeff33691377f976b31216fe4d36161da0f8c7549047c9dfde650a5c9ae9a5357fb15c3e7dbe296ea10d76b46612bafe7824410bb297eceb346111a42b36663015e421a976697df83943d2365bf559b7406e147403547f78ac7b8fbc797275800eb6d46078e862c501eaebc40f16c837b4bba80000012800000090d78151e7a08ad4e11b8a2fb201f83ae713fdac255819cb3c024620025484b20fc3748b713279b0dd26b37b2e38933ea7039534b4e0f5974a4f96ab01d8181dfc988b9f5f495bac0a6ae67df7053157249f7baaf0c91a284db4d1d4345602134382388b5b4a3449214fed2956b221526e2e0dd60320449b4d725af164b212b69b8e0c4b7089c3a030407b9e861ef132c200000090a0539b668cca6c01fe2ed23f6f2d5df8145a48af96d7dd3dbfe6e675af044114c69c44ad4f150b889cbfba7eea026e9ea0f599c4d035d7b709ece6ad5988040a4d51ab2029d9cd88e4b791fdd0cbb6ac36fb943ad0b80e6b2bf4ece885b1048dd8d9b1524f44b75ef82d3fef0826c5d043b2fcf253758cf5e372a5b87d1cb94eb4cbabb547a28d3b8ee124ca5581bb9c000001280000009077ac86a4406764a86f704ff7139ee1f7a2f7e10253ea15f544502be3dd4eb0f4fc2a75653bb060ccc4d03c442f13361ab492775ea71761e90a7113ba55e3d5a10bf43f23fbce60e453aa76ef098b9c93560cf002bf2a52040f12a1b54cfb0c1e47384e91a05d774f558c47a01508e1b0b102ec96c16c2be6ea6d06c8fa1b29aecd8beff997fc4f0ea947c41be6dc7afb00000090be51c1520c12abb9c70648e88aebd75f67f72da3b12e7450a780ea1a8e3082b5bbe7db2ddea227fdd56d3312a3e440f3c1de5d7a1cbd17ed1e71b263fb50e6722c48d5005df3a9fc8b524c64a2de0cbba8dd04fec097af10540a193e0ceb30380c1e127931d154f19310644472722de34551b100eabb2146354debd5dc72f4dda786b3efc42fa91daa612f4986ca4733000001280000009005f1417483ec00421bd576190ca8d530a8b0ebca2abb3995897ba2fe24320056312adc6d898c0c8dcabcae7aecae0970e5640b9664479948de28fa79ca53c232044f5e97331d53dc4c177cc5df9bb46b9a9752b3846de4a72524ee262fbc12f2b25b57ea1da2d1b05ef5a250af84f5f1fdaf2157ec8dad2ed3bc1e5169fd9866be39bb91961bda0fd7fa1ec3e9b08bb4000000907f8517ea4d3422fc85946ad1e31e8f25d2a2a1374ec8b76917efe37eae76771c416cea99423ffac5ee56772105b8203db836ae6c5c33f8ccf371668f516eafc891e4ce29e6c055b473c27330e9e40adedc722c043e9aa74d64d98ce7e363fe2c36eafd9f92add125e075bcf6464d4d3cf35d335a0a70f07ee53e736d282004f45879f9015f0da7a1ad200a3eef7ba0c60000012800000090eaba354a29c93d1f132a1e369079a6db3ba8387cf8f02e36355b5b0997eff35d167ec7c07a7b20013d7665632ae9f5ae2e46671dc912ddfbe3e0b5c7c1db56496f3d464b7a741e764142cda0e2d2d5809c9c4ff4a095cfcf5e8f6b6b52aebf94e2454a7041aa434739b7c98e937cc62877e7ac129f07ca626e71a126880beddd01506d8c7d71b3d35679565eebad27c6000000903129008169633e4de7fc916e6dc182da1d8748aa8b736120f9498c842ef44a3a0540f78e2f5a0c817f38fdde511d5830a0bc185fb760d3581c127038546032768c0ca4d57821496f147047aa7a401171a4bfe3475c8dee1ae60d6752044946ab8181430484b0bf8537e17ec9856129776fb730cd06818524d3d96f8c8c0625b7e51e86f1308adff7423443ff0853ff3b'; - - + bytes internal block_empty_1 = + hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda5410000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000006027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000040050f7a38e7222792175befc9d6af3433c94309b86f3d2cccb3d9dafb178071a000000022bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f119000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000102bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f11900000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000"; + bytes internal block_mixed_1 = + hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000127378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000235f4e41a2440aa28f9ac14e7eed447ddd2e539179cee4c0941e6e408d2443e50000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000600b6abbab461cfb072b267bfc1ecf8dc3c943736341baf11c5c829e345c49b509000000041c1b17b2cb59cc2314fb65fe31dcfdb1b014630fab522a263d9935601ff78a5c000000022d02c42204d7182da24e9ca1e3244fbff1e00efb8c85ee3a1ac9488fe2e3aa9d000000022d9b8d2353587ca56bdf967b4bb8847af3671bd6901e9e28f82c240c6e33129a2fbbd267a1c9b23b3ac1609b2c2a7961a0338c56d62607d5f8d6b6a29e7fe4cb000000101d223d0a7bbe8cd9eace6507ee0fa9dbf84565685a1c6ceb978cdd46c47025ea00000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d00000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc000000906eb2b444212e7fc5426b585fe92da7a94010f06dc82f8ae57dd4dc91cac317e141462fbe15290e7da75db817402d54bb34c3e36b82b681103e75a06b53742b0b225f76d3e207d15147eb3fa760d364422d4bb6a9ec10df5ac9b8fbedada4b6f97045637edc6c78f389dfd44a466e10e2cbfd84b112515666452a25e6877921275cc60bda20061ed54e6775087bd44cae00000090b3f361eebad14c9843114c3e6e2bd810b17a1381953eb6cbb0920e5412435c42cb36efa2ddf219d289c394700893caed500cb13b1d5724d57cb97922ec555d7fc40c94889a666bced531fbda4f9aff016a6b4267972abbd9f60287f6c1676f6b2b20577f3781e34a8cc4dd36cc6e2725d1b8f6f9aa612fc43358c1fc167a56d9bcb3a463fb9abf152723c36020393f5d00000090e084263ed67cf75ffbcf9f9922716125423be3ae02c0c3729c564a7d4209afe4534a20db0dc79f85a69ec8676eaa7b094857b5af72dbd40346c7bf2f79cb39bbbf37e977fb595639e0585abc2bc6ad67b097c23a286a2c4c62380ee2d496222ddced1e4d329d5fb47a9545927466e8c663e2a559d4fd78af3845efa3c09ebb3d6d01582609371337d6d83ecb704ce2e2000001bc00000090979ac1a9ccb8fa6b9f8d1747232ea8e8864f3cf83ac87f780d923d33e97a85f6265276e47faac640a966272722bbd297083a0c65244eb2af13e1606259957c60a88e03366a96fc328b0702cd760a399e1c3a1aaea86e4dea5ee70213ff3cec470cd54c52097126ba8556b129d085d5e393c78dfb03b4c3626a77cd5b0d2f42acdd3b5e975a06cc2582ce355071364a0f00000090359b86b1136c91f98136d693ca665141f5f7adf0ddc0b3d24ebe39ed6e4e41b9d239e64256b0609710419eff5f183af46cdb7407aec40ff9d3d291befc3e23e65fd6254b68848954eee73e0ff6964789f04ec290cc99421d4e0e56821a8a312a67970a7ebe83173b49ed73d8840b89a9d9cb0dc98fe9f4feaae4fa92b060a935d8c1406da1a627653baba6a8267cc62c00000090c194828fe951f3090d5c36d57dbe3998258d521b01ab426864e64d06e29e126a3ad8bf44eb471f87b57ab7a4ae675696029cd9ebb22d0531b43d8768a2c6426a1dce65ef024e065ea151a865b0c85a176d8c1e6f882fbe4d67d91820b6d412466f0dad365b4a824700c697093f14e8dd6c6262d7d377d014f64c941ebc6cbf9f6edc9d695fde67204b98c24c4975a621000001bc000000904bdaadd47d29131302d4a29451be409a04d7dfef42764e84acea034f5997dcbe37cb01583b3e82cb83e5c6f66818dc340b00d9e3a89c9b43045a69ed33478bf28bb11cce3ef0f7af62f96b40e80bbba69f3672751c10958bc365f2285c16012675d00111f440bdca78403ccc5411412c66e4e4da0e786295bc665b891221254152b8af23424761cdb74b45b4a9da854b000000905ae0304af7a3c27c9ea281ccc1f646de7110b4c4ed43e3739324c42dcc84d93fc6c6b4325bb3c081cd7159315060af0c6b2d1e60956ca9210ef483f7ec880282606f8a6ec48556f3badd07a2a0859bade234daba4801ca7c2b55766a4e62b3492c16e2b4077dcbeb2a3cd33fab95774791d743dba7dd5572d76d58cc65a95161d1c46fe75c05ba2cd1e8a994d9b2caba000000904314d956bc3d4990810346da528a4f7af2994e5a41e969346e41617b8a6cddb91268f8f471847037fc84388c60eb4cac3d15e774a3e243f151cdce2ce60bf348b1fabddb3adeff2f669172cd67eebd8ae153423391241572e335b54922c21f9db35c717babaec2c746ad769603696eaf7f4a7037893de3c4a2d7afbe6f8374ae39f1eb65835c02e41b176cde83fbc469000001bc000000900d2c37ba80eb50fa643e8bb1b2be6abfcb87e67b9a3199aa54911d35fea3f6e918b7d19c876d978c6af8d9416d334a02a380d5067d016d1c38e72efdd1dd82f89fc0ccf03ed4b02ecf0430f19c8f7d036a4ca56654acb8a6cca6aed4ef70e69226a73ff44595e59920650a1b1c4507efeb2540949a053bd59bd3225b7683d04eb845e22b4c2854f4ce3ad69404b8517a0000009046adc2c903a76594df533c486b5f0213e1bfb5ce70b22034e328d2b40b0c3126919fde6536d823bdd4b6429e3418199c5cdaab29240d4bf6466118f526c193d3cd8d7e9ec4e829271c230d3b558c8503b1e22d71a9e72473e18feb31ca5de0d9d57e77fb27c8f28c11b5e07dd8c2254540e3ea20650ef88d221732a4a9164bfdcebfc77a9f2badbba68231f5ef4ea3040000009062878ac127eb51ad6bb82e75f3d0d003c664b2010bcaf68e8b2cc6001a8911b57ac81fa23591d33248c0babdc70b53f53955ba124a852dc866ca6f32db37a4fcb0c39309e80f73c59ab0d76d41671aaed89b54ed6a85d306cef2c65afc2042893d6f858f8c5555a4e64180c3629acaeb813598f7b08328cefb69b413d5583ac0c4c5571e856bf556ba0c01d4af59f5e7000001bc00000090ff2435a0b914f0faebbd91d4473d7c139e093fb7fb5a7fbfd3976a36731bcf8bc1ceee34a855f3646e37f07c05bbfdc304c8b4e4105fe1ba8f620cac6ad84344ae67c9a98270792c376248abc54a3887fed1aa32da71444ef85cb0c5bf6754d067e543b18cfddb2a2bf05782018afc649a8d40cccc2cef80819321359ea87ed2840e321bafe6f6df4ce11895b969230600000090f01ef0a085fcda6760980143ece14b530125bfcd9c38b6ca47961cec36698d684a520168b9092ecb88d0384f90cb0262add2ee8a6c9752a1dab7f73738d95b87c2f4acbc816672097635bfe14f61937cb5baa0574172a2d84271e6c4dab145c3fda63e7099ea0e3949af3642e6d00d41c19d3d48d86455e6f6f168d9009d8780e81d3f9a125f360079aa0ea5774e44cd00000090303d2297696cd74d806fa47bcb234b1224a624737e75db864007d03a4d006c857384de3b141e2f0846f2c4cb2ff4db2cce6d75e727e02ac0d8bcf7185a00d7f177bd856967359edf67dbd6c41097dd03bd51d1b5523c54c2794e4d1323f4ecec113f36c7384b14e3cf95bfa98ff5357be32226a1825968b50fe076821f5afcb320c8ee22da0a669326cdee408481c431000001bc000000906cce662bc89f0e2bfc073f7fb02b5e4554c04245864b2f8602b3b5b8ce869b0b80809dd2abd376f7689aebf4eb9a9ddf4c1b45204f38eca18d00c03a6c1a7ee006b51552f21ef587bf99f532f0b9289f8e9378a8e70c04affcd6653339149435f6392edddd8631fe099e48a14a3f714a636a820243919b24c28af14eb67b949b3efc7bb1fc8592549f7cf417596ff50a00000090cf301578a705479b2c666d95ba9c33e6b446216ce84ebcb5c692cd64b70b5ff911a6a110725e656b5da4f5559c3fdbf660544f979fc6afde525bed51dcecef52e0d7c786c10dae116109ac08d0d42cb2417fe2e221cd8e195f82c859713f535ac972c169759aa3017a916cade68fd0fbf12ab770072571828122daea5e755e47eb2bb9c17858753d6fb7b50465554a58000000905b43550bbfc6b90c6c71e4e852d5c5965fad0bad906e057d7fce52b4931f46162925b802d2c59930528850130a421e5dce1b5a5b31f9dd5856dd11fb1265b64e6df9d3576b9b1b5492752a39f0941556df29a41d1ebd53b6e3a4076034b2b22a4572fbb47811d8cec4d811fb2f44ecba5c9e31ce6f24de219646a85d9535317828aa378309793ecf6d3955aeb9fef712000001bc0000009002d5ac96e04b1354d51222d6d525e6ba31104b2d19e076f1389f8a6cff3ecb73dd21c8161e41b470bb995cad44e7a4f4c61d0ae08c6acb6e4ec4a38c1e4957fe7b0f385a655164401c7a4f6e50de8c0588e83d37df12b64a79acba23f7ee0a6a0a7818fea578680d50ee7e289d911617a42f9728cce2bbc7f4a2cdf22f3e64dc697871edd0c33ce1c9b179b793a89c810000009006dae99b741eb1404deb4f716aa6b153d9e05ee4f1ca76b2495d9559b1d408939bac110c8dbac10957a5f709367885a802c9df7ae0b4dbf29b74e53b1d182639d2ed888a4e8c250ed8a6f4acefeab665e2a8481da550dee1ced20fae158e99d993a034fa78054330793a31574fc1d469b6689ae9d8d54162d82a6982f4ebd239f152ed0c53f962cdc7611a298c1d1592000000904ae4fb51433228123b9b6110d0cf7536ff9c13daba8e88ea129e44d451bafa159ae0c73e148f91b0b7f04e43230dc4860532d8b1bb623d0ef7e5636ea43fc8edf5a31135f50a0eb7b57a0a431c3531a80d354f9f199a9e36ce690946e8ac360a652b68c56c7df4ad623f10d99650ab6bdc95b401657481352a4aa5f48610d76c236f78b2b64e9799a338a7b18993a625000001bc000000903c5e8cf037296bef39b34178fc6704de6be6b9c4c977f13b9040a369b85b7579564bfbc3ef32baf2d59d016be685f44851f43ec4fc7a39417e4bc16278193c97776bc2bc06178d5dad9747e5a6eb8283ff8b3ac8b11299f8022ea8afedfb356c814c3cd9fb989d851d9e6722382e1b184d7fcae98f122dc70dcb57ef5536850a266c6c3061c0bc501a081531abd0335c00000090be24b50850949a6fb272128474fb4c9e44c4e9f21235c43134f06e36a8d5432724daf0258ffb72863d934b189725a9fb2ee95dfacc5d5568d0f70b7de4140befb4496fdf54e02d215e98b06b0fc32ad6ec2f9397b324c153d5d3dc88a988308460fcb61192b89021848e19f0efb11f6de7d9a344d696d292c960c567f4e2f3f3a45d30c7fc1b28b762476e613a45bb0500000090a58b1f5a78bae600267b40964f867160741759b2db895253e6629306741e9629a1d6eca76350864f297ca566a3ba2c707e3f7ac5633178a517de20edf98a9ae237474de5012f88ab0ed68ce79ba0cc9af44313bca966d78c44f76798775ab86123a53224c43805e4d668574646374c3b5d944a8583bbe508cf6516e68f5a21f1bf5f591fd1e965422ac31a07960249ce00000e00000001bc00000090f9e56638daabd6fc1023090b32bedcf471261843722a57589df71ae6a6fb9068fc9f7fd1a2746d7a3696b7e4552c6a6fbf8a709ad295ea66afd3201783748f5fec2ab3f2516703404e1149360415d8166646796b117adb6aa3294c81795dddad2ffc84d88828d21a751619c15d804dfa695b23298f03b1ed6f0b1b5aa5076c284fcf2d268a181c195d62c83cd6bbe15800000090ef28121a593a23b9575a043dbf21b4f7004de19f7f9d8b43b8685911aca0728843c35ea6ec86bf567e12414e458ba0c4eb73ad926d1c9834b0fe095cf0375a736a131bcdb899c59c46c9b6323f8468b118818e941ceca4af4b1235f6eb2fa0d1e9b6f9f5225a424fc95448d3249d3e672fc868b5b9cc2550f0b63ce2932a31e1c15fc4c8bcec304cd7dc5c91b21197b200000090e7812aca513f0efbaeb1f26d0dd854f2d959e8462a3df8510ef9151e027e4f6e0022c0fa5a5ae9b2fe2b07cf9737d5d3e3c14302ee2e0b7f94fb7c5a22b4f0768bfe97c8f292df7746f468569b93071072ee308dfc981df098886e07495f5545e69f5566b6b2049cbce7030decdb2b5cb7b41f0b6dff5cccbb90321752986fd36856a38e466e521fd4b2e0219dc11200000001bc00000090af74c11a88f7c49a1f09874652ba9ff762cf886bdd68768c15dad92b6f9e121e4337f607c653ac7527a675c4ae43fa036b11b3f401c49b0bd4b6c30e21d20ea4145e357279338288fa4f91ea704e8a5cdb739226b24b268f842c062554cdd33272f62fb85bc76c9545a9989dbaf9b7962c56812b8a972fc4142e97d02745b716576ad36e242813eb32b0d78a64a1fba2000000903d20a276fd09c048d101c8d78e69ec6ca4055f68e0b3ff07fda4cf6bfdf4b0be29d235a77951e58ab7c184554ae31f3e50331dba55308646321cf17c473cf2e8fd37f08cc65451a3e498d22256855afa8f1be99c5d7023363fa700f3acdd5a354035fd19633197559766a56f49222704f16ae8755e01aa305077f1ff2e1fb381db6ee2d45d60a2daf03489428defd79800000090561ca53af312ded7a6d1a45f6d93aa1b1079f2de66713b4a6a2c303ce78fd26fe6e9bc0f61b3a86a82e95ff52ea020a581dd45e2dba70bf76b474e752c260fba9b676e9dcd0a84f9aaa993882d584a0aba6282985a46eafba41305ac5767b163ed2a590d84629bc3d402b21f4c2ed4621dbdc432ffab8b2b4591d7ef05bdf11c0a34f9354189dbbd779617c765073876000001bc000000904ce42b5eec11797c1f8afc79114c6ea9cedd82426075ddfd8a6dbbca559c60094fe58300bf1a7107370f8c6bed505cd3bcea1aba6dc2be4367c69f1f79f45514118830b1424fb0e8ce93de8bdcbb95280169924700023e4f98aaf6419da9b08cd1a792c726434a03ef7b3059c4757d6e3e7328b4876b13bd0fcf7dbc7134ec3d92ddfa8846d014f09b04cf7037b901f90000009050b61813c794d0bf68daa228a05a5f6a95456520afed8a5a0c07ebb4ca7242a7594462868b811c95d65bb08a3c369162f6bc6fb1fc8b9267586dc03f411953e700ab00cf55764d79f429d21fac45539dff80233566854493d4159e35cd15d02840fec6cf5eea625b82c390df073898f3854f3c9f19d14a3f155118b91d629098ca8388ad5f260fac5dea06a5449b917a000000904bc2c01e9e4e3a2f2f148a881b87e635785c7b440d634a8ae7f894c732aedeb8f87367117b6b5ebb585282e3dcd53c42362c962af14bd4e370133ce2387ecc5102149a62089aeb02c8ffab68df211bbde384d0d9d5325c8e85de847b5d810eee257d18ddd970cf4ec90396d34725f691d2b21e0b6ca8debb8c2f894980ce2db28fe97c8c00d4182346cd335219d8c014000001bc0000009080d739bf38be185bab1564dc36940e345491b0ba1a0d519301f946ff88cd36c8ab9bae17bae9828c5aa4608851b9ea14cc6de10f8338bfdeef0890a31282fc30d1459e0f43c63ee33e150d9069b090b573857a013db7442b4147639d91768ce87a93e560dafe84e975f24b8967a91009cb5555fb2e3ca35e25ba3246cf307d00d050d906a8f1427da6eb0e49236e66320000009052160a2b2b01d3adb6ace0f043523e0baa2fee091941ff5b95ddf66db5170b22b8ba578f09fd8c8cf127920c5da841bd7c5d439fe6ab222ba2f7cbb69b0e34ca217afd282d4a1d85c76d8a108970528731c1e4f32703e0ee92410eedbd52d0fb7d2d7797c038e887d69c2e4016c56a4cf9a98df0fecdffe16be815b94b1a5cb382fd02c2ad91a49a5d1ec5882cc574ed00000090102ef5abafe1a801f359491349a458cc2b0bc567c7752fcae65a0408230fbc88334098c5c8ae4cde42d383eba6832d71abe6f4c450f5c14b6f56dd9e0c02d818d912a893ac1694dcab0cf9ec29fdb378b95fa3179a82757312ddf0d7852bb9f1a380f20e8851a2b7313900fbea3e07a3ae18e457ddf5639a0b1f3e7dbce05d8e42db93082774587393b3daf59ffbba7b000001bc000000905f9d5406ea0521e54cc2918df8c5b6b97473424f4d0107a32d0aa31ea5453a8bed2f4f455892d61bed404080577e7744bbcdd880f418d4a091b9f8482514ad04674abb41585d5558d36c03be687ea2be36a493ede581eac13fc309f0b3c74a2edc152217cc24c45fcb48bca15ef00900fd62429786c725a99d1b9edb9b03bc7cdb177909c0a8c3e6822f2e32269cc96900000090c927d7dc259777e39ac2a14352dd6a3743403cdd15c154c3d44d15014018603356e926eb1efe597d34708527cd952eba7a9fc1b3c527427d4732ab4830cbfdb10f315e4e11ec1eae6440dc7f5aa4f53b95a2921f19be7a5f9acabeee51d7d73af893305bb86855559e8bf31bdf56cfe732a504e5b4a2005a75c607031da39ec02a783d92222beb4aa8c4ca142d33bb5600000090c1a905e2bb0dd6c444a2f3f909be4e7d338651ed45be1ee8d55caef42b1df59cc1b2324db5fc9c999b94e14b1f0447ce0a42443028e2207f2df5f5a87a3e2f44390755f9908681a74703197b78d7c95d1a2771e8782388975e8e0eefa35a14cd6ea38bbb117632e8d4f3b4ddcffe3dfa4d63b86b51240e7d7d10f437b9495aaaf1270731bffe191410f6a90668f09deb000001bc00000090bab929e7b47f9ffc56a6698a8586afb23a4aa1c135394fc784dae3798fb20ba90a120b82855688b82f24f1ed8786b6364df9a68e2f0798704c17145749e9e1e4be89447f9cae3a4266199652501f57a779ee3649be8adc4c4e515e2bb5eb6b7662688fef126aaa71429e5c7a06c831d6a3b4fe014084e76c332b02be583144528799385b1adb5a227006e516c7c651c200000090b97b9efef32a05892ac56dce7dbd53422e989e83691ca29d8b33c2be35873522fb4618a8670a13922212d7e552915def6c707d8c7d5b7bf2c27eb86c1745bc79ab35f331c2f7d47bbf973f5e4061beab3d0363416bc6d512f1d3bcc01fe8b2200d690392bddeda24b48651ed9fc04fe54af774b6a474e2b4726d50b1068ace093509adcac756800a16af821d54ec7d1c000000909226c5084e16e186bd9e541267ee3d429c15bb43dbf0b763b357d5320de671721292478be795f2161612269c46f198116b4fc074fa67c80f18d1b4e357961645275e12a098aa4c2491c88033e83cec70998c0490b185fadfd1a5ed843b1f67de377a733e70b96f9a283739eb6a6cb91e3a0ad6cef9f36fc79a8c137e391ad860235728abb7d32d359e61a7c81d1d5e9a000001bc00000090cc0215e729382d3444ad0f362c10056bf719c015218de84e473dc849791d970f9eef969e1e029bcf044160e4b86c8de4e86a615a8826a4337775ae718f0c5249da0b7ced10a9097a6f5ce151b7256c2a901b827c57f6f0ce0574c366dbc01cf1349fb660ad93693d4cdeab0936e38498378823c74e1e6c905d503609b1705481589d96412b8dfed83d65f3c6292614f9000000909934e72118bae1be1466cf7aa6a7fff16e7b7ad069e0803caeed5c89fcc2962159bc74a1ac5798d03622e679750b324bd7e046c5b893cfe79b91da241b65800d912434f58bee9fb242c4c99ddbe6694f4f0a8777d7aa71e3bfdf5c207add86e13d6e96b3998ca754b3b1ab566f5b72a8229e85ab4acd20574e82849ab399ad2bbd593a35d2fbb284522ac11d5abd3df700000090896c70456c2b313d7af3ed9a5c2c525bda692a4eaee80933d90db9e96a419f4f7c89fbe5d578a12ff8e9825b245431f76b851f33a8e353f3267f8252bb4522165b6c4bf96fa512302ebdf8ff64bf1cc283236e096edcb7d3b726f96bd1c7cb2e91abcc042e3ec5e06e74d748fe76b432fade0eb0a9cb20b06806f71415fc8a27e3d803bf1ba923c090b509dde7168318000001bc0000009020562ad9bf630b1d12fefc8c620f2a403f54813c295e87c7e90f527ab1a83f2ca6e9e92d4896597a0aebfb3f63059b413b29f61ebd672aee82b842cd1c41c6e56378c332552195c3a924a4fcae0616f117bffd90494105c3358d9aeb389e1350bbae80dfa5b7bbc7c3a30422f177eae6297a332ce4d78ab39383f8983db42d78f7ba2e78137dcb3bad3964a4e287ec02000000908d9737b8984f04ac7c553973a24c6e3b42c916e97512ebb783a07d7cc71f39cc316c89a37a6ac719a050e31867aebf4dc15884ab4aa256e3bd7e85144f9ffaec76c3dddd8326974d55b4fdb20c1d09818c2241bf3094744e5da9d95e931d76d896241d07edf58792c6f272c4b8e67530fe4f05c662ad8b3239ad450cc084ae0eacaea4c928a730d98982773c8a9cfba4000000902d21ea94707238e11327f310cc5a1d61bcf3b230dd8358c66534dd1e61141a3e8f6eb32018fb065de3e271d2f58e93a73d3343ada4788dcbc38458e908a3236ac828b6260f81ba94e4dd8b361c695272575fccc0dbefc5c37ee856177898dfc6bf745e8e856e0bdc0f8ed1460ef0d31600ef32af4a5efa05d3c1dfc71b80087afb2c6356354e92953cb28285632a5e2700000e00000001bc00000090b6b785a893c9c0c4368bcd283bd218703dcc8f2ecc9f721af430d61dabc087c4e0b0c3c575b9dbb67bd9b18eb7ea50838216d8fffce548aefccd802598cf68ec879632163d9d3f424f5cde402f2e90c6aafdbff67f1d76138bdf0f07aa66f218d7fa82d5b71c96c428086521f0a1b3d99f6570c10c1570def6ebb734ce38fba2d31df12e13fafea1903d8059cea3b38a00000090379a72abb0a5df1331e887d28e17eb23e3868c552d316db9d6630362d9a9f0b18eec57ce9854d860a772b2b25bb7138b79bc060c7d426c6c08b3c850d8db8d96500704f9b43ee791c28c24ee4dcf55f66f4205d46208f33365f534f4d24e0240dee79567fa3959bcce06b3e4431d6207a1a01c97d3adbf3383c8ef83618bfa92e87c57b00fc5188b9092bf5ada6ce3200000009057cc225fc73ba28aea06a45d52d711e347438edde7f1cb29eb308515818601cbe5f722ec0e59b1be58a2db33ac0740bd9c726824cc807a0b6f84817c61c339c2fd95fdf0ebf4d31b3e713ad261bf09745821334d718216ea8c2feeb0d21e31bb6f695b6ba86f8ce95af1169727d3c83434305ebf2a5800ef53395addd383aa6a860f2ca133e7c173a02807ea8248f5d8000001bc0000009090438b8cbaa0fe2876ee6560b32b396f688f9a76e7968d1f81350d8ce0a94e0239940ba0c1a79dcff2e7b0894111ae4969f5b82a9d602fba69377f582be4ba8d1dfed2f84574ee6375c6317f8734a547f6dd457c9027e32bb9c807fcdd23d2beebc622ad99659610852a3f3ae3cf55fb4e5689147ca3329931df0ba8d69f44f9db5a2eee4fed51b3602d0ddc2ee2e1b0000000904679f91e736276795fddaa7f672ee5329fb2b2805ccbdd3344ead6beddc96e33cb9ecfd683b9f90997c47f4fdb8d1aa34c9b2e259d778956736a640cc6b3c49f43d012682b8966605d17066d490187f9fb7ec62e0ac58c151365ff968f5672ce87f5152181252407d6cf5fcf72aee330382c05f284c9bfa40048726d829d715675b02b1bbb158099ed76de7732dd87a300000090171df1386679177b3caaf165a29d44b91172ab5ba6e11e73abba018a0712fb7216150d9914802d24af90df73b5d10e5cfeee085ba89dc862e131675351e2fe066b5edab3ef380d47c225134aa6696c96fc979781acd6d92c1bf1d6fe5a22952fce22b40f9abab339e8c824ca182f5b564f852d5022cec42c1e5808063cad2c0a6899dc91f4b4e0f014d41ecf30b0733c000001bc00000090f73cda38e1011799114681aec8676d15cf04e1996f7bebd9620b3899d2a88fadd31bf6c00de4b90d3d33631049e855eb455a0af7b258a3c87c30c737972ac5240c474d9e18fba22dfb6cb19113b7af3646fa5b0c4cc78129e064ed53a5dfce38aee2cef0adc1ecc9526947508a0525ed50dcf5a64a6a34c8035e46f154b3dbc91d3b62396072e48b7927ceaf80a948a500000090a2c90c3fd62e6c3b9236753c545563ab765db750c0d46fb03313eb289c16e21800ea14b8461d404ca2a3c132e15a2eebdcdfda6fb26a53e1c543a9c15b223533b1647f7aca04960a0fe6f18ada9dd4013a0976129cfe596f6de5c0eabd25b48b582fc782a503ba4ec03a1cc0e07213b9a43b13551261e65fb070f85e226b2521ad441db4038781eed1185bc63ce3dc7b00000090e4da73a3e62cfd1e71baef3b802a0b10ccb723bcf26f6115ab679724e6e08d1a589baca7fc9b1088e8bda527540e3d2d37c06341ce746b8c4f4d6133375f7fd13d0ea62b1f99fe88b143a5731be5f648e8db78b0352b87bc7c114676ecbf14790f5e328ad74e914ceb0d87c7dd9908a8e012ae04d037bc0ddc5c582cebf384aa6553fa166b8c639046910afcbd64ad68000001bc00000090857e1aee424f91f5699f41b2b6f3bf426eec3b2aac6f23f18df162c275c5c981a1f1c50cdaaf71172438bf825711ff7ca25c98e693027bc89aabfe189498b4f5a3fb62aebe2428924afd861410d87ef97254e972470c67f4d60a4c4ab6f3619b151ff6384b4d969f41f9ebc7068940b006fc39dac0c91cc0e867a39bfb65b855fa75cce185ecd028ee9ec9e79534a9cf00000090167a6241e3a93f0138b987eac85ae919534d16dc9a80bd86ea97ffdb0b9b6042d75a6fd0db555bb907336f013dc8ebb30c42990c97fb0a770742fb27cec4e37b909788ce1338151890dcbcbc8c5af9916bec77f98d4cd2c358a72f3662eab1dd157fdb71b58ea8c95e44c6f6e842c107ea4042fdabeb88cd7772bb01939449b3a84c95589b7fbfc8b65275af7561537f0000009071d5c3c0bf428b360fa2d5b119e112662503032cddd90044d840d6230cd305bc1ef5629c4bdc326df89baa9b27f8ba45d932d8b193c01ef48659a4706c4f00ee893fc062155c71ee0a07d964106e57f8d4fa6fe30b75d32fc85cbb6bb51bfaf86c24842d317ff4fe76663ab6ab358ccd52d81d4ca5e1f51d2c63269c1667f6788d0a2ef5abee5676692c32c63eab63e8000001bc000000905447d0488946ca5c41b79d52ef05da1889d794eff409b97f7c0ba11327cee35fe4481a454324cddb7dccf17ea311fe6aaf0d7d5a8b813a5ae9796eb447b4e080e5e96420503f3ce734879dd26a945fcf3c0517a8fff0501034a03c12f8fe328dfb4179db4e9ebba66a1a4ec52e63c149159d0c7d85390fd7b458860afb0706bf6a9d4b4cf7bb519b105dcbdb69a8e47e00000090bb17f41eefaebbd2e8a125e590260bd565dd1160b71761a311d35e1fb466be6b4edfe197c926b16b21ec942637a24d5cba7b0a97ed452c8abfbaeea57f84f9147d85059d020805dd39e9a382707c6c50e3db9740a25c1cc806acd0f2b3b348732d0b40d230efd56be31b6c14c8db7f323872f465a8c8c2883d802b537cd033fa22dd2d94d41dffb719209c7066faf76800000090fb1d99c034031173cf99df92d2c1466c06bd9fd2ddf61d80c7764ec2e9b3fc39e3754f8385d47c7cbc91853a2e230d68c43ecbcdc05148c54bf4bdd589c0de19234f13628c5173e59e73a21009df9cb2ed5fb9c2f572f3b6eddbdf12140f810bbd0d43b740b45f16a6571e3890b7d0daf91382c6df2a6cf694f755a3a54f2ad7d4e08a3c34d136981ecbe959a88a10b6000001bc00000090394bd2a4044e0fa016de48eaf444b3166f1155216741ca6cddeb4a8635bf438146dc5d98811ba76954928ed4aca1ae6df227525a888987d4d8ba94b7c8616326ec01b5f37da8c4af05b846737a1ca500cb2865a53eeba6cff09cd48cb1ef61dd56adf08f0d02d6cb792db82dbf92b24b4fb3e6ee985fd11f2521dd4eaf6e208d76998c8d8ee2bcc58382e8e403a6061e00000090ceaebed596c0d16e317d6bbeefc1256611ecc3711ace9376cc4204cacff94326588f0f3114653d57af1d1c72ed28462e6820b3fc7392131938b575e04712c03216f04d2a8fc6d2413ade9058dfec7f5e36cc943ab8a741873017c17c57869929df35739e7b7ff6aa64182ed1d21beecc3c7c884746fb05eff157a60c13da5a04ee701972f5103422b5b20f875ead5fd600000090164177fa3d9453fbd6c7cb4884d3b7a77e056a7e2962273c809411486775c93e06b6e2f067a1b1da7b7deb8d1cb1cb3eaaea0880d2a898591d12e6656c44db58b466489f58567f88f9d5e1f19c26935fa13fc182a358b7067af8a9fad9265d3b05f1220ebda17412e2a5f579d58c7727d5d151d99530c5a68ca290c6014ad665eac46eccf1dd4beab4add602ee4a0b3a000001bc0000009013f0191618599cd9a94329b8941fcdac9e8f2c843cb1ad35077c6312c089d53369b012990d86772aab4184f99dab44d4dabcab6894c540ae40c03f3c97f0739d98dc70c26f3b2ec3ff78621f9e255f095448117aae033cfafd752da06b13bf47db123018a68019c84ea43ac1d534fd8b6ab5b160d5764d920cb896c2ccf492d713d6495a1f5507d26866b8d8ad24fe8e0000009088a2599f38885350473ee05bab6679aec3fd6753be0b0029d3ded6f1a7d781e6828c47a0c800da06454f58c27383aa7e6ca6dbe57453a74ec6effe58b52b0b36e972a1fc5b3d965f8d849dcde51921a6b0755e7e3dd1cb7ff046cf1496f3dded3bbe5bda67b253d6e09ac2ead6ae8d7c2b763831d67bf238756cf9feda6a0078dbf8404268be7c950a2be61e1726ef330000009094d580c24085ec765663c6290fcd6b482893e572d671dd593a8ac82e50c2899db396a0474cfa5ba8d6b8ed16dc32f95af966916ade952275b586589a81d0c7fae4462e5f7569002eee9e419369dd1f7585feab27fd512d387ec76c4a38a3008691bb586210d1f006aecf9f5053362341994b414a0afd445c9192368596000f3528002e99747a94749be62520a9941419000001bc00000090ab299d12da5d4400c0fb7ede1ce9a277dfefb8ac60ef4822a5d3f2e2cece137e0d386dbfc29d9e612821b416028b692eea91374c805d368c233bf6acb49c8ca1d814a95863ef18a0aaa6351550205a065010b875e2802729f30777c6442a9f3a725de94b37025c070de6ce4ec381e6bd2462bc35010939e34a13b802cb58455ea56c994263367e6d9d5c30c94fc3cea10000009085327a7bde96de64cf1ec0dd4ae3f6fe4893bb14ba8a8f210032294c990cf6b8532f184c440f93d61eeb66b7f8f4900026d77e3c7fce28e5e8479aaccdad7fd97792199b48289ee96021f658f9542994ca61997d4e3ce8de1ece2eeddcc76c745b4de2a263246f98a6c120d4c896c1cf1dbfda47b149f41523a6ac90883c32d41a82210ae996907d5215f87c20010a4400000090b9297568777df8232be5498e8608b7244657c6240ec9b869ca97ffbd5cca719f0a18759e2fa4b37a7cf41c753adfd4a4803e2c9439cbfa4420776dba88391c9c5a18c05111fcae73dc406a731e9d2296758d195b6823c5853772b44583059794fee392be61e2523602befa969cd93915e2a2354eaf942a28dee21baf732016656ebe18812de6682dcafd4b43a5ffdb4c00000e00000001bc00000090801ef9c2577ec82636d3cd9bddf8fe9faa1916f076983c1eb61db7cdf5284a554b54c708549f4a16fea0a64a7509a7656d7ff04c0b6dd5b92b76641930d3ecbf22c0c96082a97cad9030dbb6287e5c4c9ac5078e55f4f8a1bdcbd55a42d9c882c1563509b06f4484a793be80ecfe0e42cd3acf1f33fab869b03690d0e2c8995e3fef9bc8a02f4cb7e9d076ba2cb0e8aa00000090c932ad01f8bf981f307cd0678be81a254fcd35fe1dd01d89f4dbc1a08aa1b6d7821e4599904894618943195181dda479755864f7bbb228795182ce13ff45656bbca9f56112e7d630bd48f8490b013067141e69379d4ccc05f08c357f8e54b10bf8ac4731da861cea9b509b90c0f76fdd834371a2de507483b09b9d402065fa038b4591acc7c3a1726616c368d64ef87600000090875924116fbfe13068edea36b4029e0f8684bd7921447fd7cfb85f2ce489b755934b81eb2dfb0d318cb390cefead098c670756c2204a29d8b53f6284618638950529a0c5c6bc9e927efa083b460a275c69923a91038c0089470cbdab7fb51d7ac7b05e20bef690eaf28615d5de31b260257239137bceefac894dd3803070ebcf0a743b06accbe856b7785d0815427796000001bc00000090c1524c555d1de312b4d6dfd4498bb6f0689f10df8814c31dd2cc9f9e47cae78f4cf612c9de50d777cabf50e738f3076a1d4464e3d51631f72adf16337c02d58da83591df58291f8edc2055376691623215a04d791b2f70d724b4999523352553eebeb5a815c66504d1f6be97ae94c778e606d4ff110fad07a919469eba144602ad947f2f1cf21063d666f700bcdc152f00000090a4f0fa4eda04c3269acb3b63bd19447076a8df4d3c7f4ed3775da5c54afd384d84b0dcff3a2afc5dd9d9c604f0716208b997a22a7f0ebc3794dee40ae80031b4ae1e695636fd8675eeea73abe669097e05df866fde70faf4cf15c9d9eb01645ffb7fa40a8ec963802a6b838b47fd91466c838102ea392c72d20d1cd2e2cd525be013551576dffa28bb6fbf2bde78b6e20000009031a6d25d6b5bf8d27fcd97cb17614b487ae1fc7a3296a0e56c34492b7cfe3b52d542b80b0114fb19b7527a8b7fc497a0d88fd8e29e8d86552cf56e773dae95ad63502b0fd6d487cf69b9c23b808698ce7b707a40b5b765da987905f0979b836aaf6fec136f7427c9f53273c7145c1cf8236f43ea369ed0ef4250512935073d11e9f1a2605b9e6fdaf9953c89ebd1296a000001bc000000900f346de1f80bebd75770adeec5e1b40134cbb2c6d8f71bcecaddc6a162646a7dc1b546e104294f9d399e0b07274babe75668f43cf1bc1390c6c7f03479135102d76810e3006c7a1c5691a677f441380b3749e616b1853ae1086c2f9de1ec1158a5966587d30fc7a062a98b77de490774366ac4bd55176ae71ebcf97380e3458f99a64c68858d9a542d787c419407480c00000090afc3a982e9b18074b18f8e9241af438e78e8ac319bd7db91a3cc42b095e12a18dd961b24b8c863a0994234adbfc2d6e7483a79e4d54481048d90cccffc9465218ff5f5d901203764b62af6b4db57e2602543585602e1f94f4c086dd69c5c9b37edbc03abffdfe322f353c5abf54ce07eb8ed5e805a5bec7d59d15256362230beac173d50d74e67226306ffd589b5c0d5000000908c9f222581c07fb644955af88c1a00a64c28e97433755fb8d2b824a045ef3ef9718e05c4ef36217d6bf5167ad0a5f17798cbfc967d8db658d369d2ece607d90374f295103ae9d79a0695c5def30bd3a43c4e04d2d915f347f444225e75f01ad2d68492efd52ecb47064ff9632f5e47a8d35122a170d5d95428aa035584ea80b6ffe3e499ea40492da1d7e469a030ee11000001bc00000090f3aa49be1ef2da782a3a250d14a09a4571b0b2875223e27ecf0701a757e03405d9ec08c8bb839dea797c25693021bb0695d2e5629a2568ddaa8d79b3316a5ff059388a49c33c70e4ff39cbd33dde9f049c3a9aa1dc9f5c0d8143641736d572c1e3486a58835a47adc0d8fb9710f1563229892d45e055aec29e9531fccbe7b46ceb68ea5529ebf9d415a5dbdc86bda1820000009030629b2f31fbdcd559bda5bbc841d7fc7127e1fdcd05b92fef2dd6172ba516b3712c6c0919fea5c19246b15f5ece0e66ee60b84372b840b1e7b8b7e710f105b3406e167774acfa409263e612b92705475118cf88bf9bb02f87bfc8aa22602748f8b4dd0f60ffc56b4569ddfa8b2ea728a18f6de5bb6f67f302eb8284f7ee74b6ceb8343b52bd1bf47d478b3301c7dffc00000090219a86279f2a85edbb4d6f8431b1add2747a087197466d378490c9193749711b0bb59b38cb7fd15898272ca2dbef517963f6086978fda51cf685209158d6222adffc82ce8179e30ea9bf2661e10470f306835488e054e6b3253f78a2fe6959979ba5d7c27e3ce187fc6ad8d39e0575aa6ef7be38938bded99f596d09671890fdf64d98e4ac0c987228b144dcf6d3b3d9000001bc00000090b5680313dd737e26fb80af1b3a2652cab7da5447292c4317006f6699ecea9c48ed7cda8733edb6ceb0467610c4c454eb79779920fb67e1658e5cdbaa43780e0822997aa6341347fdcaa032bf10afc63c3e32c4ab0a79943d9069c2ee16c1ed6c0afb61b3b468e2dc389dc5255e53d29576e823d8a446c27146cf9edddad9cf73f800c123462852b2e5e4262db101a13400000090539c18db539b56c610e0ae6e65aff959cbbe87a2d1265e9641ac1c6e593a61e5430828e9cc6959ba079cd68372f5ebe403db4b3a765e6596118cb67b36ab498e09592873b5f65b5adf7ae22bdb1260a35d66eac4cec5ba2f25ea1aa098a014dc88b399e16d3bcbbdfba407ba23c652b8147e044a93b354b46ae70ff0132864d5da00cd9e3c3a3d3726698cd46813393800000090d689249495b3e90523cd0c7cfa1acd98c279a814ad02cead5651ca56edb9cff526005591fd5c5630035ba8383e59e11fccb45700e3f0f185ffdb7a2d6980e57536dc68d0f3f5ea5af29e04d3ab2a4cb396c6931839b74e6f516c13ab1c1705bce0c8bf55ac11796c0feee88162d3ca18daeb835c13d187dcf4494f582d5013b5b36cdfe0d8a01d2303f68e406643922e000001bc0000009033c59257596f42bcd14cc4931da340546eb7ed481e505983ea174a65f337e3ddd8694b4bc91fb9c6aecc02bb26bf4be45f7781d8c71268b898b0a88ab612969378e8746ededd98c2bf384005f182c002f356dc7e9f441aa18638f7cb970f68ff146335f746322443e427e941d567d8b2704e3369a4b7cafc3857e8f36fd05b3fc655dd4768421fad2db557b6c7c4fc4a000000904632ca5761f5e73e9c7c833817c97164030c0fa8b96816ac0d0240256c0b823ad8f114c1bf1da4785232cefbbaa1eb5c8e7148d795a8507f1878f04e61bc372413360ec0c89a590d82f66db9a7da440f04aac88af5e636d3316d211f44314469fe2bf49a563f73d4bf12b7b318fb30538c3dcbcf254e14cb686177c876e63a4f88868fb35289fa8de8a8d230ad7452a6000000904b24f06233a197ec6bad7cd38cf4bc9fd4268b7e1ec2e5d3e216b44c2fd39b7a091d74e4444021e4b2c34f7f6937c9c5eb60d20c2f5c3826ae13d21bbfdcabd5a1412cfb6e725ef24cfd96657034a248b4f9923f6e7ed377cb8082d928a0948f952eeefca63ad9fb5634dc801fc3d0a1552ce4d63b60f953c560e6a1ccc5dfd2ca0a91873b6dc19b5d16e4db432026c6000001bc00000090145a6a31edfe177e2a1f9722a3aeee99760da5a34a9b69ca0a23c351f41021478ee69c632627166c2e2bcacbfda3ed3e7274b0d71670bda552b51a53c98e334ef07f4f7ce8c1ec45010f4d875cd8a85ebe0af3c7644d564eed7b2909bbc7bfa0be1b43b65e660bd592476fe14e73478ea9e109473a89bce38e34a75d16cd09975a4043763fc1b17cc867e05888af015a00000090fc1864227ec8804b378b445c8d92eaf0935fc6e49a1bb5e62f5df74e576225a3ec1b98b06bff1ca40d896a0b3d1fd5da1592fb129528ba4d58f6f195866c7d6c48b26b475a0f72226099e52a51c2259b7ab9edf7765dba7454cee56064f27eeac649e798bb6353b2258b098cf8ba89f662075b9e3e7d5244df22b9a6f5d6c30e3da30db89aa20dfda1340667907efd3b000000903041f714a8934ad43722f849083e7a6585d66fddeea9be2f423e6d4f9a8b935d1a88c7e0394b53aac5bbe8606742dc2182be3e81be382fa0dc7506a120d7d832832b69f1094d04cd5b2c8613dc858963c5ef897758b5b5deefd5f8eeb76dc92dc996472cff8c2d8d2e840c843a7d7d44a7f7a7461b9819412fa8b93c1923b8a689ae21e8c6bc560cdc13455dd1ca74af000001bc00000090b3e2eec14675cfb9e6fae9e2839f095d822fd6181aea14152a4ea49cf7b89242da9ff57e0bf78e006dd3d83b0b8be5e884cee08bbc965f6953efd4ed3e86e25ea6048f35f4096c0f96503d21aa4990bfc28679707704e3b8a04be7fc25bdf4e509a0584c4772f9e08b1e9436ec371758298cb6a41a65fcfcdb333b12969e112ea444b6b1d1a32ed1f4498b1d3c8d990800000090f69263003adb1ebdadae02462f927195e4012704433ca265ae4302a17056e4ee1fde8ed8a24d804afc735761c06a5a0ed954ff73a9698e88aa68717a8055032cf0bf3d9eb51bf7c90dde3f8e351386c850281bcabe4da59e52582e05d64d74b4969e7480284bf8fd8062912d4cc469193ecad218a32fa941cd63761ed22b637a4401dd09847c9364389a8d780774a67d00000090e5dbafefb9b1634f77bb47a9183ede40562b5c9a0dc801d38d0b90fe57c0af4a5fa2a7a6fd5f079659e22b9aa6b79f9ff124df2ebba44bcf1942de81d7961420889728a12eb054ff6802fd4a20e5bd047addaad41b7d838cac5def04bfbae085b804c2caba0ba79df0230523629e59938442d6659a25d8a1d99e09a1397fa3768f57d79924ee76da4da67d008eaca622000033a000000ce40000012800000090639d486cdf8acd57ef037bd52e740d927260a038bbcbce4a25bde98af3f670bdc7368780be3cda17b9e8e1c825b02518927735957c6c50fc33f6083c635704a9cfe1d511917acf0f63b246303b2d782cc38fc32781d41e450dbea20b50c5cbf1a1b673c6326b538f94430f5db70085f3d9d01b328f165f0e790136b52e7ded86c38eeca0390ffb4463e537ddca0fbe48000000901d83225a50847a2925cb255c507dd38f4645f05d85941db543000b8cbf1252fe12a18668514c4565dea3f9b88f87fffc65a07af88a5f6ab57a79db7be69cc8d52a2064f511c7a2a04a85fff0e2688821b713c3994301835d056346690f9764e5a7d6991083b0484c5cbe7961f4bff6dc46658c8fcf3529e187d781990f2ad7459537733f81e8212205dde6a547409d900000012800000090cbe5f87209419bb150056d00d04fba5e7386c8d0926df7a3c619c1cb7285a80b542d105f55cab4a2929a1fa5fced09fd4391159d41bd97e3c48b8527f1a7fa720786f42e149ff3684b4602e9c721f841729c5240e02fbd72a69334f1fcae9925f661997b5a6f6885fb6fb35215570dc50accd2888b39a6edb340592c186a8f0c60ea6edb1c10fdecb84a6db4cab102f800000090a4057e4da28b2d51b0cb9a14ed984359df78af483ab432f408ed202c48c4b9cfe3d2bfbc69b3158ab635863f0cb918ce6f517be1a986235926174dc9f2e90752b1d4001accb4fd267f5ff6299d1831672848e7f17160c03364fb5a00e29822c884db91413bd63ae112db74a1fee36fd37709c5450548c1f11bd7274b518871cfc02606f22a0f47e2a0caaa158b4df7310000012800000090db4b8cdf217d4e8d5457bee548314bca5d7d83fc27aa60f87d459cfdc6ae82f757614de089da919dbae04ae77f9422bf1b008dce97058dae7a043cf1d9f82f6e3220ac8c8b5f1aced6bcbe786454e2156484dd8449e1633ace23b50b813d312b7be8a33c5e721730483d57a6a2ec3bb08da97a5ca5ca787ae34e4ffff000d9d001228941442dc2f3bcd9871a1dac37ae0000009065d2234018f4d38a5730ec5510036db0a1c6293e5ac5f5c97ee28729e2fe13357c1da0119880138d20e25590e624261b70794267f4433d4711adf2bac4c08757568c52d52e0cd182a40f3181a130fa4964886b5bdf34a102bda3b0e97830ee548a2e4ead76689aacaac714a62f640128165d477057b3c7b6c9b2448613c834decd7e5ef2ab4f50e9f32acd6d236a20fd0000012800000090a2fd7da86afaa8d81634276960ab4fc9b355c4fd2c3ea5114abe4caff0427f96f25cfdbee7cebf96d35d294b96c22a087c702a05914a24e5a115c69fbcbfd25e21c971cb3697127fdee46c11d4b9c30c2ce5de4259e41961522c4118c2ee00f2b70bd7d06c5422c26981683bd61a6ef754e087a9eeb53b16e3bcf087cbc8f390cfe97986f1ef6b0234493e9d8806275f0000009079d388084b1dad045b2f73306b13bf335be555ad14acdc26ae123224ada033592a2be1d2ad3a942c4c532ed1f0c1c1ca9316e10fe474e12dad4534eb8f4fa045803d50816bb9579304a7a00aef983b8fb834344fad8b4e572a766fde8676cab6f11436fbc448abcf88afad3969aaa988112a7c5b081416d4e70963f108dcad242fd5d15204d370b9ae2025c0f6faab620000012800000090e0156263f20bb92a39dd3049cf6f418143192d5904f2734340f55fea7854616030766503f2136688003134e058481035725434bb5a09b2f16a61ecd6f314368cb7e567ec36c42b17728f2d47d71b49d1853b4988d91dbd0fbabf36c98c327b19a267d56fad2dc1f05b2bee17002e3e00941af273c5e9f84a5cb3624a544abe94305c2d5e290fa0e8340a084825fcdd1100000090e755259e0e6fd3b0d8cfcdcc0a7ab644ecd780e405dc3996da1f784bb132cc34d7f800605d002a1fc88f9f49bcb408069b7f81e1f343aa1c6c3509fda4147b8cc2af53745e245f7d7bfbf177d49db1d6ffba6fec04c78f3556438ce455c18e9d54d1815229ed43eb4eccadb65162a90e0eccd7b628fa5649f3def35eb04361df8f863adb0ce47206df3b20fcbab8417d0000012800000090103ba4b387fd9e18befbe1321a17774de0a57791a98aa00ef7985afdfe51787931c2c20425516fd2474ad3bf2ea9a1dca54c7af84655cc99cba7c2bc82107809118d13fe2db6dd6e89304486c0ab9b2248628cd2a840cd379640bfb9c1125db845214c941bf00054baf2f7cde366ddfe94904277950663fc4ad23356875905a632d2f9b51135f6ee529fa7a0db622c8900000090a9f7c79016d72271446f8b8f28971a011db5e1c26dd313def999790a8b28b94165afb94360cc66edfec6afb41635cea260d3ecc87c0fdad7f7194e3b4b2e68b2ca1ccede1a7bbd9a1fa7cc75b3aea404052d0d158cc4be13757bc9f15c34f8326c2194ce4674fedfae84b0062f2fdbcbbaf3735191885d22eb23d7c37dbccb17c6c73bd6ce64e1b4efacf04b2bac202d000001280000009004bd547838a4f37fee8a1baefa39987c4c979636407bde403d8d4c132253e17d7a8582b5a0f883527c36c5b766b7e218e47cdf5867447ca50bd936c7d9d1443f06429beef8ef3cc0e3b4748bc87f65fc285fe5f34dd38207c9103418f9adc69427f697d1b2a10f8b80cd79224b64714ddfecb2ee3927a540bc0f14ff6c6f98d85397e4923c5ec144a1444fff4e7dc249000000905e80407b1c81e498717666a4ae03f9ca54ce14fb5ecb9322f0ca9214a2f35ec5475ea05f21b1b634b940169448ed2ec1d72c3ab9aed5ebbc3abeab2b5e1ed2b86db7940028e2125ab67427fc5399e605057f05642423c1618042318484ea12b7686b080a0162eaf692e3f8ed5729f9931c15a994127bbf8d9c2c3a2b41382a811804ea6eef3fd871505b44a43e1616460000012800000090be9b4fda861bf7888112ef635cdee9a91a3d21535b7362a6c0dd53f556681f20579748d7918f0dccd5752dcab5d3793e6f996af0ecc9d061686606dc42c1ff4f666473fc8091e1925887df5338eea6d50641af70b95cc5ac6c0f2d55005a6b4aa0c0358889cf9529e9fe997018ac9cb16b1186cf1a90fe071ae3bae3c602a6396db6ca6f499bbafdc8ac4610fbd33d94000000903498f0e293205cd2082af437d12d1619d59933be6f9d0d8563bf5c3926434ba6abc87b4056c775e78082a9a53a0357fc67eadf16643000af9c25a897de7a076b0dc6e73f5f39bb42a875e0121bfbf6d1c6817e970dccb8045e71e92ef1ed9ac033cafafec3ed0e61cf79b00b3917a7cc3e74d4eb6fdf4e4255185abbb966769fffa8c939e90805cba9c1d027f235eb12000001280000009072619021db2578b89f28361d759cb625b80707604a73e06e16da844e8e92953832a9d7d8703bfa56a6edb22fa80a55def20914c155f6576038437b26e348ef7613f4fd8616f6ca34eee1286c22b917337072c4fd7f056e2013c85d480b81b0295956f3413d532549f31bd5d1a7fff5928a68d6c808a21d12147beff79b97774dac67575e68654e0c9e4b0bdba043b0da00000090b96df6fc07703c2d4f7b60cc45c2ce90925465d435664666c162e2493fb6023a4472c5f6cada4017ae3fcfce8660c0872ae15efbdac00af8c391dc23d39fc94950b6b4254b8c8e64241976692a14e5a4c80bacf1a9091d76b3cb1b3ddec01d749c6469b28e55f457d44ed8540fbd9dec42b49e9b7eb3461b9e03b2b2db210fc9408bf399c69855bcbf5c94db97b0d6d300000128000000902bb67c2d333b2d72140e8125c20d524321de7130124c205c8033f5a52ef5751cbee212d1e9f8fbd55c9ab593bab90bd8d0fbbc74cfb7d2079f7fca70814457e1bd0f15193e3621e2ae2dcb4b666ffa95cd90f27ce22bacdf3c32bed9d1c077fa3d4b0029aeaaac7c0e21097573cac7833431105bd4f7cac41f950e81ce497d073fe041c0b267963d351e7f46bad85a2300000090989a5f287ba771b3c486594cb4e206a7fc8aba4e4b7894a5c95e92cf705983efe0dedcbf2966814be4a00aee6b386da748020ec285344fda37a0a533ce4a7161789a0c499b62b19c62bc80710f5d64dd8823e68b324a32e2b1c12335be5a8cfb55792f0f8dea993b24374838cbb74b1e067d79454b3753b758d12406fc63fb95887c8aeeef291add1091e21a21a531d90000012800000090086f352a63a2c15b771e0e95cc484d9ab851d45ece9022a2fc16979ccebdf6cd8a281d080d948dd0da7f84a3d037f11d57fa35a96a22f2b9d0ff7094e3dfb5b59b407bc65ab07c59c2b9738baf486dea809514987a7b46bdc7162db13c94a09580abb4ba31707e18fe0a83712de26f5d28b97877c9b4f6fb82521097d5fcee5159ae26c4e90f70b7b8a2ff3a0be9491e0000009025c7d37f4395d5a199c6c99fe93e7b7cf5c394699ca0564da5c668b1b4a0789681354ffa1142895c23a4115e7ca67ee112af0bcf0e5ccc798d9bd3eaf0fe14005b25256a460585325cd7c1f325edcc0e161c001fae73fbab5d24f9ee352c9ec770be8ba37ffa58c52b9e9ce3e5ef5a72d9e75a9dfe7e1237118eee1c6a8b21f0eaaa356fc29286ab04b212aa6d110bac00000ce40000012800000090dbb4d0d2a8ec9b5796f37e0276b93adfd82de35fa8ddedac71f24a3afcc1fc70cddb2f0d10966e8434bb4b7e5ea542b9fbf64f903effc84e1e089963e3aab331c4569d6d2ca5bcbe3ba69fce732432d3b7ff889c3c810e3a4fe597e10a1e51f9cd77e162887e3f12d0b2f1797e80c2c0ad744f4c78c290ea2bf3e3bf90251b5b304c7fe0e8881e9d6734da71614698dd00000090e15c9eef7b9c18bbddf844771bb2689cff590cd861b042087c7d5749e43bbf1b07c0a99a7db7fabc0f59f7e5f8c5e86f8867304654bc12e2ddcdf5066e3081348202c12fdeb0380f41bf7bf0bf12aef785960a82cab387ba3900e5efd50dbc7275452fb6b2a3c7e6d5905019b5627c3c9b177e8826a57737cca86a66ef73d541e80c25f2fa774f84117b434af3f03aa70000012800000090237b304e7115ef24ca0b6af4c6904442432c1653d1f91dda11667a3391e376a8c59b9494bd9fd8a3462a58a8ae2e43f38287965d68ff229f05db9ea2f05cb42621e99230c1b6eebec317dc511f75de10af0ca3f3d540ac79b4de653802d92487593d016741aac8d1e6f767c2632c80fc12b3fe9f84acb96f73f4e93573a0f9f4672356fb526981d00798e3d490ff622700000090d36abf7a4952bf867dd1c2d2ae4f5fd680a698e216c39969903b289cb79464bd00d28d7b81f3c19fd3870cea5d5152cea39d2b9ab6b00930075f258cc60b036150984914b301248279e5652d4ae7fd2767d574814ee68c9fb37a32532003e1bcb4875521e6a9f74b031cd71699689597753451dc29abc51026fdec1bf0b522e90071b356059ec3ca16d05047541581690000012800000090cb8402f03aa6f308556bf119609f6f02cc0d2aa1af938d6e56be76de6012a6ba66ad93d74a8be2e3758976c78a1d84352be6a8b1dc8deae64670304fd476d7d41e20e1b02ea33594014611ba725785fd0be257de48c00be120a5f233322741713f5da81edd9c6cba8afd48089d158d0dfe9eb236bae1290cffe993b9b8306c51ba8b6d88c2fdcd4cc5f3a94aa0be6a82000000908556eb17cbe123f2d0304c877536b7f6da54fe5c6a124b6df08098d77c7a79d7d871dae6f125410320f821dca432ed032ae877ac84f821568b7daf89631392f8186db2ebb30fa836234ef18d64aea7d13d2fd05aa3789c14c09a4938015343fc06a580a43fa333e6be0848f494e6fbc0e6c91ec752ee98e220897cc39808a1131c8f5811b4c60568755f1f419694673a000001280000009019bd42cfa2a996fc95214b0a1b7adbbd631dac971238e40a723b018b5a75787b34c00b7ee71f3d1cc2f160f6b395334543f03fe872d94cfc04c4570a9d3802362ad77d482d6c650696580ff7d50df656a14d82f9549a0c8c4b4a94d4b01730b50eafa7bf8348415b88dec562fa729e6cf4eb1192646d98c279ce586af89b0906c38ea22c1d7851c53639f3d598ff864800000090aef905153f7086f16d147b2ddcc9b602bdac77f4667032b7b874889fbdc7cda53099d931a61462d93a751ccaa750b3a8e55693a687cc02359177745540efb45f8355f5742f44bc19572ea9e5dc0c090288127569449d536728bddf98419cfb073cedc949b52cbf25e8d7371ec989708a452cc8819922688d639df27c5a6f1f89ad17b79a5345fefa4afb930b655170a700000128000000904d010d18bbc916ce1b9cf07a77761275b8452ee8432c84c45f2f477e964fc5bf1510da3445b0f879597fc2a1d0a6cda10c47c58313f76be11f9250e43082db2c2f2061a213c3d954141247ea2a6c7e4836ae3859b4be1b7e210d0f6174fcf171ba9d74991c74af9a6b188b56c7b86c08846880d5348b7522f31f15819b6db28434535142e1896f4063a84fcc40c9992a00000090716ded02fd483c28d914a74f40e01a1dacf169f6ecc39ff2769079726b77cc7dc3cfe9647970fda3ead30246f2bb8ce41e041a93b690c2c954c305aeef82193e086c1803c04ae989b9ac025ba9436fb36e855e2c7db6aaf202fe6cc400e78eef0d8471d1946b3b9103ba82bc0bbb3cbc22bdff6de9b614a08f3fa60695cf944f69f26ea7981dd80c39a78a4b6ab2e6170000012800000090482ddcea8042e342790b5636a5a253c4e2d242dff8aa93c4e42eaf144a7a43c645c3502bfd25b163904caefaf223321c08aff19bf387485183d163fbfbd2e4c4eb3851fb9c36ad06aa42eb3f77d02fc7d6dc85b104fadd34a87e1b1ff9f6888630e641f4110453f6ef24256db1e7f1a70e16bc995c5b4833b454876830d2337f884a2880bd3e851c7762343691fd642b000000909e394aa7821fba6dde93d161ad4d0a20fda7271f4e2f6e75e6aaa6e04879abdcdaeacb6a966c1377dfb0a9be44308338b5ce7eda23a9a132ef3dd00ad9e33aabf208014fa7d7eced6ee23094059a9c26a70777e1452ab451db4dfbd3701e04aaaa6ef712b609559504193c3e4f20ea1e7ffabd5d98d837722fa9633ddfb557dc2b28908364fbaa10ff224a6db2d759560000012800000090c298a805b2e680a8867e93addd9426e09d5570d808085b1c593da76a0400d27d559c39107d45e0ffc6d0737c8750605ea0ac4d8a339162f595c9b9e62488d921a22b120cfd1ccd2486cfdff659910b3cb3fdd671702b7540c85d27708f8ab86212816cc4c66624d9d1d9db16bc6d1272b277c887226c4dd3ea3d005b87196355f0e50eea16e4be3cc5993fc810228858000000904489997ef0faa1245cdd9d8c523aeb6710340f949b49edc38c89487f13a67e4c294a15957c598097d17155c07f67f5e3eb61f735dd5cfb4428f097696523942aa121ae82699fec94dde8b460ba6fde5113395b8fadd7ee8ff297b27b04745f73314a64f23c5e1d6a71a54c4c5d6f756eae8c17548bda4cc54b73a2efa316b7b85cbaa55e74bbc79a8f0c642059c8b2440000012800000090b99bcf815e1aa84e58f43e479149a40360fb1b016e51ee5af903e09e16afd3a1f43adccf0f4f7f6481f3725ff7dbc611ff78ed8589b37441e5bc4ffb51ee8c10cd8afdd2d4651a8723e00d42cbbddb31263269b8aec62bda4fd980942ccd3f2a0b2b7fd5e255e0e378635763d5007da49dfea0d93ed3feabd723daad70b689ca5d88f136018a755ba897ce4aff7a77e900000090cdad61ea71af30981f6a01c1c1f922d1006dcecd97d67ee300350c45c71bb02dd1cc93ff29ae59ee29f9a0b763fa0f184e5332d8b5c591acb33f384559460bef4c7cb663d37f15dbc321e2482d47a262923c2f9c121e0f8ad02b67e53963f0c00a4362c691f209039fd3fa4af613b447aed473c44f18a99a5f2e28f65c2fa11ccaaa88310f5dc64bbfd78c1301bef18f0000012800000090486fecef6b3ae95ac8e6ae9f636548cd2a1b3aba0710a3fd00a66cf0f4b7333b33944c0b0d0232bd8fd79b22daa745adf3a04314645ff0b6b984c152226931c0aa8b25a2e00d6406a3898b4957b45454c07d05c382529d7ebf344c77835dce02c49d0d55b56cca350cd2ba86659ee962909f9b72bc773806208af327f23b03f5b4014eb92f3fa476e85bf0b1343f33e0000000907bf2e48176476863d220b04a0b95b41f139fd6a2d1e8047f75e9010ff45fbd412a661ab30fa8549538fa4a69819cc2e7a2e2adc4eeca30c0aaee2403fa639035c535a7cfd331399569ee47d10df8f5faf860fd3193ad2d5c544cc91a6c753ef19a1f6c64e1e764b6b10ac4dcc40147571016a8371ff6601575956629a891b91dd238c262ba67705929b1edf4617162660000012800000090c3466ce7a4d524534483cc46fe71b134827ce2f7e313981ae63e7d6c0a433690db9c6f7564029066c585d50ebcb0e4a79280c4a31440aa66beb5fa6b1076c36630ff029c269ab377fbd32b8b2b46d337fc784b6ca7a8e150211fd5fd348f8495645940607733be947a216d4cb81c6f5147dd0b4cc5204f7600ec012273b312404d0f7088983a9da4851f32de157c526100000090664901ea78c6963fc43fa423d45f149992d9af67d74e3b49c9334becfd002e9ac159c7b4bfbeff96ffd74bc825a41493a2ddf1ec8154a3c6c9e3b6bd6af6c1cbc7e7e99a07c16538e5dcbb9864885e179ff5742d95d2a0bda32956c3d90d096eb9eb2c99746bbb66601700ed8536a126dd31986ea2b0299ed532b8dd623359453b20d821b27b712f3394db9619c496f0000001280000009067238c9e1a8236663c5d759d22f7c0b5571b4c3ce87609610e8c0b0c22513586b6091a099a865016383ac203315e83bbfba56380e251e40f460dd28d1f4f48847b1179f57912057e53b316301f603beb80f2fcc62e896c9fff553420163e005df74a455c6190e30b8a4276c7af0808c91bddab3f9dc147f6f31bea913ddc281647668e0521d44680cfac9748cf7fa679000000901554e014140980588ad1013f5514aa886ca1ffd5cb1e80f3ddcdf1652e9bcd2e418cd2b27d51a79658338c5c6e35d6e257e537d769357a0c565d766757b02ed40b720b751616d6408ebbc516271759fe0685feb6745da64dde0d7f95e85abf4dfdf7c1d98defacc660a6fb1a448bc6881e4d79869234f981095ad351b06e5f3bfc349b68affbdeeeceaf3296024d1e5900000ce40000012800000090f821f2e5485e3c0af4b84fae21d986dc642938632260220147ff8f0ec70c5f6f97e10343c0fcc465c93ad626a7112c96c9e29b9619e3430c79306697e4b79e28b2a0239a176a54234746e061b8859cd13329f145ede2524db4c02491a218ba19fca3149ad8919ded8aab2d9082594c666094ed5f3ed0296f5483194a86a6c09af2a1905020ee88ea4592f5891772da3e0000009083f8cf115bd237f940b6b6c0b070b835b3b1e16b004f565909845c1f775bd74479a0ffd4a260d337ca93253d9c15dacfdd648fe0be61716c8c8c8c7e6351ce8fc7555dc26409ca9633c3bb6cf126793f197fd40c3b80df76046f8e46bde2e11802c8a182468c8a900c612aa11a0edf37def572ff0ba72f1dc075b0aa5a9b37d9a3c2cc35663bf4e2d2a36f417a6a3fe90000012800000090fae3021c00189b073c016491925cbb782113fa0cd7559c94c8e2c12853689cf14da70ac3886a89f22e2f7b664fee4ecdce844163c3273a5112e33d709c1bb5138278512dcae2c767b90e178f102a0ef2540f30fa24cf05b7336952e34a4f4fc151aaa6d82fabe22a6baa5353684ed2bfbf0adfe7120ae8d1ed6c563bb2a87dc0e0c18298fa7a763f3aa2250f41228e0000000090620fe1d6a7da657aadd4e29e1bb09edb6f293a84f08055ee5e0568e2620ba4711cf8a0776b139ed24904139f442ce4390c988814b3b5b7b4afc27c4f8ca7c2bc1dfc9225e45afec25092031b38974666ff0db3fbe0082703eff4b153af602acdd9ee19e7023d2be09d6f567ce79929231e542eab9133b09d39b6cd149e8af3bd686d412afd06f2e88632a6098f3574400000012800000090dcaa62f948654f40d893c4a4c31662cc125b60c87075fae66b66a2183e781cf7beb587bf57437f9827a2b9fb78ab3dcdc5fe4867a4e8b8b4f012abf3626b64af0f552b9419d35d67aea4e48ec7ff8507de86e89b4354fba12751dba280f8a7f05d52449c5b4f5566fddf392e9e388d2b68b35df13454c60aa110b1a738e311d63eedc223421a48cd60bb0eb5cbed928d00000090d6bd5c8f5170af53e76f14b243f82a2c2b8b9d68bdd505c6c2fbfca36f53333b91c1f765d13b2b16ae48ab9b2d12ae0f1255f1f24c99692b71c19341d2e4776562dc543f5064fe9c7f0df630b0097dd62ef280f42b7ab50e53a42b31cf64064cd20ba1f044e24197b1eaeb1f53d5d7b3d7ef7de6ee682c5ae9f24993b11f42e627740af2e8e9c877b095b057d75714c60000012800000090f00a0370a0cd5ec57d9d79a44644cef128fd247847a671a4de662325cb879934430fdfb488edfee63fa4a177a76a5bbd7fea6aa4c3fbcd9d1926ac271ea7235fd3acd833d974be88a9e8df60c272a2a853d6a1876e84cb7857d2fab74086dfb7e56b205712d19a21e99465ada71395af3303ccb51417da3375faeef928696d9dd86cefd69cc400c166a75e7ccf78dd5000000090b085aacbaf54e57349dbce112679c344dfd54fde70c15d8c0e284c8c70f37dabf14207e638287f062c349e8b903a33f0046e6c5695a1c973223dd481cea29b899e80db83fc05380779664157dd9679ddf6e1ceda231712637b1e527bd5a0f14fa398cd793aba15a21a4776413e04139486b8e5b4924b0b5b0663b767dc5c44f3a3fb506616eb9627e72be73a445df38100000128000000904e04527a1fbc4918fb0f5dc938d33445bd450ad98eb25e3e1d34bf8aac57f60b2abab9fbe140c2784ceefc2e437a38ca309c9bfd2071f3809a28383e9faa063f57ad8667838dd1be75ea2b3e299cc4e417bb5705f1c22bb59e4a7254a6d408ae8f55772b4f2007ced955119173ce0e00a632de4a49e0a08414b308eb02da4a55231f8c0418131a63596955bf270f38350000009057b894cdba6c674382d0ca850af5dae67fd1f3dfc55cbdea681145d7bb6187ff3a0dba30eb41e19b3e6832c6beecff3350f116211f25c509918a4980c1c214bfee81f2aefc930c54004f0dd3263e106a002a12fb9c7796125ad555a1d7b37f5149bd1a27f28a7dd65ce85026647d18d10a0a3f56747e96f7b1e138a12bbbfe3b9001e0eaf0066c32a2d3687fc62116860000012800000090d4461f6118036ab697daf4e90fa5cff8c853f0b54e57aef00d9d4e81115576b4ab3a86cdc3653a3efe7dcb7fa650f176bd557b02b03cc139e9a3221cf7d3a7c2150bdbfb3c879d67e2460b69fec40a0e42ed5c0e359f6f91bebb6c506371b7338587e3d0feae6f7ce555e74da6e76302e62bbcac25d8509f3bda57e323ef7b166f1d2b391d2bb6860efdac1b809b9250000000909207e364faa20d0a1115a269393f9d98152e0019ed33b3c7156d0ef9113be7138f900c4d72e379426bde9b98e1aedc8aeab18ea9e756fa4eac2908038f003435e987d22132cadfaa9e430e452d78032e82a7ed64815063d08b4274c7cfac1a9520d10ff8140565f5986c9c2a135afee4f4d4bf19b1904acb3318d720584e3936de56aca310dd26b714f0a7dec1939b040000012800000090781ae925b7e0ebd9cb87e718b7c7ffeae45651552404fffdbc1df7d85686dd227cb4c1de22650479d3bc359ec4f9e81c79da28757035088b0ba2d1f7b2a321d1abcd3a4bb8b9010906dc7450b8d012dbee1d41e5314a7d094f797425ddfafc8728c6422c58805c0f9d698be9fc320ded25d0466880988f2dad98e0256fa89c288d8e99569f588cdab93ccf67cfab691a0000009092aa76893b5cf1b10cecea31187de1b6190aca3c4941659f077cd00ab9946f3192a2e9cff6a743b51d2217dee81a68541ce18b321fc30d4f5017f866dbab792dd00cd676ef3ac107b0e02420172a92d9f4b252a6cc4dfd4e6d506d1cdfac701ba017d16f692702e2d960c0c7e27794d30aced94c9661109af94d2381decc99211e8bc4dd401c6f2e197ef3057930655d000001280000009069825afeae91c9a0e5db75e73f9d1a1a24ff8398a6b8fce60791b611953a12eef7f0bdd08847bf4d7041aef2a144d2038aa8fbb78fd51a745b6967293dafdaa4f46cd6d0d06d53801cb9cd95c192c96183603c45c304a3332353411d8efd1f79a974f8993fe4e283975e9eef3b867cb60995a74b83383b688c102a4e0d78c6af78ed45a1f028bea71914d9d57c7ae79300000090fd9decd929d5172e46f45ba17fa6c49e4d265fb231e26df16e3f9a1baec1bd6c76a304217741ee8e638dc21c2a019d5d0cba632e13ddfdc7bfc615fde3895aec4ca4ab22291f5dcfb88f27b5d739d549d08d0db6f8fd27a095b6ab9d11728ece355a764e06f0822927716e589ec35d12123b316f1849deb6a9581502a2abd08d4a37b76400c65358d30cf4c4baa3a1e500000128000000902106ead6df33bd10b164d22be5509b1e0afdc774f1e1ff78ae3937c49c8a58c59c89ab7a254fdcc2260f641da11954b053d1869f8aff87c4ca2efb626e1a7f84c10533c1e65ddcf7e7cff35e1c3cd6e696317a1a37783a13cff580b2c614d797a03392c98f19bffa927dbb45de09a3dc25adf76acf2a041e253eef08fac1cdbf8e603383166b7a774f7175070e6c6a600000009072a7e284d2e397b224c4b8f8a20a52403abb3b28a8b788e4a091090c0b6fcbc1fb3539ad4458307722f696580048c4a492d201aab14dbd1af074d002858c522d195ee0bd0786c834a6f6445b476df280c5bea5d01e6369bc12cc2c3ac6e697de844671056cd7263f5604a835aadb448f79300cf927246b8b5220341fa78a6f3dbcbac09550a6ce546131822cad0621810000012800000090dd4294cd8f8c449ad02c6ea497fa35bb7111cccf47686d0b90d118145c1e04dcde092cdf362d408d95ef8925c9dde1ded107c16f4ac9ff46d39d96da2d7ac35e2b3e70583c3cfd6c34c9a9f5ae4a437b49510397a419f5e546ba3456763fdd8252ad584ffdbd5fd4ffda3adac48b8375255def1f7131eff0617799ce406733579c856618ad0db4b4523970c75e95de9100000090af2fd32856e57805ca74674c9d8e6147df5fd4e9367b7d43948d593fd825e10a09ec6066c96ed49ba88d680d7d2a8fe6a7d5518d3fed621fd71f37fb8ee851356ebf4d7efc2905693ce37641397880ffddb16bddd170b29a062e42b76b54171ad1b92c16dd50770cf954905e90a194c4bbbc580a13b432ba581a8456ebb371d337efd1b2f24c2812d51558c88adede8100000128000000905807262584c7578162ce616409b887dd2c861b7cc4e8f19853c008bbd4acaf0f19db1e572398ececfdef22aec0ae7030e7247fe8451984233c12b61b4afaf5804551d46100937b25b7023e5ce39a4f1d0babd330384e38030c2757abf5a7ec092c26349e1d54b83a6c0263a441e24090806168a061b708136f54a949598359283853f4c3c4abead7f6985d4fc393677b00000090ee85daf522efbc2636c7ce5c2a0ec0c99e3e905b753c34d5e6c5db2ff50c82c5aa57de538c88b78bce4c2c1b3f9a412aeaccc8a243694452962647fd3c8a0d53a2eec14ef97e1e224894d3e6db522850ac5c55d0b244bb4aea84143426ba6bfa4f5572a1ba7ba91f34e28bfe68107e34a552f3676c53b34e609675533fcc293d6e6e56ca9648f614cee0c52cbf6e03f900000ce4000001280000009008d66dd316e03c11f2f6f80d3970dc8c516fa76840e4074f4e19e0b95b59a0aebc11492effcdb0c820647a729c67ed95bf500412059c80ea48d48a26705115e659b893ef589d37268fac8809ce28919a4be38cc9e1f564ae77258a4147de79ead0d27dd159679f0f795b096e133eaa2bfff9900462c766b12b9d727c9f1981b4cbe1df4ca5da89bd4283dc4589a0642000000090c47110c0f4fae3f396a2b362bcf4e3c8a9d65fe0a21cb68d3841654a594561c12bfea7e3be27ca5a2ec93fdcff6258dc8215fed3305818baa19067acb03fccb46650250b15fd18a23f4cc1e3e62becb3df759030f92493baabc546feddb86fdea8f42749f994cefef3662465290dab5e53614405c899e27ee60b884823aa06daf2c18ffc69777040fccad493d1e5c84200000128000000904cfd8f43502458ab8ea4b7ed39a2768cd125681210de2ef0cefa30eee2c408642821bf9b19085330d22b43763c3b815dea6fe6396d3c8beaa80a795eb0ffa71e5af496632d65ef83ef4cc14288d20dd1000f6b024b26f5ed3006c6b1eeb67a3049b36fec9c76dd973745bcfe3bb6f37ecb6d08f698cac4da7ce4c781903e3b4e0fc3f3d15000e364adddcd15eaf961f2000000903efe093939d9ff98a01a5e8fd0ab75ee6476d77e279bee266831f6b15061278e9486e5d7d5c627969845f5344607a2eb666a0fbf8de1b24d1fdbd98287c037efa5877e20a4a53163a0c86f6603fb139118a93676525e98a105cc6b1e19ad925d9e131360a74aae10b31104f823e74ca6b16d485bcc131ac037aaba2b972fd445d1cad14efd641dd41a483236239c3cf80000012800000090604771ddf429cf224d4356e7446ec9cd85463670428be3e71568c06f6a9bbfeb9312f5b9cd803c9d36b9992f142a23b56c1ccd0f72b42a1bdc733ea0aa9d71531bffa31ffd6f0a2bd62155531c9ff88b9335846f76052c80bbf28fa854f8739d30e5eb965cc76d52577eed0aacdf17b49692e419cb2b3caaec46db1139e4c970244b030dcb61055d7b7db90bede37c0b0000009042e6ab0a6d746538d1bb5ad5594c60b28d89daa57b2b77c9a40090f69cfead34eccd04efd05d612586841b266c692d2f383a743f8a0ea860ed8129e7a2bfd916290021fc80fdc8c701ecab322cd98b1a1d0446d553da699ba8e672e90fad07ada6acf10d12653745581dea923b1d86b970966fa1d364890acffac86956efc5b30a11cb0f44bca296014e9a33af4ea5690000012800000090a7a6e87fd0cdb332a67c397b738c80deb4e3ff72cd7a1b3aabb891ffb5ce3d25f74e8b75816ba2b1ac000ec3034bc8da4b598d635d8f54d04c595d216b6e037f053d43233da9cf6f672ff6ffc6f6b729d6b0aac4a5ec4d5f847a717e75d027ed0dd660e502258408a639519fced9a1bc9699643f8b52582738c9243537d0945381c416af9d6d2e773add87b4942bb9460000009047e32fe86a0742d9473b758910c78e49372efe69852d111dbbc7da54b9bcf522087c4ee5e7396f2b4702bb5379c21c5a9400b7ddd1d40ee77c9ab05898fcbcf4ea65288f1b73c45267bbbde0540e2ad4af121924eefe85a3d54cabc7b10fb63b9fe3c429b75c9989e59f033df3e064b6c6237779303140bdfcf25653fe92348516f2651d6d0bb18faeea85b94bb660b9000001280000009078b9e99817350a9491dc6867f0cda5fdd9b39d1fe0a9ed58548978cfcc637957ab82784d3b2c30829c7edd6118bdf0a877635660a1d183a010d31390839af04587346dde9980e5b824a71f4e4148012d089842e4e59d5d9a89d6d78e7ec0e2513e6322b0977e3cd7b5f08d5d18cdcbf5dbcde57b87768a860cd76613fe40da8efc0618c34c12e409626b9c577fc00e4b00000090487671868ac16596ec7de56e973381703fe43929e74ff073e9c963aa22bda9d6f1a04e093a379e586f3d76954e318b6df1a823897ee5e4d7c5063597e130a81eeb4c9535a227c45974e78da48e0f7026f1e689ade61971444a449995919cc7431fc9e900129866c3a2ab7174f72cc8ed74b91e6e4c025f693045259f8c9e4cb1d32504c38443236025c37c4c7c0a5adb0000012800000090e734aaa308d6b54f9d7a52fbe20503bf80c73d593365fece0bf1aaaabbe87770833e54bf425e71ffe12ecbda6e9e1df258f94541f0d7f94fddd506653cf122f7c5386c659dadcdb6e6e92bdf9824aa69f775d39caf5b99b73226cbcbd95b82d070c2400fdbf0996937e67a5c513c3946e667fba983561b48a931e3cf3f68254e4f2fd86034fee3abcd82c97ecf88348700000090b96d8f7757738f0f7f58de967313433e3fe1733bf4d5c15a2078690187a1acde17ebc915b23cbc6dcf74219e3cd63362fa003391f19a3a92bf26390d441c1a1c69809270fc9d61da00d0695dbf73d67f37050d622c773829e929b8285955e82f16361fbbe9113658235b9afd0b7a784781b5bc6251126453aa973943410f16a85910376f0b609292e9b9e46104054f5f00000128000000904282cb9ca7cec0bea85b1a8e83379b5365bc8a843a3d79afe1e9d5dfe92184920e375d084c5c03d3d27d4aa4f142ccf6c89ceffaeb3068745e2c9dddebd6ce7dad36b0e76ae97feace5939660ad9dd79f8d75fbcb740a2254c39b9bf2787517cfb2cb48a0e26228f085e85dd15b7e873058334594d9fbb8e877ee498fc11ad0e430e3be518bc9e0c1afb4ad652ed2f9a000000909824f3e20d39014fe1ce0c25d27af4d1fc16aede6aa127d241ab74b62aeeff33691377f976b31216fe4d36161da0f8c7549047c9dfde650a5c9ae9a5357fb15c3e7dbe296ea10d76b46612bafe7824410bb297eceb346111a42b36663015e421a976697df83943d2365bf559b7406e147403547f78ac7b8fbc797275800eb6d46078e862c501eaebc40f16c837b4bba80000012800000090d78151e7a08ad4e11b8a2fb201f83ae713fdac255819cb3c024620025484b20fc3748b713279b0dd26b37b2e38933ea7039534b4e0f5974a4f96ab01d8181dfc988b9f5f495bac0a6ae67df7053157249f7baaf0c91a284db4d1d4345602134382388b5b4a3449214fed2956b221526e2e0dd60320449b4d725af164b212b69b8e0c4b7089c3a030407b9e861ef132c200000090a0539b668cca6c01fe2ed23f6f2d5df8145a48af96d7dd3dbfe6e675af044114c69c44ad4f150b889cbfba7eea026e9ea0f599c4d035d7b709ece6ad5988040a4d51ab2029d9cd88e4b791fdd0cbb6ac36fb943ad0b80e6b2bf4ece885b1048dd8d9b1524f44b75ef82d3fef0826c5d043b2fcf253758cf5e372a5b87d1cb94eb4cbabb547a28d3b8ee124ca5581bb9c000001280000009077ac86a4406764a86f704ff7139ee1f7a2f7e10253ea15f544502be3dd4eb0f4fc2a75653bb060ccc4d03c442f13361ab492775ea71761e90a7113ba55e3d5a10bf43f23fbce60e453aa76ef098b9c93560cf002bf2a52040f12a1b54cfb0c1e47384e91a05d774f558c47a01508e1b0b102ec96c16c2be6ea6d06c8fa1b29aecd8beff997fc4f0ea947c41be6dc7afb00000090be51c1520c12abb9c70648e88aebd75f67f72da3b12e7450a780ea1a8e3082b5bbe7db2ddea227fdd56d3312a3e440f3c1de5d7a1cbd17ed1e71b263fb50e6722c48d5005df3a9fc8b524c64a2de0cbba8dd04fec097af10540a193e0ceb30380c1e127931d154f19310644472722de34551b100eabb2146354debd5dc72f4dda786b3efc42fa91daa612f4986ca4733000001280000009005f1417483ec00421bd576190ca8d530a8b0ebca2abb3995897ba2fe24320056312adc6d898c0c8dcabcae7aecae0970e5640b9664479948de28fa79ca53c232044f5e97331d53dc4c177cc5df9bb46b9a9752b3846de4a72524ee262fbc12f2b25b57ea1da2d1b05ef5a250af84f5f1fdaf2157ec8dad2ed3bc1e5169fd9866be39bb91961bda0fd7fa1ec3e9b08bb4000000907f8517ea4d3422fc85946ad1e31e8f25d2a2a1374ec8b76917efe37eae76771c416cea99423ffac5ee56772105b8203db836ae6c5c33f8ccf371668f516eafc891e4ce29e6c055b473c27330e9e40adedc722c043e9aa74d64d98ce7e363fe2c36eafd9f92add125e075bcf6464d4d3cf35d335a0a70f07ee53e736d282004f45879f9015f0da7a1ad200a3eef7ba0c60000012800000090eaba354a29c93d1f132a1e369079a6db3ba8387cf8f02e36355b5b0997eff35d167ec7c07a7b20013d7665632ae9f5ae2e46671dc912ddfbe3e0b5c7c1db56496f3d464b7a741e764142cda0e2d2d5809c9c4ff4a095cfcf5e8f6b6b52aebf94e2454a7041aa434739b7c98e937cc62877e7ac129f07ca626e71a126880beddd01506d8c7d71b3d35679565eebad27c6000000903129008169633e4de7fc916e6dc182da1d8748aa8b736120f9498c842ef44a3a0540f78e2f5a0c817f38fdde511d5830a0bc185fb760d3581c127038546032768c0ca4d57821496f147047aa7a401171a4bfe3475c8dee1ae60d6752044946ab8181430484b0bf8537e17ec9856129776fb730cd06818524d3d96f8c8c0625b7e51e86f1308adff7423443ff0853ff3b"; function setUp() public virtual { helper = new DecoderHelper(); From e0808b868ce47a217793a083dcc8e9b78d161f03 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 25 Jul 2023 17:46:50 +0000 Subject: [PATCH 04/58] fix: linter --- l1-contracts/src/core/libraries/Decoder.sol | 25 ++++++++++--------- .../src/block_builder/solo_block_builder.ts | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 967083390c6..c9bdf1ad56e 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -77,18 +77,6 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * |--- |--- | --- */ library Decoder { - // Where the start of trees metadata begins in the block - uint256 constant START_TREES_BLOCK_HEADER_OFFSET = 0x80; - - // Where the end of trees metadata begns in the block - uint256 constant END_TREES_BLOCK_HEADER_OFFSET = 0x01c0; - - // The size of the block header elements - uint256 constant TREES_HEADER_SIZE = 0x140; - - // Where the metadata ends and the block data begins. - uint256 constant METADATA_OFFSET = 0x0300; - struct ArrayLengths { uint256 commitmentCount; uint256 nullifierCount; @@ -123,6 +111,19 @@ library Decoder { bytes32 unencryptedLogsHashKernel2; } + // DECODING OFFSET CONSTANTS + // Where the start of trees metadata begins in the block + uint256 private constant START_TREES_BLOCK_HEADER_OFFSET = 0x80; + + // Where the end of trees metadata begns in the block + uint256 private constant END_TREES_BLOCK_HEADER_OFFSET = 0x01c0; + + // The size of the block header elements + uint256 private constant TREES_HEADER_SIZE = 0x140; + + // Where the metadata ends and the block data begins. + uint256 private constant METADATA_OFFSET = 0x0300; + /** * @notice Decodes the inputs and computes values to check state against * @param _l2Block - The L2 block calldata. diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 310846ee0b6..b9091b92dc8 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -122,7 +122,7 @@ export class SoloBlockBuilder implements BlockBuilder { endTreeOfHistoricContractTreeRootsSnapshot, endL1ToL2MessageTreeSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - endHistoricBlocksTreeSnapshot + endHistoricBlocksTreeSnapshot, } = circuitsOutput; // Collect all new nullifiers, commitments, and contracts from all txs in this block From 98692dddbc2d5e92bb723450dc9f57a09ac5a651 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:11:29 +0000 Subject: [PATCH 05/58] fix: stub circuit output for the meantime --- .../end-to-end/src/integration_l1_publisher.test.ts | 2 +- .../src/block_builder/solo_block_builder.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index a7b13312d84..9d4d39b5f8f 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -59,7 +59,7 @@ const logger = createDebugLogger('aztec:integration_l1_publisher'); const config = getConfigEnvVars(); -const numberOfConsecutiveBlocks = 1; +const numberOfConsecutiveBlocks = 2; describe('L1Publisher integration', () => { let publicClient: PublicClient; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index b9091b92dc8..afe959229e5 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -92,7 +92,7 @@ export class SoloBlockBuilder implements BlockBuilder { startTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - startHistoricBlocksTreeSnapshot, + // startHistoricBlocksTreeSnapshot, ] = await Promise.all( [ MerkleTreeId.PRIVATE_DATA_TREE, @@ -122,7 +122,7 @@ export class SoloBlockBuilder implements BlockBuilder { endTreeOfHistoricContractTreeRootsSnapshot, endL1ToL2MessageTreeSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - endHistoricBlocksTreeSnapshot, + // endHistoricBlocksTreeSnapshot, } = circuitsOutput; // Collect all new nullifiers, commitments, and contracts from all txs in this block @@ -169,8 +169,9 @@ export class SoloBlockBuilder implements BlockBuilder { endL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - startHistoricBlocksTreeSnapshot, - endHistoricBlocksTreeSnapshot, + // TODO: Stubbed until #1162 + startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot.empty(), + endHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot.empty(), newCommitments, newNullifiers, newL2ToL1Msgs, From 2942f95ef4d5ed8fbf1d62e55a625f5610c4ed32 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 26 Jul 2023 17:58:51 +0000 Subject: [PATCH 06/58] feat: add naive block hash calculations to root rollup circuit --- .../aztec3/circuits/abis/global_variables.hpp | 13 ++++++++ .../abis/rollup/root/root_rollup_inputs.hpp | 20 +++++++----- .../rollup/root/root_rollup_public_inputs.hpp | 6 ++++ .../root/native_root_rollup_circuit.cpp | 31 +++++++++++++++++++ .../src/structs/rollup/root_rollup.ts | 7 +++++ 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp index 480dc6d166b..563cef2d830 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp @@ -58,6 +58,19 @@ template struct GlobalVariables { return NCT::compress(inputs, GeneratorIndex::GLOBAL_VARIABLES); } + + // TODO(Maddiaa): is this cursed? The linter is shouting at me for doing pointer arithmetic. + std::array to_bytes() const + { + std::array buf; + + auto* ptr = buf.begin(); + chain_id.to_buffer().copy(ptr, ptr += 32); + version.to_buffer().copy(ptr, ptr += 32); + block_number.to_buffer().copy(ptr, ptr += 32); + timestamp.to_buffer().copy(ptr, ptr += 32); + return buf; + } }; template void read(uint8_t const*& it, GlobalVariables& globals) diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp index 0fff9bd5981..ea22bcfc980 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp @@ -16,18 +16,22 @@ template struct RootRollupInputs { using fr = typename NCT::fr; // All below are shared between the base and merge rollups - std::array, 2> previous_rollup_data; + std::array, 2> previous_rollup_data{}; - std::array new_historic_private_data_tree_root_sibling_path; - std::array new_historic_contract_tree_root_sibling_path; + std::array new_historic_private_data_tree_root_sibling_path{}; + std::array new_historic_contract_tree_root_sibling_path{}; // inputs required to process l1 to l2 messages - std::array l1_to_l2_messages; - std::array new_l1_to_l2_message_tree_root_sibling_path; - std::array new_historic_l1_to_l2_message_roots_tree_sibling_path; + std::array l1_to_l2_messages{}; + std::array new_l1_to_l2_message_tree_root_sibling_path{}; + std::array new_historic_l1_to_l2_message_roots_tree_sibling_path{}; - AppendOnlyTreeSnapshot start_l1_to_l2_message_tree_snapshot; - AppendOnlyTreeSnapshot start_historic_tree_l1_to_l2_message_tree_roots_snapshot; + AppendOnlyTreeSnapshot start_l1_to_l2_message_tree_snapshot{}; + AppendOnlyTreeSnapshot start_historic_tree_l1_to_l2_message_tree_roots_snapshot{}; + + // inputs required to add the block hash + std::array new_historic_blocks_tree_sibling_path{}; + AppendOnlyTreeSnapshot start_historic_blocks_tree_snapshot{}; bool operator==(RootRollupInputs const&) const = default; }; diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp index c6d97a97060..3c64dba56d5 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp @@ -22,6 +22,8 @@ template struct RootRollupPublicInputs { GlobalVariables globalVariables; + fr block_hash; + AppendOnlyTreeSnapshot start_private_data_tree_snapshot; AppendOnlyTreeSnapshot end_private_data_tree_snapshot; @@ -59,6 +61,7 @@ template struct RootRollupPublicInputs { std::vector buf; write(&buf, globalVariables); + write(&buf, block_hash); write(buf, start_private_data_tree_snapshot); write(buf, start_nullifier_tree_snapshot); write(buf, start_contract_tree_snapshot); @@ -110,6 +113,7 @@ template void read(uint8_t const*& it, RootRollupPublicInputs void write(std::vector& buf, RootRollupPublicIn write(buf, obj.end_aggregation_object); write(buf, obj.globalVariables); + write(buf, obj.block_hash); write(buf, obj.start_private_data_tree_snapshot); write(buf, obj.end_private_data_tree_snapshot); write(buf, obj.start_nullifier_tree_snapshot); @@ -164,6 +169,7 @@ template std::ostream& operator<<(std::ostream& os, RootRollupPub { return os << "end_aggregation_object: " << obj.end_aggregation_object << "\n" << "global_variables: " << obj.globalVariables << "\n" + << "block_hash: " << obj.block_hash << "\n" << "start_private_data_tree_snapshot: " << obj.start_private_data_tree_snapshot << "\n" << "end_private_data_tree_snapshot: " << obj.end_private_data_tree_snapshot << "\n" << "start_nullifier_tree_snapshot: " << obj.start_nullifier_tree_snapshot << "\n" diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 344ea93190e..9627d770061 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -138,9 +138,38 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, "historic l1 to l2 message tree roots not empty at location where subtree would be inserted")); + // Build the block tree for this iteration from the tree information, and global variables, and the public inputs + // Then insert the block into the historic blocks tree + + // TODO: make all of these arrays - and throw into a function somewhere + // NOTES: + // - What goes into the blocks tree? + // - + // write all of the block data into a large vector before hashing + // NOTE: the block hash will need to be a public input so that it can be indexed? + // TODO: how do we want to build this? as a subtree or is this method fine? + auto block_hash = NT::hash({ left.constants.global_variables.hash(), + right.end_private_data_tree_snapshot.root, + right.end_nullifier_tree_snapshot.root, + right.end_contract_tree_snapshot.root, + end_l1_to_l2_data_roots_tree_snapshot.root }); + + // Update the historic blocks tree + auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree( + builder, + rootRollupInputs.start_historic_blocks_tree_snapshot, + rootRollupInputs.new_historic_blocks_tree_sibling_path, + fr::zero(), + block_hash, + 0, + format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, + "historic blocks tree roots not empty at location where subtree would be inserted")); + + RootRollupPublicInputs public_inputs = { .end_aggregation_object = aggregation_object, .globalVariables = left.constants.global_variables, + .block_hash = block_hash, .start_private_data_tree_snapshot = left.start_private_data_tree_snapshot, .end_private_data_tree_snapshot = right.end_private_data_tree_snapshot, .start_nullifier_tree_snapshot = left.start_nullifier_tree_snapshot, @@ -160,6 +189,8 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu .start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot = rootRollupInputs.start_historic_tree_l1_to_l2_message_tree_roots_snapshot, .end_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot = end_l1_to_l2_data_roots_tree_snapshot, + .start_historic_blocks_tree_snapshot = rootRollupInputs.start_historic_blocks_tree_snapshot, + .end_historic_blocks_tree_snapshot = end_historic_blocks_tree_snapshot, .calldata_hash = components::compute_calldata_hash(rootRollupInputs.previous_rollup_data), .l1_to_l2_messages_hash = compute_messages_hash(rootRollupInputs.l1_to_l2_messages) }; diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 90b4dabc4e6..65afe3923f1 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -102,6 +102,11 @@ export class RootRollupPublicInputs { public globalVariables: GlobalVariables, // constants: ConstantRollupData // TODO maybe don't include this + /** + * The hash of the block being included into the historic block hashes tree. + */ + public blockHash: Fr, + /** * Snapshot of the private data tree at the start of the rollup. */ @@ -198,6 +203,7 @@ export class RootRollupPublicInputs { return [ fields.endAggregationObject, fields.globalVariables, + fields.blockHash, fields.startPrivateDataTreeSnapshot, fields.endPrivateDataTreeSnapshot, fields.startNullifierTreeSnapshot, @@ -256,6 +262,7 @@ export class RootRollupPublicInputs { return new RootRollupPublicInputs( reader.readObject(AggregationObject), reader.readObject(GlobalVariables), + reader.readFr(), reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), From 376e71a8cdaada15ea0315eb7ff6342f41446c0a Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:56:01 +0000 Subject: [PATCH 07/58] temp --- .../abis/rollup/root/root_rollup_inputs.hpp | 10 ++++-- circuits/cpp/src/aztec3/circuits/hash.hpp | 35 +++++++++++++++++++ .../circuits/rollup/components/components.hpp | 26 ++++++++++++++ .../aztec3/circuits/rollup/root/c_bind.cpp | 2 ++ .../root/native_root_rollup_circuit.cpp | 4 +-- .../circuits/rollup/test_utils/utils.cpp | 21 ++++++++++- 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp index ea22bcfc980..8a48deb5002 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp @@ -30,8 +30,8 @@ template struct RootRollupInputs { AppendOnlyTreeSnapshot start_historic_tree_l1_to_l2_message_tree_roots_snapshot{}; // inputs required to add the block hash - std::array new_historic_blocks_tree_sibling_path{}; AppendOnlyTreeSnapshot start_historic_blocks_tree_snapshot{}; + std::array new_historic_blocks_tree_sibling_path{}; bool operator==(RootRollupInputs const&) const = default; }; @@ -48,6 +48,8 @@ template void read(uint8_t const*& it, RootRollupInputs& obj read(it, obj.new_historic_l1_to_l2_message_roots_tree_sibling_path); read(it, obj.start_l1_to_l2_message_tree_snapshot); read(it, obj.start_historic_tree_l1_to_l2_message_tree_roots_snapshot); + read(it, obj.start_historic_blocks_tree_snapshot); + read(it, obj.new_historic_blocks_tree_sibling_path); }; template void write(std::vector& buf, RootRollupInputs const& obj) @@ -62,6 +64,8 @@ template void write(std::vector& buf, RootRollupInputs std::ostream& operator<<(std::ostream& os, RootRollupInputs const& obj) @@ -77,7 +81,9 @@ template std::ostream& operator<<(std::ostream& os, RootRollupInp << obj.new_historic_l1_to_l2_message_roots_tree_sibling_path << "\n" << "start_l1_to_l2_message_tree_snapshot: " << obj.start_l1_to_l2_message_tree_snapshot << "\n" << "start_historic_tree_l1_to_l2_message_tree_roots_snapshot: " - << obj.start_historic_tree_l1_to_l2_message_tree_roots_snapshot << "\n"; + << obj.start_historic_tree_l1_to_l2_message_tree_roots_snapshot << "\n" + << "start_historic_blocks_tree_snapshot: " << obj.start_historic_blocks_tree_snapshot << "\n" + << "new_historic_blocks_tree_sibling_path: " << obj.new_historic_blocks_tree_sibling_path << "\n"; } } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index f3b6763cb34..9e23fd7fd8c 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -205,6 +205,27 @@ typename NCT::fr root_from_sibling_path(typename NCT::fr const& leaf, return node; // root } +template +typename NCT::fr root_from_sibling_path_trace(typename NCT::fr const& leaf, + typename NCT::fr const& leaf_index, + std::array const& sibling_path) +{ + auto node = leaf; + uint256_t index = leaf_index; + for (size_t i = 0; i < N; i++) { + if (index & 1) { + info(sibling_path[i], node); + node = NCT::merkle_hash(sibling_path[i], node); + } else { + info(node, sibling_path[i]); + node = NCT::merkle_hash(node, sibling_path[i]); + } + index >>= uint256_t(1); + } + info("root: ", node); + return node; // root +} + /** * @brief Get the sibling path of an item in a given merkle tree * @@ -235,6 +256,20 @@ std::array get_sibling_path(MerkleTree& tree, size_t leaf_index, size_t c return sibling_path; } +template +void check_membership_trace(Builder& builder, + typename NCT::fr const& value, + typename NCT::fr const& index, + std::array const& sibling_path, + typename NCT::fr const& root, + std::string const& msg) +{ + const auto calculated_root = root_from_sibling_path_trace(value, index, sibling_path); + builder.do_assert(calculated_root == root, + std::string("Membership check failed: ") + msg, + aztec3::utils::CircuitErrorCode::MEMBERSHIP_CHECK_FAILED); +} + template void check_membership(Builder& builder, typename NCT::fr const& value, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp index 2e64593dc65..bf25fe352c7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp @@ -2,6 +2,7 @@ #include "init.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/utils/circuit_errors.hpp" using aztec3::circuits::check_membership; @@ -29,6 +30,31 @@ void assert_equal_constants(DummyBuilder& builder, AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, BaseOrMergeRollupPublicInputs const& right); +template +AppendOnlySnapshot insert_subtree_to_snapshot_tree_traced(DummyBuilder& builder, + AppendOnlySnapshot snapshot, + std::array siblingPath, + NT::fr emptySubtreeRoot, + NT::fr subtreeRootToInsert, + uint8_t subtreeDepth, + std::string const& emptySubtreeCheckErrorMessage) +{ + auto leafIndexAtDepth = snapshot.next_available_leaf_index >> subtreeDepth; + + // Check that the current root is correct and that there is an empty subtree at the insertion location + check_membership_trace( + builder, emptySubtreeRoot, leafIndexAtDepth, siblingPath, snapshot.root, emptySubtreeCheckErrorMessage); + + // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. + auto new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); + + // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x + auto new_next_available_leaf_index = snapshot.next_available_leaf_index + (static_cast(1) << subtreeDepth); + + AppendOnlySnapshot newTreeSnapshot = { .root = new_root, + .next_available_leaf_index = new_next_available_leaf_index }; + return newTreeSnapshot; +} template AppendOnlySnapshot insert_subtree_to_snapshot_tree(DummyBuilder& builder, AppendOnlySnapshot snapshot, std::array siblingPath, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp index 9bc1e7b66f7..01389990f6f 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp @@ -53,6 +53,8 @@ WASM_EXPORT uint8_t* root_rollup__sim(uint8_t const* root_rollup_inputs_buf, read(root_rollup_inputs_buf, root_rollup_inputs); DummyBuilder builder = DummyBuilder("root_rollup__sim"); + info("rollup inputs"); + info(root_rollup_inputs); RootRollupPublicInputs const public_inputs = root_rollup_circuit(builder, root_rollup_inputs); // serialize public inputs to bytes vec diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 9627d770061..3668d6ea589 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -115,7 +115,7 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu // Compute subtree inserting l1 to l2 messages auto l1_to_l2_subtree_root = calculate_subtree(rootRollupInputs.l1_to_l2_messages); - // // Insert subtree into the l1 to l2 data tree + // Insert subtree into the l1 to l2 data tree const auto empty_l1_to_l2_subtree_root = components::calculate_empty_tree_root(L1_TO_L2_MSG_SUBTREE_HEIGHT); auto new_l1_to_l2_messages_tree_snapshot = components::insert_subtree_to_snapshot_tree( builder, @@ -155,7 +155,7 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu end_l1_to_l2_data_roots_tree_snapshot.root }); // Update the historic blocks tree - auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree( + auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree_traced( builder, rootRollupInputs.start_historic_blocks_tree_snapshot, rootRollupInputs.new_historic_blocks_tree_sibling_path, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 5f7fd58111f..141e661ef54 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -341,7 +341,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, MemoryStore historic_l1_to_l2_msg_tree_store; MerkleTree historic_l1_to_l2_msg_tree(historic_l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); - MemoryStore private_data_store; const MerkleTree private_data_tree(private_data_store, PRIVATE_DATA_TREE_HEIGHT); @@ -351,6 +350,9 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, MemoryStore l1_to_l2_msg_tree_store; MerkleTree l1_to_l2_msg_tree(l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); + MemoryStore historic_blocks_tree_store; + MerkleTree historic_blocks_tree(historic_blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); + // Historic trees are initialised with an empty root at position 0. historic_private_data_tree.update_element(0, private_data_tree.root()); @@ -364,6 +366,7 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, get_sibling_path(historic_contract_tree, 1, 0); auto historic_l1_to_l2_msg_sibling_path = get_sibling_path(historic_l1_to_l2_msg_tree, 1, 0); + // l1 to l2 tree auto l1_to_l2_tree_sibling_path = get_sibling_path(l1_to_l2_msg_tree, 0, L1_TO_L2_MSG_SUBTREE_HEIGHT); @@ -378,6 +381,20 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, .next_available_leaf_index = 1, }; + // Blocks tree + auto blocks_tree_sibling_path = get_sibling_path(historic_blocks_tree, 0, 0); + info("problematic sibling path"); + info(blocks_tree_sibling_path); + + // Blocks tree snapshots + AppendOnlyTreeSnapshot const start_historic_blocks_tree_snapshot = { + .root = historic_blocks_tree.root(), + .next_available_leaf_index = 0, + }; + + info("snapshot"); + info(start_historic_blocks_tree_snapshot); + RootRollupInputs rootRollupInputs = { .previous_rollup_data = get_previous_rollup_data(builder, std::move(kernel_data)), .new_historic_private_data_tree_root_sibling_path = historic_data_sibling_path, @@ -388,6 +405,8 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, .start_l1_to_l2_message_tree_snapshot = start_l1_to_l2_msg_tree_snapshot, .start_historic_tree_l1_to_l2_message_tree_roots_snapshot = start_historic_tree_l1_to_l2_message_tree_roots_snapshot, + .start_historic_blocks_tree_snapshot = start_historic_blocks_tree_snapshot, + .new_historic_blocks_tree_sibling_path = blocks_tree_sibling_path, }; return rootRollupInputs; } From 7520217de5a969167ab3e1cd6dac6141f5459fb5 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 31 Jul 2023 15:10:28 +0000 Subject: [PATCH 08/58] fix: update snapshot --- .../__snapshots__/root_rollup.test.ts.snap | 47 ++++++++++--------- .../circuits.js/src/tests/factories.ts | 1 + 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap index 56de7ad12ca..0b201e51859 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap @@ -187,6 +187,10 @@ next_available_leaf_index: 8704 start_historic_tree_l1_to_l2_message_tree_roots_snapshot: root: 0x2300 next_available_leaf_index: 8960 +start_historic_blocks_tree_snapshot: root: 0x114a90e165ae4b9d878da63d75598f8b5f3123c8311b02a5087856f3500002fc +next_available_leaf_index: 235 + +new_historic_blocks_tree_sibling_path: [ 0x1800000000001c00000080421000030000005d42100003000000008f971a0000 0x1d000000ba41100003000000974110000300000000f1012e000000001e00 0x9b39100006000000161f10000600000001fd006500000000210000005843 0x1000030000003143100003000000003873af0100000000000000884210000300 0x6142100003000000006334440100000001000000c2411000030000009b41 0x1000030000000017e8fc01000000020000009739100003000000d41f10000300 0xc879dd010000000500000042fb9e40ca3a055ff0000000d20100005043 0x1000030000002d4310000300000000a60a8a000000001c000000804210000300 0x5d4210000300000000e7bbe1000000001d000000ba411000030000009741 0x10000300000000d58fca000000001e0000009b39100006000000161f10000600 0x1f4ae0800000000210000005843100003000000314310000300000000d3 0x7c478c19a07df2f666f2bb18879492e36fcd7d7af60d029ac9634c2b64d00fb 0x1000000c2411000030000009b41100003000000004b024c010000000200 0x9739100003000000d41f100003000000004bac880100000005000000a13e 0x100003000000eb301000030000000079bb050100000006000000694310000700 0x4843100007000000002fba9d0200000014000000ab421000070000007842 ] " `; @@ -207,56 +211,57 @@ version: 0x101 block_number: 0x102 timestamp: 0x103 -start_private_data_tree_snapshot: root: 0x200 -next_available_leaf_index: 512 - -end_private_data_tree_snapshot: root: 0x300 +block_hash: 0x200 +start_private_data_tree_snapshot: root: 0x300 next_available_leaf_index: 768 -start_nullifier_tree_snapshot: root: 0x400 +end_private_data_tree_snapshot: root: 0x400 next_available_leaf_index: 1024 -end_nullifier_tree_snapshot: root: 0x500 +start_nullifier_tree_snapshot: root: 0x500 next_available_leaf_index: 1280 -start_contract_tree_snapshot: root: 0x600 +end_nullifier_tree_snapshot: root: 0x600 next_available_leaf_index: 1536 -end_contract_tree_snapshot: root: 0x700 +start_contract_tree_snapshot: root: 0x700 next_available_leaf_index: 1792 -start_public_data_tree_root: 0x800 -end_public_data_tree_root: 0x900 -start_tree_of_historic_private_data_tree_roots_snapshot: root: 0xa00 -next_available_leaf_index: 2560 +end_contract_tree_snapshot: root: 0x800 +next_available_leaf_index: 2048 -end_tree_of_historic_private_data_tree_roots_snapshot: root: 0xb00 +start_public_data_tree_root: 0x900 +end_public_data_tree_root: 0xa00 +start_tree_of_historic_private_data_tree_roots_snapshot: root: 0xb00 next_available_leaf_index: 2816 -start_tree_of_historic_contract_tree_roots_snapshot: root: 0xc00 +end_tree_of_historic_private_data_tree_roots_snapshot: root: 0xc00 next_available_leaf_index: 3072 -end_tree_of_historic_contract_tree_roots_snapshot: root: 0xd00 +start_tree_of_historic_contract_tree_roots_snapshot: root: 0xd00 next_available_leaf_index: 3328 -start_l1_to_l2_messages_tree_snapshot: root: 0xe00 +end_tree_of_historic_contract_tree_roots_snapshot: root: 0xe00 next_available_leaf_index: 3584 -end_l1_tol2_messages_tree_snapshot: root: 0xf00 +start_l1_to_l2_messages_tree_snapshot: root: 0xf00 next_available_leaf_index: 3840 -start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot: root: 0x1000 +end_l1_tol2_messages_tree_snapshot: root: 0x1000 next_available_leaf_index: 4096 -end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot: root: 0x1100 +start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot: root: 0x1100 next_available_leaf_index: 4352 -start_historic_blocks_tree_snapshot: root: 0x1200 +end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot: root: 0x1200 next_available_leaf_index: 4608 -end_historic_blocks_tree_snapshot: root: 0x1300 +start_historic_blocks_tree_snapshot: root: 0x1300 next_available_leaf_index: 4864 +end_historic_blocks_tree_snapshot: root: 0x1400 +next_available_leaf_index: 5120 + calldata_hash: [ 0x1 0x2 ] l1_to_l2_messages_hash: [ 0x3 0x4 ] " diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index c4af1777908..8c57042263b 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -835,6 +835,7 @@ export function makeRootRollupPublicInputs( return RootRollupPublicInputs.from({ endAggregationObject: makeAggregationObject(seed), globalVariables: makeGlobalVariables((seed += 0x100), blockNumber), + blockHash: fr((seed += 0x100)), startPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), endPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), startNullifierTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), From 3c9422ce59468e44024f47840070801136b2b04d Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 31 Jul 2023 15:37:25 +0000 Subject: [PATCH 09/58] feat: include block hash calcs in sequencer --- .../__snapshots__/root_rollup.test.ts.snap | 6 +++--- .../src/structs/rollup/root_rollup.ts | 12 ++++++++++++ yarn-project/circuits.js/src/tests/factories.ts | 2 ++ .../src/block_builder/solo_block_builder.ts | 17 ++++++++++++----- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap index 0b201e51859..a3598124ce3 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap @@ -187,10 +187,10 @@ next_available_leaf_index: 8704 start_historic_tree_l1_to_l2_message_tree_roots_snapshot: root: 0x2300 next_available_leaf_index: 8960 -start_historic_blocks_tree_snapshot: root: 0x114a90e165ae4b9d878da63d75598f8b5f3123c8311b02a5087856f3500002fc -next_available_leaf_index: 235 +start_historic_blocks_tree_snapshot: root: 0x2400 +next_available_leaf_index: 9216 -new_historic_blocks_tree_sibling_path: [ 0x1800000000001c00000080421000030000005d42100003000000008f971a0000 0x1d000000ba41100003000000974110000300000000f1012e000000001e00 0x9b39100006000000161f10000600000001fd006500000000210000005843 0x1000030000003143100003000000003873af0100000000000000884210000300 0x6142100003000000006334440100000001000000c2411000030000009b41 0x1000030000000017e8fc01000000020000009739100003000000d41f10000300 0xc879dd010000000500000042fb9e40ca3a055ff0000000d20100005043 0x1000030000002d4310000300000000a60a8a000000001c000000804210000300 0x5d4210000300000000e7bbe1000000001d000000ba411000030000009741 0x10000300000000d58fca000000001e0000009b39100006000000161f10000600 0x1f4ae0800000000210000005843100003000000314310000300000000d3 0x7c478c19a07df2f666f2bb18879492e36fcd7d7af60d029ac9634c2b64d00fb 0x1000000c2411000030000009b41100003000000004b024c010000000200 0x9739100003000000d41f100003000000004bac880100000005000000a13e 0x100003000000eb301000030000000079bb050100000006000000694310000700 0x4843100007000000002fba9d0200000014000000ab421000070000007842 ] +new_historic_blocks_tree_sibling_path: [ 0x2500 0x2501 0x2502 0x2503 0x2504 0x2505 0x2506 0x2507 0x2508 0x2509 0x250a 0x250b 0x250c 0x250d 0x250e 0x250f ] " `; diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 65afe3923f1..750373a8acf 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -3,6 +3,7 @@ import { BufferReader } from '@aztec/foundation/serialize'; import { CONTRACT_TREE_ROOTS_TREE_HEIGHT, + HISTORIC_BLOCKS_TREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, @@ -54,11 +55,20 @@ export class RootRollupInputs { * Snapshot of the historic L1 to L2 message tree roots at the start of the rollup. */ public startHistoricTreeL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, + /** + * Snapshot of the historic block roots tree at the start of the rollup. + */ + public startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot, + /** + * Sibling path of the new historic block roots tree root. + */ + public newHistoricBlocksTreeSiblingPath: Fr[] ) { assertMemberLength(this, 'newHistoricPrivateDataTreeRootSiblingPath', PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); assertMemberLength(this, 'newHistoricContractDataTreeRootSiblingPath', CONTRACT_TREE_ROOTS_TREE_HEIGHT); assertMemberLength(this, 'newL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH); assertMemberLength(this, 'newHistoricL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); + assertMemberLength(this, 'newHistoricBlocksTreeSiblingPath', HISTORIC_BLOCKS_TREE_HEIGHT); assertMemberLength(this, 'newL1ToL2Messages', NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); } @@ -80,6 +90,8 @@ export class RootRollupInputs { fields.newHistoricL1ToL2MessageTreeRootSiblingPath, fields.startL1ToL2MessageTreeSnapshot, fields.startHistoricTreeL1ToL2MessageTreeRootsSnapshot, + fields.startHistoricBlocksTreeSnapshot, + fields.newHistoricBlocksTreeSiblingPath, ] as const; } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 8c57042263b..fddd470ffbb 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -818,6 +818,8 @@ export function makeRootRollupInputs(seed = 0, blockNumber: number | undefined = makeTuple(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, fr, 0x2100), makeAppendOnlyTreeSnapshot(seed + 0x2200), makeAppendOnlyTreeSnapshot(seed + 0x2300), + makeAppendOnlyTreeSnapshot(seed + 0x2400), + makeTuple(HISTORIC_BLOCKS_TREE_HEIGHT, fr, 0x2500), ); } diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index afe959229e5..8ad6780ceb6 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -92,7 +92,7 @@ export class SoloBlockBuilder implements BlockBuilder { startTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - // startHistoricBlocksTreeSnapshot, + startHistoricBlocksTreeSnapshot, ] = await Promise.all( [ MerkleTreeId.PRIVATE_DATA_TREE, @@ -122,7 +122,7 @@ export class SoloBlockBuilder implements BlockBuilder { endTreeOfHistoricContractTreeRootsSnapshot, endL1ToL2MessageTreeSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - // endHistoricBlocksTreeSnapshot, + endHistoricBlocksTreeSnapshot, } = circuitsOutput; // Collect all new nullifiers, commitments, and contracts from all txs in this block @@ -169,9 +169,8 @@ export class SoloBlockBuilder implements BlockBuilder { endL1ToL2MessageTreeSnapshot, startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - // TODO: Stubbed until #1162 - startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot.empty(), - endHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot.empty(), + startHistoricBlocksTreeSnapshot, + endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, newL2ToL1Msgs, @@ -443,6 +442,12 @@ export class SoloBlockBuilder implements BlockBuilder { MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, ); + // Get historic block tree roots + const startHistoricBlocksTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); + const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath( + MerkleTreeId.BLOCKS_TREE, + ); + return RootRollupInputs.from({ previousRollupData, newHistoricContractDataTreeRootSiblingPath, @@ -452,6 +457,8 @@ export class SoloBlockBuilder implements BlockBuilder { newL1ToL2MessageTreeRootSiblingPath, startL1ToL2MessageTreeSnapshot, startHistoricTreeL1ToL2MessageTreeRootsSnapshot, + startHistoricBlocksTreeSnapshot, + newHistoricBlocksTreeSiblingPath }); } From de68edd7b9eab7c951923c2e74c1d772b8978edc Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 31 Jul 2023 18:11:49 +0000 Subject: [PATCH 10/58] fix: make calculate block hash a cbind --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 5 ++ .../cpp/src/aztec3/circuits/abis/c_bind.h | 1 + .../aztec3/circuits/abis/global_variables.hpp | 2 + circuits/cpp/src/aztec3/circuits/hash.hpp | 86 ++++++++++++------- .../circuits/rollup/components/components.hpp | 43 +++++----- .../aztec3/circuits/rollup/root/c_bind.cpp | 2 - .../root/native_root_rollup_circuit.cpp | 13 +-- yarn-project/circuits.js/src/abis/abis.ts | 15 ++++ .../circuits.js/src/cbind/circuits.gen.ts | 68 +++++++++++++++ yarn-project/circuits.js/src/cbind/types.ts | 1 + .../src/structs/global_variables.ts | 3 +- .../src/integration_l1_publisher.test.ts | 3 + .../src/block_builder/solo_block_builder.ts | 50 ++++++++++- yarn-project/types/src/l2_block.ts | 2 + 14 files changed, 227 insertions(+), 67 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 5e0a2574cb1..506c8e81f2e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -441,6 +441,11 @@ CBIND(abis__silo_commitment, aztec3::circuits::silo_commitment); */ CBIND(abis__silo_nullifier, aztec3::circuits::silo_nullifier); +/** + * @brief Computes the block hash from the block information. + */ +CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash); + /** * @brief Generates a signed tx request hash from it's pre-image * This is a WASM-export that can be called from Typescript. diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 37b9d3f5a31..482052d6218 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -38,6 +38,7 @@ CBIND_DECL(abis__compute_commitment_nonce); CBIND_DECL(abis__compute_unique_commitment); CBIND_DECL(abis__silo_commitment); CBIND_DECL(abis__silo_nullifier); +CBIND_DECL(abis__compute_block_hash); WASM_EXPORT void abis__compute_message_secret_hash(uint8_t const* secret, uint8_t* output); WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, uint8_t* output); diff --git a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp index 563cef2d830..660aaee0eb3 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp @@ -24,6 +24,8 @@ template struct GlobalVariables { fr block_number = 0; fr timestamp = 0; + MSGPACK_FIELDS(chain_id, version, block_number, timestamp); + boolean operator==(GlobalVariables const& other) const { return chain_id == other.chain_id && version == other.version && block_number == other.block_number && diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 9e23fd7fd8c..d9d4561734b 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -2,6 +2,7 @@ #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/function_leaf_preimage.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/point.hpp" #include "aztec3/constants.hpp" @@ -137,6 +138,25 @@ typename NCT::fr silo_nullifier(typename NCT::address contract_address, typename return NCT::compress(inputs, aztec3::GeneratorIndex::OUTER_NULLIFIER); } +template typename NCT::fr compute_block_hash(typename abis::GlobalVariables globals, + typename NCT::fr private_data_tree_root, + typename NCT::fr nullifier_tree_root, + typename NCT::fr contract_tree_root, + typename NCT::fr l1_to_l2_data_tree_root) +{ + using fr = typename NCT::fr; + + std::vector const inputs = { + globals.hash(), private_data_tree_root, nullifier_tree_root, contract_tree_root, l1_to_l2_data_tree_root + }; + + info("globals: ", globals); + info("block hash inputs: ", inputs); + + // TODO(Maddiaa): does this need an index? + return NCT::compress(inputs); +} + /** * @brief Calculate the Merkle tree root from the sibling path and leaf. * @@ -205,26 +225,26 @@ typename NCT::fr root_from_sibling_path(typename NCT::fr const& leaf, return node; // root } -template -typename NCT::fr root_from_sibling_path_trace(typename NCT::fr const& leaf, - typename NCT::fr const& leaf_index, - std::array const& sibling_path) -{ - auto node = leaf; - uint256_t index = leaf_index; - for (size_t i = 0; i < N; i++) { - if (index & 1) { - info(sibling_path[i], node); - node = NCT::merkle_hash(sibling_path[i], node); - } else { - info(node, sibling_path[i]); - node = NCT::merkle_hash(node, sibling_path[i]); - } - index >>= uint256_t(1); - } - info("root: ", node); - return node; // root -} +// template +// typename NCT::fr root_from_sibling_path_trace(typename NCT::fr const& leaf, +// typename NCT::fr const& leaf_index, +// std::array const& sibling_path) +// { +// auto node = leaf; +// uint256_t index = leaf_index; +// for (size_t i = 0; i < N; i++) { +// if (index & 1) { +// info(sibling_path[i], node); +// node = NCT::merkle_hash(sibling_path[i], node); +// } else { +// info(node, sibling_path[i]); +// node = NCT::merkle_hash(node, sibling_path[i]); +// } +// index >>= uint256_t(1); +// } +// info("root: ", node); +// return node; // root +// } /** * @brief Get the sibling path of an item in a given merkle tree @@ -256,19 +276,19 @@ std::array get_sibling_path(MerkleTree& tree, size_t leaf_index, size_t c return sibling_path; } -template -void check_membership_trace(Builder& builder, - typename NCT::fr const& value, - typename NCT::fr const& index, - std::array const& sibling_path, - typename NCT::fr const& root, - std::string const& msg) -{ - const auto calculated_root = root_from_sibling_path_trace(value, index, sibling_path); - builder.do_assert(calculated_root == root, - std::string("Membership check failed: ") + msg, - aztec3::utils::CircuitErrorCode::MEMBERSHIP_CHECK_FAILED); -} +// template +// void check_membership_trace(Builder& builder, +// typename NCT::fr const& value, +// typename NCT::fr const& index, +// std::array const& sibling_path, +// typename NCT::fr const& root, +// std::string const& msg) +// { +// const auto calculated_root = root_from_sibling_path_trace(value, index, sibling_path); +// builder.do_assert(calculated_root == root, +// std::string("Membership check failed: ") + msg, +// aztec3::utils::CircuitErrorCode::MEMBERSHIP_CHECK_FAILED); +// } template void check_membership(Builder& builder, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp index bf25fe352c7..565868010ec 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp @@ -30,31 +30,32 @@ void assert_equal_constants(DummyBuilder& builder, AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, BaseOrMergeRollupPublicInputs const& right); -template -AppendOnlySnapshot insert_subtree_to_snapshot_tree_traced(DummyBuilder& builder, - AppendOnlySnapshot snapshot, - std::array siblingPath, - NT::fr emptySubtreeRoot, - NT::fr subtreeRootToInsert, - uint8_t subtreeDepth, - std::string const& emptySubtreeCheckErrorMessage) -{ - auto leafIndexAtDepth = snapshot.next_available_leaf_index >> subtreeDepth; +// template +// AppendOnlySnapshot insert_subtree_to_snapshot_tree_traced(DummyBuilder& builder, +// AppendOnlySnapshot snapshot, +// std::array siblingPath, +// NT::fr emptySubtreeRoot, +// NT::fr subtreeRootToInsert, +// uint8_t subtreeDepth, +// std::string const& emptySubtreeCheckErrorMessage) +// { +// auto leafIndexAtDepth = snapshot.next_available_leaf_index >> subtreeDepth; - // Check that the current root is correct and that there is an empty subtree at the insertion location - check_membership_trace( - builder, emptySubtreeRoot, leafIndexAtDepth, siblingPath, snapshot.root, emptySubtreeCheckErrorMessage); +// // Check that the current root is correct and that there is an empty subtree at the insertion location +// check_membership_trace( +// builder, emptySubtreeRoot, leafIndexAtDepth, siblingPath, snapshot.root, emptySubtreeCheckErrorMessage); - // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. - auto new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); +// // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels +// up. auto new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); - // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x - auto new_next_available_leaf_index = snapshot.next_available_leaf_index + (static_cast(1) << subtreeDepth); +// // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x +// auto new_next_available_leaf_index = snapshot.next_available_leaf_index + (static_cast(1) << +// subtreeDepth); - AppendOnlySnapshot newTreeSnapshot = { .root = new_root, - .next_available_leaf_index = new_next_available_leaf_index }; - return newTreeSnapshot; -} +// AppendOnlySnapshot newTreeSnapshot = { .root = new_root, +// .next_available_leaf_index = new_next_available_leaf_index }; +// return newTreeSnapshot; +// } template AppendOnlySnapshot insert_subtree_to_snapshot_tree(DummyBuilder& builder, AppendOnlySnapshot snapshot, std::array siblingPath, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp index 01389990f6f..9bc1e7b66f7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp @@ -53,8 +53,6 @@ WASM_EXPORT uint8_t* root_rollup__sim(uint8_t const* root_rollup_inputs_buf, read(root_rollup_inputs_buf, root_rollup_inputs); DummyBuilder builder = DummyBuilder("root_rollup__sim"); - info("rollup inputs"); - info(root_rollup_inputs); RootRollupPublicInputs const public_inputs = root_rollup_circuit(builder, root_rollup_inputs); // serialize public inputs to bytes vec diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 3668d6ea589..6bba1980c19 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -2,6 +2,7 @@ #include "aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp" #include "aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/rollup/components/components.hpp" #include "aztec3/constants.hpp" @@ -148,14 +149,14 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu // write all of the block data into a large vector before hashing // NOTE: the block hash will need to be a public input so that it can be indexed? // TODO: how do we want to build this? as a subtree or is this method fine? - auto block_hash = NT::hash({ left.constants.global_variables.hash(), - right.end_private_data_tree_snapshot.root, - right.end_nullifier_tree_snapshot.root, - right.end_contract_tree_snapshot.root, - end_l1_to_l2_data_roots_tree_snapshot.root }); + auto block_hash = compute_block_hash(left.constants.global_variables, + right.end_private_data_tree_snapshot.root, + right.end_nullifier_tree_snapshot.root, + right.end_contract_tree_snapshot.root, + new_l1_to_l2_messages_tree_snapshot.root); // Update the historic blocks tree - auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree_traced( + auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree( builder, rootRollupInputs.start_historic_blocks_tree_snapshot, rootRollupInputs.new_historic_blocks_tree_sibling_path, diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 5105d7b098e..01bcf3bdd5d 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -5,6 +5,7 @@ import { Buffer } from 'buffer'; import chunk from 'lodash.chunk'; import { + abisComputeBlockHash, abisComputeCommitmentNonce, abisComputeUniqueCommitment, abisSiloCommitment, @@ -16,6 +17,7 @@ import { Fr, FunctionData, FunctionLeafPreimage, + GlobalVariables, NewContractData, PrivateCallStackItem, PublicCallStackItem, @@ -298,6 +300,19 @@ export function siloNullifier(wasm: IWasmModule, contract: AztecAddress, innerNu return abisSiloNullifier(wasm, contract, innerNullifier); } +/** + * Computes the block hash given the blocks globals and roots. + * A siloed nullifier effectively namespaces a nullifier to a specific contract. + * @param wasm - A module providing low-level wasm access. + * @param contract - The contract address. + * @param innerNullifier - The nullifier to silo. + * @returns A siloed nullifier. + */ +export function computeBlockHash(wasm: IWasmModule, globals: GlobalVariables, privateDataTreeRoot: Fr, nullifierTreeRoot: Fr, contractTreeRoot: Fr, l1ToL2DataTreeRoot: Fr): Fr { + wasm.call('pedersen__init'); + return abisComputeBlockHash(wasm, globals, privateDataTreeRoot , nullifierTreeRoot, contractTreeRoot, l1ToL2DataTreeRoot); +} + const ARGS_HASH_CHUNK_SIZE = 32; const ARGS_HASH_CHUNK_COUNT = 16; diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index fb522144789..8c37b836d79 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -21,6 +21,7 @@ import { Fr, FunctionData, G1AffineElement, + GlobalVariables, KernelCircuitPublicInputs, NativeAggregationState, NewContractData, @@ -42,6 +43,55 @@ import { toBuffer, } from './types.js'; +interface MsgpackGlobalVariables { + chain_id: Buffer; + version: Buffer; + block_number: Buffer; + timestamp: Buffer; +} + +export function toGlobalVariables(o: MsgpackGlobalVariables): GlobalVariables { + if (o.chain_id === undefined) { + throw new Error('Expected chain_id in GlobalVariables deserialization'); + } + if (o.version === undefined) { + throw new Error('Expected version in GlobalVariables deserialization'); + } + if (o.block_number === undefined) { + throw new Error('Expected block_number in GlobalVariables deserialization'); + } + if (o.timestamp === undefined) { + throw new Error('Expected timestamp in GlobalVariables deserialization'); + } + return new GlobalVariables( + Fr.fromBuffer(o.chain_id), + Fr.fromBuffer(o.version), + Fr.fromBuffer(o.block_number), + Fr.fromBuffer(o.timestamp), + ); +} + +export function fromGlobalVariables(o: GlobalVariables): MsgpackGlobalVariables { + if (o.chainId === undefined) { + throw new Error('Expected chainId in GlobalVariables serialization'); + } + if (o.version === undefined) { + throw new Error('Expected version in GlobalVariables serialization'); + } + if (o.blockNumber === undefined) { + throw new Error('Expected blockNumber in GlobalVariables serialization'); + } + if (o.timestamp === undefined) { + throw new Error('Expected timestamp in GlobalVariables serialization'); + } + return { + chain_id: toBuffer(o.chainId), + version: toBuffer(o.version), + block_number: toBuffer(o.blockNumber), + timestamp: toBuffer(o.timestamp), + }; +} + interface MsgpackG1AffineElement { x: Buffer; y: Buffer; @@ -1458,6 +1508,24 @@ export function abisSiloCommitment(wasm: IWasmModule, arg0: Address, arg1: Fr): export function abisSiloNullifier(wasm: IWasmModule, arg0: Address, arg1: Fr): Fr { return Fr.fromBuffer(callCbind(wasm, 'abis__silo_nullifier', [toBuffer(arg0), toBuffer(arg1)])); } +export function abisComputeBlockHash( + wasm: IWasmModule, + arg0: GlobalVariables, + arg1: Fr, + arg2: Fr, + arg3: Fr, + arg4: Fr, +): Fr { + return Fr.fromBuffer( + callCbind(wasm, 'abis__compute_block_hash', [ + fromGlobalVariables(arg0), + toBuffer(arg1), + toBuffer(arg2), + toBuffer(arg3), + toBuffer(arg4), + ]), + ); +} export function privateKernelDummyPreviousKernel(wasm: IWasmModule): PreviousKernelData { return toPreviousKernelData(callCbind(wasm, 'private_kernel__dummy_previous_kernel', [])); } diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index 1bf5f663ce0..2fa41609f26 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -51,6 +51,7 @@ export { CircuitError, Point, Coordinate, + GlobalVariables } from '../structs/index.js'; /** diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index 10509a5d015..d80e70cbe71 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -1,8 +1,9 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; -import { FieldsOf } from '../index.js'; +import { CircuitsWasm, FieldsOf } from '../index.js'; import { serializeToBuffer } from '../utils/index.js'; +import { pedersenCompressInputs } from '../barretenberg/index.js'; /** * Global variables of the L2 block. diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 2ba1655bc8f..7374ccd41c6 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -297,6 +297,9 @@ describe('L1Publisher integration', () => { console.log(`end state hash: 0x${block.getEndStateHash().toString('hex')}`); console.log(`public inputs hash: 0x${block.getPublicInputsHash().toBuffer().toString('hex')}`); */ + console.log(`start state hash: 0x${block.getStartStateHash().toString('hex')}`); + console.log(`end state hash: 0x${block.getEndStateHash().toString('hex')}`); + await publisher.processL2Block(block); const logs = await publicClient.getLogs({ diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 8ad6780ceb6..7b98c26b911 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -26,7 +26,7 @@ import { VerificationKey, makeTuple, } from '@aztec/circuits.js'; -import { computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeContractLeaf } from '@aztec/circuits.js/abis'; import { toFriendlyJSON } from '@aztec/circuits.js/utils'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -45,6 +45,7 @@ import { ProcessedTx } from '../sequencer/processed_tx.js'; import { RollupSimulator } from '../simulator/index.js'; import { BlockBuilder } from './index.js'; import { AllowedTreeNames, OutputWithTreeSnapshot } from './types.js'; +import { pedersenCompressInputs } from '@aztec/circuits.js/barretenberg'; const frToBigInt = (fr: Fr) => toBigIntBE(fr.toBuffer()); const bigintToFr = (num: bigint) => new Fr(num); @@ -107,6 +108,9 @@ export class SoloBlockBuilder implements BlockBuilder { ].map(tree => this.getTreeSnapshot(tree)), ); + console.log("blocks tree start"); + console.log(startHistoricBlocksTreeSnapshot); + // Check txs are good for processing this.validateTxs(txs); @@ -114,6 +118,7 @@ export class SoloBlockBuilder implements BlockBuilder { const [circuitsOutput, proof] = await this.runCircuits(globalVariables, txs, newL1ToL2Messages); const { + blockHash, endPrivateDataTreeSnapshot, endNullifierTreeSnapshot, endContractTreeSnapshot, @@ -182,6 +187,10 @@ export class SoloBlockBuilder implements BlockBuilder { newUnencryptedLogs, }); + + console.log("l2Block"); + console.log(l2Block); + if (!l2Block.getCalldataHash().equals(circuitsOutput.sha256CalldataHash())) { throw new Error( `Calldata hash mismatch, ${l2Block.getCalldataHash().toString('hex')} == ${circuitsOutput @@ -305,6 +314,7 @@ export class SoloBlockBuilder implements BlockBuilder { newL1ToL2Messages.map(m => m.toBuffer()), ); + // Simulate and get proof for the root circuit const rootOutput = await this.simulator.rootRollupCircuit(rootInput); @@ -314,11 +324,28 @@ export class SoloBlockBuilder implements BlockBuilder { // and validate them against the output of the root circuit simulation this.debug(`Updating and validating root trees`); await this.db.updateHistoricRootsTrees(); - await this.validateRootOutput(rootOutput); + + // Calculate the block hash and add it to the historic block hashes tree + // TODO(Maddiaa): clean this up a bit - might be worth putting in updateHistoricRootsTrees below + const blockHash = await this.calculateBlockHash(left[0].constants.globalVariables); + console.log("block hash"); + console.log(blockHash.toString(true)); + await this.db.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); + + await this.validateRootOutput(blockHash, rootOutput); return [rootOutput, rootProof]; } + protected async calculateBlockHash(globals: GlobalVariables) { + const roots = this.db.getCommitmentTreeRoots(); + const wasm = await CircuitsWasm.get(); + // TODO(Maddiaa): Maybe pass in all of the roots? + // cleanup + const blockHash = computeBlockHash(wasm, globals, Fr.fromBuffer(roots.privateDataTreeRoot), Fr.fromBuffer(roots.nullifierTreeRoot), Fr.fromBuffer(roots.contractDataTreeRoot), Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot)); + return blockHash; + } + // Validate that the new roots we calculated from manual insertions match the outputs of the simulation protected async validateTrees(rollupOutput: BaseOrMergeRollupPublicInputs | RootRollupPublicInputs) { await Promise.all([ @@ -330,12 +357,13 @@ export class SoloBlockBuilder implements BlockBuilder { } // Validate that the roots of all local trees match the output of the root circuit simulation - protected async validateRootOutput(rootOutput: RootRollupPublicInputs) { + protected async validateRootOutput(blockHash: Fr, rootOutput: RootRollupPublicInputs) { await Promise.all([ this.validateTrees(rootOutput), this.validateRootTree(rootOutput, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, 'Contract'), this.validateRootTree(rootOutput, MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, 'PrivateData'), this.validateRootTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, 'L1ToL2Message'), + this.validateBlocksTree(blockHash, rootOutput), this.validateTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_TREE, 'L1ToL2Message'), ]); } @@ -351,6 +379,20 @@ export class SoloBlockBuilder implements BlockBuilder { this.validateSimulatedTree(localTree, simulatedTree, name, `Roots ${name}`); } + // TODO maybe use the above method somehow + protected async validateBlocksTree( + blockHash: Fr, + rootOutput: RootRollupPublicInputs, + ) { + if (!blockHash.equals(rootOutput.blockHash)) { + // TODO( MADDIAA): we might not need this as probably will pass it in as a circuit pub input + throw new Error(`Block hash ${blockHash} does not match block hash produced in circuit ${rootOutput.blockHash}`); + } + const localTree = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); + const simulatedTree = rootOutput[`endHistoricBlocksTreeSnapshot`]; + this.validateSimulatedTree(localTree, simulatedTree, "Blocks"); + } + /** * Validates that the root of the public data tree matches the output of the circuit simulation. * @param output - The output of the circuit simulation. @@ -385,7 +427,7 @@ export class SoloBlockBuilder implements BlockBuilder { protected validateSimulatedTree( localTree: AppendOnlyTreeSnapshot, simulatedTree: AppendOnlyTreeSnapshot, - name: 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message', + name: 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message' | 'Blocks', label?: string, ) { if (!simulatedTree.root.toBuffer().equals(localTree.root.toBuffer())) { diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index 1f89bb16097..b00efc1971a 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -594,6 +594,7 @@ export class L2Block { this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.startHistoricBlocksTreeSnapshot, ); + console.log("start hash inputs: ", inputValue.toString("hex")) return sha256(inputValue); } @@ -614,6 +615,7 @@ export class L2Block { this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.endHistoricBlocksTreeSnapshot, ); + console.log("end hash inputs: ", inputValue.toString("hex")) return sha256(inputValue); } From 55fbd5feb96e54c6a5ee07048231c2b541e07f15 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:21:04 +0000 Subject: [PATCH 11/58] feat: add block tree checking in ts --- circuits/cpp/src/aztec3/circuits/hash.hpp | 9 ++- .../root/native_root_rollup_circuit.cpp | 3 +- yarn-project/circuits.js/src/abis/abis.ts | 4 +- .../circuits.js/src/cbind/circuits.gen.ts | 2 + .../block_builder/solo_block_builder.test.ts | 16 ++++- .../src/block_builder/solo_block_builder.ts | 58 +++++++++---------- .../src/block_builder/types.ts | 2 +- 7 files changed, 51 insertions(+), 43 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index d9d4561734b..a6593445ab3 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -142,17 +142,16 @@ template typename NCT::fr compute_block_hash(typename abis::Globa typename NCT::fr private_data_tree_root, typename NCT::fr nullifier_tree_root, typename NCT::fr contract_tree_root, - typename NCT::fr l1_to_l2_data_tree_root) + typename NCT::fr l1_to_l2_data_tree_root, + typename NCT::fr public_data_tree_root) { using fr = typename NCT::fr; std::vector const inputs = { - globals.hash(), private_data_tree_root, nullifier_tree_root, contract_tree_root, l1_to_l2_data_tree_root + globals.hash(), private_data_tree_root, nullifier_tree_root, + contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, }; - info("globals: ", globals); - info("block hash inputs: ", inputs); - // TODO(Maddiaa): does this need an index? return NCT::compress(inputs); } diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 6bba1980c19..10e345faba7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -153,7 +153,8 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu right.end_private_data_tree_snapshot.root, right.end_nullifier_tree_snapshot.root, right.end_contract_tree_snapshot.root, - new_l1_to_l2_messages_tree_snapshot.root); + new_l1_to_l2_messages_tree_snapshot.root, + right.end_public_data_tree_root); // Update the historic blocks tree auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree( diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 01bcf3bdd5d..72ae8706b92 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -308,9 +308,9 @@ export function siloNullifier(wasm: IWasmModule, contract: AztecAddress, innerNu * @param innerNullifier - The nullifier to silo. * @returns A siloed nullifier. */ -export function computeBlockHash(wasm: IWasmModule, globals: GlobalVariables, privateDataTreeRoot: Fr, nullifierTreeRoot: Fr, contractTreeRoot: Fr, l1ToL2DataTreeRoot: Fr): Fr { +export function computeBlockHash(wasm: IWasmModule, globals: GlobalVariables, privateDataTreeRoot: Fr, nullifierTreeRoot: Fr, contractTreeRoot: Fr, l1ToL2DataTreeRoot: Fr, publicDataTreeRoot: Fr): Fr { wasm.call('pedersen__init'); - return abisComputeBlockHash(wasm, globals, privateDataTreeRoot , nullifierTreeRoot, contractTreeRoot, l1ToL2DataTreeRoot); + return abisComputeBlockHash(wasm, globals, privateDataTreeRoot , nullifierTreeRoot, contractTreeRoot, l1ToL2DataTreeRoot, publicDataTreeRoot); } const ARGS_HASH_CHUNK_SIZE = 32; diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 8c37b836d79..e791d83ed07 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -1515,6 +1515,7 @@ export function abisComputeBlockHash( arg2: Fr, arg3: Fr, arg4: Fr, + arg5: Fr, ): Fr { return Fr.fromBuffer( callCbind(wasm, 'abis__compute_block_hash', [ @@ -1523,6 +1524,7 @@ export function abisComputeBlockHash( toBuffer(arg2), toBuffer(arg3), toBuffer(arg4), + toBuffer(arg5), ]), ); } diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 346f9c8b006..8454a874025 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -18,7 +18,7 @@ import { makeTuple, range, } from '@aztec/circuits.js'; -import { computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeContractLeaf } from '@aztec/circuits.js/abis'; import { fr, makeBaseOrMergeRollupPublicInputs, @@ -149,6 +149,10 @@ describe('sequencer/solo_block_builder', () => { await expectsDb.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGES_TREE, asBuffer); }; + const updateHistoricBlocksTree = async (blockHash: Fr) => { + await expectsDb.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); + }; + const getTreeSnapshot = async (tree: MerkleTreeId) => { const treeInfo = await expectsDb.getTreeInfo(tree); return new AppendOnlyTreeSnapshot(Fr.fromBuffer(treeInfo.root), Number(treeInfo.size)); @@ -171,6 +175,7 @@ describe('sequencer/solo_block_builder', () => { const txsLeft = [tx, await makeEmptyProcessedTx()]; const txsRight = [await makeEmptyProcessedTx(), await makeEmptyProcessedTx()]; + // Calculate what would be the tree roots after the txs from the first base rollup land and update mock circuit output await updateExpectedTreesFromTxs(txsLeft); @@ -194,6 +199,7 @@ describe('sequencer/solo_block_builder', () => { rootRollupOutput.endNullifierTreeSnapshot = await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE); rootRollupOutput.endPrivateDataTreeSnapshot = await getTreeSnapshot(MerkleTreeId.PRIVATE_DATA_TREE); rootRollupOutput.endPublicDataTreeRoot = (await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE)).root; + rootRollupOutput.endTreeOfHistoricContractTreeRootsSnapshot = await getTreeSnapshot( MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, ); @@ -205,6 +211,12 @@ describe('sequencer/solo_block_builder', () => { MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, ); + // Calculate block hash + rootRollupOutput.globalVariables = globalVariables; + rootRollupOutput.blockHash = computeBlockHash(wasm, globalVariables, rootRollupOutput.endPrivateDataTreeSnapshot.root, rootRollupOutput.endNullifierTreeSnapshot.root, rootRollupOutput.endContractTreeSnapshot.root, rootRollupOutput.endL1ToL2MessageTreeSnapshot.root, rootRollupOutput.endPublicDataTreeRoot); + await updateHistoricBlocksTree(rootRollupOutput.blockHash); + rootRollupOutput.endHistoricBlocksTreeSnapshot = await getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); + const txs = [...txsLeft, ...txsRight]; const newNullifiers = flatMap(txs, tx => tx.data.end.newNullifiers); @@ -222,7 +234,7 @@ describe('sequencer/solo_block_builder', () => { const l2Block = L2Block.fromFields({ number: blockNumber, - globalVariables: rootRollupOutput.globalVariables, + globalVariables, startPrivateDataTreeSnapshot: rootRollupOutput.startPrivateDataTreeSnapshot, endPrivateDataTreeSnapshot: rootRollupOutput.endPrivateDataTreeSnapshot, startNullifierTreeSnapshot: rootRollupOutput.startNullifierTreeSnapshot, diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 7b98c26b911..511fbbdfa1a 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -45,7 +45,6 @@ import { ProcessedTx } from '../sequencer/processed_tx.js'; import { RollupSimulator } from '../simulator/index.js'; import { BlockBuilder } from './index.js'; import { AllowedTreeNames, OutputWithTreeSnapshot } from './types.js'; -import { pedersenCompressInputs } from '@aztec/circuits.js/barretenberg'; const frToBigInt = (fr: Fr) => toBigIntBE(fr.toBuffer()); const bigintToFr = (num: bigint) => new Fr(num); @@ -108,9 +107,6 @@ export class SoloBlockBuilder implements BlockBuilder { ].map(tree => this.getTreeSnapshot(tree)), ); - console.log("blocks tree start"); - console.log(startHistoricBlocksTreeSnapshot); - // Check txs are good for processing this.validateTxs(txs); @@ -118,7 +114,6 @@ export class SoloBlockBuilder implements BlockBuilder { const [circuitsOutput, proof] = await this.runCircuits(globalVariables, txs, newL1ToL2Messages); const { - blockHash, endPrivateDataTreeSnapshot, endNullifierTreeSnapshot, endContractTreeSnapshot, @@ -187,10 +182,6 @@ export class SoloBlockBuilder implements BlockBuilder { newUnencryptedLogs, }); - - console.log("l2Block"); - console.log(l2Block); - if (!l2Block.getCalldataHash().equals(circuitsOutput.sha256CalldataHash())) { throw new Error( `Calldata hash mismatch, ${l2Block.getCalldataHash().toString('hex')} == ${circuitsOutput @@ -257,7 +248,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Run the root rollup with the last two merge rollups (or base, if no merge layers) const [mergeOutputLeft, mergeOutputRight] = mergeRollupInputs; - return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, newL1ToL2Messages); + return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, newL1ToL2Messages, globalVariables); } protected async baseRollupCircuit( @@ -304,6 +295,7 @@ export class SoloBlockBuilder implements BlockBuilder { left: [BaseOrMergeRollupPublicInputs, Proof], right: [BaseOrMergeRollupPublicInputs, Proof], newL1ToL2Messages: Fr[], + globals: GlobalVariables, ): Promise<[RootRollupPublicInputs, Proof]> { this.debug(`Running root rollup circuit`); const rootInput = await this.getRootRollupInput(...left, ...right, newL1ToL2Messages); @@ -326,10 +318,11 @@ export class SoloBlockBuilder implements BlockBuilder { await this.db.updateHistoricRootsTrees(); // Calculate the block hash and add it to the historic block hashes tree - // TODO(Maddiaa): clean this up a bit - might be worth putting in updateHistoricRootsTrees below - const blockHash = await this.calculateBlockHash(left[0].constants.globalVariables); - console.log("block hash"); - console.log(blockHash.toString(true)); + // TODO(Maddiaa): clean this up a bit - it should be put in updateHistoricRootsTrees above + const blockHash = await this.calculateBlockHash(globals); + if (!blockHash.equals(rootOutput.blockHash)) { + throw new Error(`Block hash calculated from the circuit output ${rootOutput.blockHash} does not match the block hash calculated from the data ${blockHash}`); + } await this.db.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); await this.validateRootOutput(blockHash, rootOutput); @@ -338,11 +331,25 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async calculateBlockHash(globals: GlobalVariables) { - const roots = this.db.getCommitmentTreeRoots(); + const [ + privateDataTreeRoot, + nullifierTreeRoot, + contractTreeRoot, + publicDataTreeRoot, + l1ToL2MessageTreeRoot, + ] = (await Promise.all( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + ].map(tree => this.getTreeSnapshot(tree)))).map(r => r.root); + const wasm = await CircuitsWasm.get(); // TODO(Maddiaa): Maybe pass in all of the roots? // cleanup - const blockHash = computeBlockHash(wasm, globals, Fr.fromBuffer(roots.privateDataTreeRoot), Fr.fromBuffer(roots.nullifierTreeRoot), Fr.fromBuffer(roots.contractDataTreeRoot), Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot)); + const blockHash = computeBlockHash(wasm, globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessageTreeRoot, publicDataTreeRoot); return blockHash; } @@ -358,12 +365,13 @@ export class SoloBlockBuilder implements BlockBuilder { // Validate that the roots of all local trees match the output of the root circuit simulation protected async validateRootOutput(blockHash: Fr, rootOutput: RootRollupPublicInputs) { + await Promise.all([ this.validateTrees(rootOutput), this.validateRootTree(rootOutput, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, 'Contract'), this.validateRootTree(rootOutput, MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, 'PrivateData'), this.validateRootTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, 'L1ToL2Message'), - this.validateBlocksTree(blockHash, rootOutput), + this.validateTree(rootOutput, MerkleTreeId.BLOCKS_TREE, 'HistoricBlocks'), this.validateTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_TREE, 'L1ToL2Message'), ]); } @@ -379,20 +387,6 @@ export class SoloBlockBuilder implements BlockBuilder { this.validateSimulatedTree(localTree, simulatedTree, name, `Roots ${name}`); } - // TODO maybe use the above method somehow - protected async validateBlocksTree( - blockHash: Fr, - rootOutput: RootRollupPublicInputs, - ) { - if (!blockHash.equals(rootOutput.blockHash)) { - // TODO( MADDIAA): we might not need this as probably will pass it in as a circuit pub input - throw new Error(`Block hash ${blockHash} does not match block hash produced in circuit ${rootOutput.blockHash}`); - } - const localTree = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); - const simulatedTree = rootOutput[`endHistoricBlocksTreeSnapshot`]; - this.validateSimulatedTree(localTree, simulatedTree, "Blocks"); - } - /** * Validates that the root of the public data tree matches the output of the circuit simulation. * @param output - The output of the circuit simulation. @@ -427,7 +421,7 @@ export class SoloBlockBuilder implements BlockBuilder { protected validateSimulatedTree( localTree: AppendOnlyTreeSnapshot, simulatedTree: AppendOnlyTreeSnapshot, - name: 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message' | 'Blocks', + name: 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message' | 'HistoricBlocks', label?: string, ) { if (!simulatedTree.root.toBuffer().equals(localTree.root.toBuffer())) { diff --git a/yarn-project/sequencer-client/src/block_builder/types.ts b/yarn-project/sequencer-client/src/block_builder/types.ts index 2b97c1973c7..167f6183cda 100644 --- a/yarn-project/sequencer-client/src/block_builder/types.ts +++ b/yarn-project/sequencer-client/src/block_builder/types.ts @@ -5,7 +5,7 @@ import { AppendOnlyTreeSnapshot, BaseOrMergeRollupPublicInputs, RootRollupPublic */ export type AllowedTreeNames = T extends RootRollupPublicInputs - ? 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message' + ? 'PrivateData' | 'Contract' | 'Nullifier' | 'L1ToL2Message' | 'HistoricBlocks' : 'PrivateData' | 'Contract' | 'Nullifier'; /** From f1d9fc7fa5e8d17c99687ea9677a1f69bcfcf8c0 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:40:04 +0000 Subject: [PATCH 12/58] clean --- .../aztec3/circuits/abis/global_variables.hpp | 13 ----- circuits/cpp/src/aztec3/circuits/hash.hpp | 35 ------------- .../circuits/rollup/components/components.hpp | 27 ---------- .../root/native_root_rollup_circuit.cpp | 10 +--- yarn-project/circuits.js/src/abis/abis.ts | 20 ++++++- yarn-project/circuits.js/src/cbind/types.ts | 2 +- .../src/structs/global_variables.ts | 2 +- .../src/structs/rollup/root_rollup.ts | 2 +- .../src/integration_l1_publisher.test.ts | 3 -- .../block_builder/solo_block_builder.test.ts | 11 +++- .../src/block_builder/solo_block_builder.ts | 52 ++++++++++--------- yarn-project/types/src/l2_block.ts | 2 - 12 files changed, 58 insertions(+), 121 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp index 660aaee0eb3..67267e67247 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp @@ -60,19 +60,6 @@ template struct GlobalVariables { return NCT::compress(inputs, GeneratorIndex::GLOBAL_VARIABLES); } - - // TODO(Maddiaa): is this cursed? The linter is shouting at me for doing pointer arithmetic. - std::array to_bytes() const - { - std::array buf; - - auto* ptr = buf.begin(); - chain_id.to_buffer().copy(ptr, ptr += 32); - version.to_buffer().copy(ptr, ptr += 32); - block_number.to_buffer().copy(ptr, ptr += 32); - timestamp.to_buffer().copy(ptr, ptr += 32); - return buf; - } }; template void read(uint8_t const*& it, GlobalVariables& globals) diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index a6593445ab3..60877da44db 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -224,27 +224,6 @@ typename NCT::fr root_from_sibling_path(typename NCT::fr const& leaf, return node; // root } -// template -// typename NCT::fr root_from_sibling_path_trace(typename NCT::fr const& leaf, -// typename NCT::fr const& leaf_index, -// std::array const& sibling_path) -// { -// auto node = leaf; -// uint256_t index = leaf_index; -// for (size_t i = 0; i < N; i++) { -// if (index & 1) { -// info(sibling_path[i], node); -// node = NCT::merkle_hash(sibling_path[i], node); -// } else { -// info(node, sibling_path[i]); -// node = NCT::merkle_hash(node, sibling_path[i]); -// } -// index >>= uint256_t(1); -// } -// info("root: ", node); -// return node; // root -// } - /** * @brief Get the sibling path of an item in a given merkle tree * @@ -275,20 +254,6 @@ std::array get_sibling_path(MerkleTree& tree, size_t leaf_index, size_t c return sibling_path; } -// template -// void check_membership_trace(Builder& builder, -// typename NCT::fr const& value, -// typename NCT::fr const& index, -// std::array const& sibling_path, -// typename NCT::fr const& root, -// std::string const& msg) -// { -// const auto calculated_root = root_from_sibling_path_trace(value, index, sibling_path); -// builder.do_assert(calculated_root == root, -// std::string("Membership check failed: ") + msg, -// aztec3::utils::CircuitErrorCode::MEMBERSHIP_CHECK_FAILED); -// } - template void check_membership(Builder& builder, typename NCT::fr const& value, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp index 565868010ec..2e64593dc65 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/components/components.hpp @@ -2,7 +2,6 @@ #include "init.hpp" -#include "aztec3/circuits/hash.hpp" #include "aztec3/utils/circuit_errors.hpp" using aztec3::circuits::check_membership; @@ -30,32 +29,6 @@ void assert_equal_constants(DummyBuilder& builder, AggregationObject aggregate_proofs(BaseOrMergeRollupPublicInputs const& left, BaseOrMergeRollupPublicInputs const& right); -// template -// AppendOnlySnapshot insert_subtree_to_snapshot_tree_traced(DummyBuilder& builder, -// AppendOnlySnapshot snapshot, -// std::array siblingPath, -// NT::fr emptySubtreeRoot, -// NT::fr subtreeRootToInsert, -// uint8_t subtreeDepth, -// std::string const& emptySubtreeCheckErrorMessage) -// { -// auto leafIndexAtDepth = snapshot.next_available_leaf_index >> subtreeDepth; - -// // Check that the current root is correct and that there is an empty subtree at the insertion location -// check_membership_trace( -// builder, emptySubtreeRoot, leafIndexAtDepth, siblingPath, snapshot.root, emptySubtreeCheckErrorMessage); - -// // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels -// up. auto new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); - -// // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x -// auto new_next_available_leaf_index = snapshot.next_available_leaf_index + (static_cast(1) << -// subtreeDepth); - -// AppendOnlySnapshot newTreeSnapshot = { .root = new_root, -// .next_available_leaf_index = new_next_available_leaf_index }; -// return newTreeSnapshot; -// } template AppendOnlySnapshot insert_subtree_to_snapshot_tree(DummyBuilder& builder, AppendOnlySnapshot snapshot, std::array siblingPath, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 10e345faba7..db48a7a4921 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -139,16 +139,8 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, "historic l1 to l2 message tree roots not empty at location where subtree would be inserted")); - // Build the block tree for this iteration from the tree information, and global variables, and the public inputs + // Build the block hash for this iteration from the tree roots and global variables // Then insert the block into the historic blocks tree - - // TODO: make all of these arrays - and throw into a function somewhere - // NOTES: - // - What goes into the blocks tree? - // - - // write all of the block data into a large vector before hashing - // NOTE: the block hash will need to be a public input so that it can be indexed? - // TODO: how do we want to build this? as a subtree or is this method fine? auto block_hash = compute_block_hash(left.constants.global_variables, right.end_private_data_tree_snapshot.root, right.end_nullifier_tree_snapshot.root, diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 72ae8706b92..18a6b2b27f4 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -308,9 +308,25 @@ export function siloNullifier(wasm: IWasmModule, contract: AztecAddress, innerNu * @param innerNullifier - The nullifier to silo. * @returns A siloed nullifier. */ -export function computeBlockHash(wasm: IWasmModule, globals: GlobalVariables, privateDataTreeRoot: Fr, nullifierTreeRoot: Fr, contractTreeRoot: Fr, l1ToL2DataTreeRoot: Fr, publicDataTreeRoot: Fr): Fr { +export function computeBlockHash( + wasm: IWasmModule, + globals: GlobalVariables, + privateDataTreeRoot: Fr, + nullifierTreeRoot: Fr, + contractTreeRoot: Fr, + l1ToL2DataTreeRoot: Fr, + publicDataTreeRoot: Fr, +): Fr { wasm.call('pedersen__init'); - return abisComputeBlockHash(wasm, globals, privateDataTreeRoot , nullifierTreeRoot, contractTreeRoot, l1ToL2DataTreeRoot, publicDataTreeRoot); + return abisComputeBlockHash( + wasm, + globals, + privateDataTreeRoot, + nullifierTreeRoot, + contractTreeRoot, + l1ToL2DataTreeRoot, + publicDataTreeRoot, + ); } const ARGS_HASH_CHUNK_SIZE = 32; diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index 2fa41609f26..e27a3e463ea 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -51,7 +51,7 @@ export { CircuitError, Point, Coordinate, - GlobalVariables + GlobalVariables, } from '../structs/index.js'; /** diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index d80e70cbe71..ac380defe32 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -1,9 +1,9 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; +import { pedersenCompressInputs } from '../barretenberg/index.js'; import { CircuitsWasm, FieldsOf } from '../index.js'; import { serializeToBuffer } from '../utils/index.js'; -import { pedersenCompressInputs } from '../barretenberg/index.js'; /** * Global variables of the L2 block. diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 750373a8acf..4c3b27a0286 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -62,7 +62,7 @@ export class RootRollupInputs { /** * Sibling path of the new historic block roots tree root. */ - public newHistoricBlocksTreeSiblingPath: Fr[] + public newHistoricBlocksTreeSiblingPath: Fr[], ) { assertMemberLength(this, 'newHistoricPrivateDataTreeRootSiblingPath', PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); assertMemberLength(this, 'newHistoricContractDataTreeRootSiblingPath', CONTRACT_TREE_ROOTS_TREE_HEIGHT); diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 7374ccd41c6..2ba1655bc8f 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -297,9 +297,6 @@ describe('L1Publisher integration', () => { console.log(`end state hash: 0x${block.getEndStateHash().toString('hex')}`); console.log(`public inputs hash: 0x${block.getPublicInputsHash().toBuffer().toString('hex')}`); */ - console.log(`start state hash: 0x${block.getStartStateHash().toString('hex')}`); - console.log(`end state hash: 0x${block.getEndStateHash().toString('hex')}`); - await publisher.processL2Block(block); const logs = await publicClient.getLogs({ diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 8454a874025..7a77436ffee 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -175,7 +175,6 @@ describe('sequencer/solo_block_builder', () => { const txsLeft = [tx, await makeEmptyProcessedTx()]; const txsRight = [await makeEmptyProcessedTx(), await makeEmptyProcessedTx()]; - // Calculate what would be the tree roots after the txs from the first base rollup land and update mock circuit output await updateExpectedTreesFromTxs(txsLeft); @@ -213,7 +212,15 @@ describe('sequencer/solo_block_builder', () => { // Calculate block hash rootRollupOutput.globalVariables = globalVariables; - rootRollupOutput.blockHash = computeBlockHash(wasm, globalVariables, rootRollupOutput.endPrivateDataTreeSnapshot.root, rootRollupOutput.endNullifierTreeSnapshot.root, rootRollupOutput.endContractTreeSnapshot.root, rootRollupOutput.endL1ToL2MessageTreeSnapshot.root, rootRollupOutput.endPublicDataTreeRoot); + rootRollupOutput.blockHash = computeBlockHash( + wasm, + globalVariables, + rootRollupOutput.endPrivateDataTreeSnapshot.root, + rootRollupOutput.endNullifierTreeSnapshot.root, + rootRollupOutput.endContractTreeSnapshot.root, + rootRollupOutput.endL1ToL2MessageTreeSnapshot.root, + rootRollupOutput.endPublicDataTreeRoot, + ); await updateHistoricBlocksTree(rootRollupOutput.blockHash); rootRollupOutput.endHistoricBlocksTreeSnapshot = await getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 511fbbdfa1a..d1b908cdf2b 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -306,7 +306,6 @@ export class SoloBlockBuilder implements BlockBuilder { newL1ToL2Messages.map(m => m.toBuffer()), ); - // Simulate and get proof for the root circuit const rootOutput = await this.simulator.rootRollupCircuit(rootInput); @@ -318,11 +317,7 @@ export class SoloBlockBuilder implements BlockBuilder { await this.db.updateHistoricRootsTrees(); // Calculate the block hash and add it to the historic block hashes tree - // TODO(Maddiaa): clean this up a bit - it should be put in updateHistoricRootsTrees above const blockHash = await this.calculateBlockHash(globals); - if (!blockHash.equals(rootOutput.blockHash)) { - throw new Error(`Block hash calculated from the circuit output ${rootOutput.blockHash} does not match the block hash calculated from the data ${blockHash}`); - } await this.db.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); await this.validateRootOutput(blockHash, rootOutput); @@ -331,27 +326,30 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async calculateBlockHash(globals: GlobalVariables) { - const [ + const [privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, publicDataTreeRoot, l1ToL2MessageTreeRoot] = ( + await Promise.all( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + ].map(tree => this.getTreeSnapshot(tree)), + ) + ).map(r => r.root); + + const wasm = await CircuitsWasm.get(); + const blockHash = computeBlockHash( + wasm, + globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, - publicDataTreeRoot, l1ToL2MessageTreeRoot, - ] = (await Promise.all( - [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - ].map(tree => this.getTreeSnapshot(tree)))).map(r => r.root); - - const wasm = await CircuitsWasm.get(); - // TODO(Maddiaa): Maybe pass in all of the roots? - // cleanup - const blockHash = computeBlockHash(wasm, globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessageTreeRoot, publicDataTreeRoot); + publicDataTreeRoot, + ); return blockHash; - } + } // Validate that the new roots we calculated from manual insertions match the outputs of the simulation protected async validateTrees(rollupOutput: BaseOrMergeRollupPublicInputs | RootRollupPublicInputs) { @@ -365,6 +363,12 @@ export class SoloBlockBuilder implements BlockBuilder { // Validate that the roots of all local trees match the output of the root circuit simulation protected async validateRootOutput(blockHash: Fr, rootOutput: RootRollupPublicInputs) { + // Check the calculated block hash is the same as is calculated within the circuits. + if (!blockHash.equals(rootOutput.blockHash)) { + throw new Error( + `Block hash calculated from the circuit output ${rootOutput.blockHash} does not match the block hash calculated from the data ${blockHash}`, + ); + } await Promise.all([ this.validateTrees(rootOutput), @@ -480,9 +484,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Get historic block tree roots const startHistoricBlocksTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); - const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath( - MerkleTreeId.BLOCKS_TREE, - ); + const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.BLOCKS_TREE); return RootRollupInputs.from({ previousRollupData, @@ -494,7 +496,7 @@ export class SoloBlockBuilder implements BlockBuilder { startL1ToL2MessageTreeSnapshot, startHistoricTreeL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, - newHistoricBlocksTreeSiblingPath + newHistoricBlocksTreeSiblingPath, }); } diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index b00efc1971a..1f89bb16097 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -594,7 +594,6 @@ export class L2Block { this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.startHistoricBlocksTreeSnapshot, ); - console.log("start hash inputs: ", inputValue.toString("hex")) return sha256(inputValue); } @@ -615,7 +614,6 @@ export class L2Block { this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.endHistoricBlocksTreeSnapshot, ); - console.log("end hash inputs: ", inputValue.toString("hex")) return sha256(inputValue); } From 3ae5a4db9f3500120767b3085d218bc70303327c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 10:57:48 +0000 Subject: [PATCH 13/58] lint --- yarn-project/circuits.js/src/structs/global_variables.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index ac380defe32..10509a5d015 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -1,8 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; -import { pedersenCompressInputs } from '../barretenberg/index.js'; -import { CircuitsWasm, FieldsOf } from '../index.js'; +import { FieldsOf } from '../index.js'; import { serializeToBuffer } from '../utils/index.js'; /** From 011a1502faaaba40b1c5e97f0f92f74f5a891617 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 13:09:13 +0000 Subject: [PATCH 14/58] review comments --- .../rollup/root/root_rollup_public_inputs.hpp | 6 -- .../root/native_root_rollup_circuit.cpp | 1 - .../circuits/rollup/test_utils/utils.cpp | 5 -- .../src/structs/rollup/root_rollup.ts | 9 --- .../circuits.js/src/tests/factories.ts | 10 +-- .../block_builder/solo_block_builder.test.ts | 28 ++++---- .../src/block_builder/solo_block_builder.ts | 64 ++++++++----------- 7 files changed, 48 insertions(+), 75 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp index 3c64dba56d5..c6d97a97060 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp @@ -22,8 +22,6 @@ template struct RootRollupPublicInputs { GlobalVariables globalVariables; - fr block_hash; - AppendOnlyTreeSnapshot start_private_data_tree_snapshot; AppendOnlyTreeSnapshot end_private_data_tree_snapshot; @@ -61,7 +59,6 @@ template struct RootRollupPublicInputs { std::vector buf; write(&buf, globalVariables); - write(&buf, block_hash); write(buf, start_private_data_tree_snapshot); write(buf, start_nullifier_tree_snapshot); write(buf, start_contract_tree_snapshot); @@ -113,7 +110,6 @@ template void read(uint8_t const*& it, RootRollupPublicInputs void write(std::vector& buf, RootRollupPublicIn write(buf, obj.end_aggregation_object); write(buf, obj.globalVariables); - write(buf, obj.block_hash); write(buf, obj.start_private_data_tree_snapshot); write(buf, obj.end_private_data_tree_snapshot); write(buf, obj.start_nullifier_tree_snapshot); @@ -169,7 +164,6 @@ template std::ostream& operator<<(std::ostream& os, RootRollupPub { return os << "end_aggregation_object: " << obj.end_aggregation_object << "\n" << "global_variables: " << obj.globalVariables << "\n" - << "block_hash: " << obj.block_hash << "\n" << "start_private_data_tree_snapshot: " << obj.start_private_data_tree_snapshot << "\n" << "end_private_data_tree_snapshot: " << obj.end_private_data_tree_snapshot << "\n" << "start_nullifier_tree_snapshot: " << obj.start_nullifier_tree_snapshot << "\n" diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index db48a7a4921..14b78a6c0ee 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -163,7 +163,6 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu RootRollupPublicInputs public_inputs = { .end_aggregation_object = aggregation_object, .globalVariables = left.constants.global_variables, - .block_hash = block_hash, .start_private_data_tree_snapshot = left.start_private_data_tree_snapshot, .end_private_data_tree_snapshot = right.end_private_data_tree_snapshot, .start_nullifier_tree_snapshot = left.start_nullifier_tree_snapshot, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 141e661ef54..13a7a58768f 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -383,8 +383,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, // Blocks tree auto blocks_tree_sibling_path = get_sibling_path(historic_blocks_tree, 0, 0); - info("problematic sibling path"); - info(blocks_tree_sibling_path); // Blocks tree snapshots AppendOnlyTreeSnapshot const start_historic_blocks_tree_snapshot = { @@ -392,9 +390,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, .next_available_leaf_index = 0, }; - info("snapshot"); - info(start_historic_blocks_tree_snapshot); - RootRollupInputs rootRollupInputs = { .previous_rollup_data = get_previous_rollup_data(builder, std::move(kernel_data)), .new_historic_private_data_tree_root_sibling_path = historic_data_sibling_path, diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 4c3b27a0286..4f393b61a5e 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -112,13 +112,6 @@ export class RootRollupPublicInputs { * Global variables of the L2 block. */ public globalVariables: GlobalVariables, - // constants: ConstantRollupData // TODO maybe don't include this - - /** - * The hash of the block being included into the historic block hashes tree. - */ - public blockHash: Fr, - /** * Snapshot of the private data tree at the start of the rollup. */ @@ -215,7 +208,6 @@ export class RootRollupPublicInputs { return [ fields.endAggregationObject, fields.globalVariables, - fields.blockHash, fields.startPrivateDataTreeSnapshot, fields.endPrivateDataTreeSnapshot, fields.startNullifierTreeSnapshot, @@ -274,7 +266,6 @@ export class RootRollupPublicInputs { return new RootRollupPublicInputs( reader.readObject(AggregationObject), reader.readObject(GlobalVariables), - reader.readFr(), reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index fddd470ffbb..744796f743e 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -699,6 +699,7 @@ export function makeGlobalVariables(seed = 1, blockNumber: number | undefined = export function makeConstantBaseRollupData( seed = 1, blockNumber: number | undefined = undefined, + globalVariables: GlobalVariables | undefined = undefined, ): ConstantBaseRollupData { return ConstantBaseRollupData.from({ startTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(seed), @@ -709,7 +710,7 @@ export function makeConstantBaseRollupData( publicKernelVkTreeRoot: fr(seed + 0x402), baseRollupVkHash: fr(seed + 0x403), mergeRollupVkHash: fr(seed + 0x404), - globalVariables: makeGlobalVariables(seed + 0x405, blockNumber), + globalVariables: globalVariables ?? makeGlobalVariables(seed + 0x405, blockNumber), }); } @@ -768,12 +769,13 @@ export function makeSchnorrSignature(seed = 1): SchnorrSignature { export function makeBaseOrMergeRollupPublicInputs( seed = 0, blockNumber: number | undefined = undefined, + globalVariables: GlobalVariables | undefined = undefined, ): BaseOrMergeRollupPublicInputs { return new BaseOrMergeRollupPublicInputs( RollupTypes.Base, new Fr(0n), makeAggregationObject(seed + 0x100), - makeConstantBaseRollupData(seed + 0x200, blockNumber), + makeConstantBaseRollupData(seed + 0x200, blockNumber, globalVariables), makeAppendOnlyTreeSnapshot(seed + 0x300), makeAppendOnlyTreeSnapshot(seed + 0x400), makeAppendOnlyTreeSnapshot(seed + 0x500), @@ -833,11 +835,11 @@ export function makeRootRollupInputs(seed = 0, blockNumber: number | undefined = export function makeRootRollupPublicInputs( seed = 0, blockNumber: number | undefined = undefined, + globalVariables: GlobalVariables | undefined = undefined, ): RootRollupPublicInputs { return RootRollupPublicInputs.from({ endAggregationObject: makeAggregationObject(seed), - globalVariables: makeGlobalVariables((seed += 0x100), blockNumber), - blockHash: fr((seed += 0x100)), + globalVariables: globalVariables ?? makeGlobalVariables((seed += 0x100), blockNumber), startPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), endPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), startNullifierTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 7a77436ffee..09f4f4079b2 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -107,9 +107,9 @@ describe('sequencer/solo_block_builder', () => { mockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); // Create mock outputs for simulator - baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(); - baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(); - rootRollupOutput = makeRootRollupPublicInputs(); + baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(0, blockNumber, globalVariables); + baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(0, blockNumber, globalVariables); + rootRollupOutput = makeRootRollupPublicInputs(0, blockNumber, globalVariables); // Set up mocks prover.getBaseRollupProof.mockResolvedValue(emptyProof); @@ -149,7 +149,16 @@ describe('sequencer/solo_block_builder', () => { await expectsDb.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGES_TREE, asBuffer); }; - const updateHistoricBlocksTree = async (blockHash: Fr) => { + const updateHistoricBlocksTree = async () => { + const blockHash = computeBlockHash( + wasm, + globalVariables, + rootRollupOutput.endPrivateDataTreeSnapshot.root, + rootRollupOutput.endNullifierTreeSnapshot.root, + rootRollupOutput.endContractTreeSnapshot.root, + rootRollupOutput.endL1ToL2MessageTreeSnapshot.root, + rootRollupOutput.endPublicDataTreeRoot, + ); await expectsDb.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); }; @@ -212,16 +221,7 @@ describe('sequencer/solo_block_builder', () => { // Calculate block hash rootRollupOutput.globalVariables = globalVariables; - rootRollupOutput.blockHash = computeBlockHash( - wasm, - globalVariables, - rootRollupOutput.endPrivateDataTreeSnapshot.root, - rootRollupOutput.endNullifierTreeSnapshot.root, - rootRollupOutput.endContractTreeSnapshot.root, - rootRollupOutput.endL1ToL2MessageTreeSnapshot.root, - rootRollupOutput.endPublicDataTreeRoot, - ); - await updateHistoricBlocksTree(rootRollupOutput.blockHash); + await updateHistoricBlocksTree(); rootRollupOutput.endHistoricBlocksTreeSnapshot = await getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); const txs = [...txsLeft, ...txsRight]; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index d1b908cdf2b..3875e4aefb0 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -248,7 +248,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Run the root rollup with the last two merge rollups (or base, if no merge layers) const [mergeOutputLeft, mergeOutputRight] = mergeRollupInputs; - return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, newL1ToL2Messages, globalVariables); + return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, newL1ToL2Messages); } protected async baseRollupCircuit( @@ -295,7 +295,6 @@ export class SoloBlockBuilder implements BlockBuilder { left: [BaseOrMergeRollupPublicInputs, Proof], right: [BaseOrMergeRollupPublicInputs, Proof], newL1ToL2Messages: Fr[], - globals: GlobalVariables, ): Promise<[RootRollupPublicInputs, Proof]> { this.debug(`Running root rollup circuit`); const rootInput = await this.getRootRollupInput(...left, ...right, newL1ToL2Messages); @@ -315,41 +314,39 @@ export class SoloBlockBuilder implements BlockBuilder { // and validate them against the output of the root circuit simulation this.debug(`Updating and validating root trees`); await this.db.updateHistoricRootsTrees(); + await this.updateHistoricBlocksTree(left[0].constants.globalVariables); - // Calculate the block hash and add it to the historic block hashes tree - const blockHash = await this.calculateBlockHash(globals); - await this.db.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); - - await this.validateRootOutput(blockHash, rootOutput); + await this.validateRootOutput(rootOutput); return [rootOutput, rootProof]; } - protected async calculateBlockHash(globals: GlobalVariables) { - const [privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, publicDataTreeRoot, l1ToL2MessageTreeRoot] = ( - await Promise.all( - [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - ].map(tree => this.getTreeSnapshot(tree)), - ) - ).map(r => r.root); + async updateHistoricBlocksTree(globalVariables: GlobalVariables) { + // Calculate the block hash and add it to the historic block hashes tree + const blockHash = await this.calculateBlockHash(globalVariables); + await this.db.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); + } - const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHash( - wasm, - globals, + protected async calculateBlockHash(globals: GlobalVariables) { + const [ privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, - l1ToL2MessageTreeRoot, publicDataTreeRoot, - ); + l1ToL2MessageTreeRoot, + ] = (await Promise.all( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + ].map(tree => this.getTreeSnapshot(tree)))).map(r => r.root); + + const wasm = await CircuitsWasm.get(); + const blockHash = computeBlockHash(wasm, globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessageTreeRoot, publicDataTreeRoot); return blockHash; - } + } // Validate that the new roots we calculated from manual insertions match the outputs of the simulation protected async validateTrees(rollupOutput: BaseOrMergeRollupPublicInputs | RootRollupPublicInputs) { @@ -362,14 +359,7 @@ export class SoloBlockBuilder implements BlockBuilder { } // Validate that the roots of all local trees match the output of the root circuit simulation - protected async validateRootOutput(blockHash: Fr, rootOutput: RootRollupPublicInputs) { - // Check the calculated block hash is the same as is calculated within the circuits. - if (!blockHash.equals(rootOutput.blockHash)) { - throw new Error( - `Block hash calculated from the circuit output ${rootOutput.blockHash} does not match the block hash calculated from the data ${blockHash}`, - ); - } - + protected async validateRootOutput(rootOutput: RootRollupPublicInputs) { await Promise.all([ this.validateTrees(rootOutput), this.validateRootTree(rootOutput, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, 'Contract'), @@ -484,7 +474,9 @@ export class SoloBlockBuilder implements BlockBuilder { // Get historic block tree roots const startHistoricBlocksTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); - const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.BLOCKS_TREE); + const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath( + MerkleTreeId.BLOCKS_TREE, + ); return RootRollupInputs.from({ previousRollupData, @@ -496,7 +488,7 @@ export class SoloBlockBuilder implements BlockBuilder { startL1ToL2MessageTreeSnapshot, startHistoricTreeL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, - newHistoricBlocksTreeSiblingPath, + newHistoricBlocksTreeSiblingPath }); } From 035c41f5687428154e28a5817fb91d0f9cf1ffa1 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:29:49 +0000 Subject: [PATCH 15/58] fix: include generator indices --- circuits/cpp/src/aztec3/circuits/hash.hpp | 3 +-- circuits/cpp/src/aztec3/constants.hpp | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 60877da44db..08531b1344d 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -152,8 +152,7 @@ template typename NCT::fr compute_block_hash(typename abis::Globa contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, }; - // TODO(Maddiaa): does this need an index? - return NCT::compress(inputs); + return NCT::compress(inputs, aztec3::GeneratorIndex::BLOCK_HASH); } /** diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index c9fe9559d37..e444a0f6b10 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -150,6 +150,7 @@ enum GeneratorIndex { SIGNED_TX_REQUEST, // Size = 7 GLOBAL_VARIABLES, // Size = 4 PARTIAL_CONTRACT_ADDRESS, // Size = 7 + BLOCK_HASH, // Size = 6 /** * Indices with size ≤ 16 */ From 5340a79cd09222cfac5a9cf30e1efd7dbc0bf7a4 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:30:12 +0000 Subject: [PATCH 16/58] lint --- .../src/block_builder/solo_block_builder.ts | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 3875e4aefb0..f45b5d5f33b 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -328,25 +328,30 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async calculateBlockHash(globals: GlobalVariables) { - const [ + const [privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, publicDataTreeRoot, l1ToL2MessageTreeRoot] = ( + await Promise.all( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + ].map(tree => this.getTreeSnapshot(tree)), + ) + ).map(r => r.root); + + const wasm = await CircuitsWasm.get(); + const blockHash = computeBlockHash( + wasm, + globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, - publicDataTreeRoot, l1ToL2MessageTreeRoot, - ] = (await Promise.all( - [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - ].map(tree => this.getTreeSnapshot(tree)))).map(r => r.root); - - const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHash(wasm, globals, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessageTreeRoot, publicDataTreeRoot); + publicDataTreeRoot, + ); return blockHash; - } + } // Validate that the new roots we calculated from manual insertions match the outputs of the simulation protected async validateTrees(rollupOutput: BaseOrMergeRollupPublicInputs | RootRollupPublicInputs) { @@ -474,9 +479,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Get historic block tree roots const startHistoricBlocksTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); - const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath( - MerkleTreeId.BLOCKS_TREE, - ); + const newHistoricBlocksTreeSiblingPath = await getRootTreeSiblingPath(MerkleTreeId.BLOCKS_TREE); return RootRollupInputs.from({ previousRollupData, @@ -488,7 +491,7 @@ export class SoloBlockBuilder implements BlockBuilder { startL1ToL2MessageTreeSnapshot, startHistoricTreeL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, - newHistoricBlocksTreeSiblingPath + newHistoricBlocksTreeSiblingPath, }); } From d9bda7b991429224938650a475b54a92f46f7f4d Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:31:58 +0000 Subject: [PATCH 17/58] update snapshot --- .../__snapshots__/root_rollup.test.ts.snap | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap index a3598124ce3..c9677e7502b 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap @@ -211,57 +211,56 @@ version: 0x101 block_number: 0x102 timestamp: 0x103 -block_hash: 0x200 -start_private_data_tree_snapshot: root: 0x300 +start_private_data_tree_snapshot: root: 0x200 +next_available_leaf_index: 512 + +end_private_data_tree_snapshot: root: 0x300 next_available_leaf_index: 768 -end_private_data_tree_snapshot: root: 0x400 +start_nullifier_tree_snapshot: root: 0x400 next_available_leaf_index: 1024 -start_nullifier_tree_snapshot: root: 0x500 +end_nullifier_tree_snapshot: root: 0x500 next_available_leaf_index: 1280 -end_nullifier_tree_snapshot: root: 0x600 +start_contract_tree_snapshot: root: 0x600 next_available_leaf_index: 1536 -start_contract_tree_snapshot: root: 0x700 +end_contract_tree_snapshot: root: 0x700 next_available_leaf_index: 1792 -end_contract_tree_snapshot: root: 0x800 -next_available_leaf_index: 2048 +start_public_data_tree_root: 0x800 +end_public_data_tree_root: 0x900 +start_tree_of_historic_private_data_tree_roots_snapshot: root: 0xa00 +next_available_leaf_index: 2560 -start_public_data_tree_root: 0x900 -end_public_data_tree_root: 0xa00 -start_tree_of_historic_private_data_tree_roots_snapshot: root: 0xb00 +end_tree_of_historic_private_data_tree_roots_snapshot: root: 0xb00 next_available_leaf_index: 2816 -end_tree_of_historic_private_data_tree_roots_snapshot: root: 0xc00 +start_tree_of_historic_contract_tree_roots_snapshot: root: 0xc00 next_available_leaf_index: 3072 -start_tree_of_historic_contract_tree_roots_snapshot: root: 0xd00 +end_tree_of_historic_contract_tree_roots_snapshot: root: 0xd00 next_available_leaf_index: 3328 -end_tree_of_historic_contract_tree_roots_snapshot: root: 0xe00 +start_l1_to_l2_messages_tree_snapshot: root: 0xe00 next_available_leaf_index: 3584 -start_l1_to_l2_messages_tree_snapshot: root: 0xf00 +end_l1_tol2_messages_tree_snapshot: root: 0xf00 next_available_leaf_index: 3840 -end_l1_tol2_messages_tree_snapshot: root: 0x1000 +start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot: root: 0x1000 next_available_leaf_index: 4096 -start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot: root: 0x1100 +end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot: root: 0x1100 next_available_leaf_index: 4352 -end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot: root: 0x1200 +start_historic_blocks_tree_snapshot: root: 0x1200 next_available_leaf_index: 4608 -start_historic_blocks_tree_snapshot: root: 0x1300 +end_historic_blocks_tree_snapshot: root: 0x1300 next_available_leaf_index: 4864 -end_historic_blocks_tree_snapshot: root: 0x1400 -next_available_leaf_index: 5120 - calldata_hash: [ 0x1 0x2 ] l1_to_l2_messages_hash: [ 0x3 0x4 ] " From 455058a679942ee595af269b3e2f0799c531159d Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 10:34:42 +0000 Subject: [PATCH 18/58] fix: remove references to block num in factories --- .../circuits.js/src/tests/factories.ts | 22 +++++++++---------- .../block_builder/solo_block_builder.test.ts | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 744796f743e..e341e278b70 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -698,7 +698,6 @@ export function makeGlobalVariables(seed = 1, blockNumber: number | undefined = */ export function makeConstantBaseRollupData( seed = 1, - blockNumber: number | undefined = undefined, globalVariables: GlobalVariables | undefined = undefined, ): ConstantBaseRollupData { return ConstantBaseRollupData.from({ @@ -710,7 +709,7 @@ export function makeConstantBaseRollupData( publicKernelVkTreeRoot: fr(seed + 0x402), baseRollupVkHash: fr(seed + 0x403), mergeRollupVkHash: fr(seed + 0x404), - globalVariables: globalVariables ?? makeGlobalVariables(seed + 0x405, blockNumber), + globalVariables: globalVariables ?? makeGlobalVariables(seed + 0x405), }); } @@ -768,14 +767,13 @@ export function makeSchnorrSignature(seed = 1): SchnorrSignature { */ export function makeBaseOrMergeRollupPublicInputs( seed = 0, - blockNumber: number | undefined = undefined, globalVariables: GlobalVariables | undefined = undefined, ): BaseOrMergeRollupPublicInputs { return new BaseOrMergeRollupPublicInputs( RollupTypes.Base, new Fr(0n), makeAggregationObject(seed + 0x100), - makeConstantBaseRollupData(seed + 0x200, blockNumber, globalVariables), + makeConstantBaseRollupData(seed + 0x200, globalVariables), makeAppendOnlyTreeSnapshot(seed + 0x300), makeAppendOnlyTreeSnapshot(seed + 0x400), makeAppendOnlyTreeSnapshot(seed + 0x500), @@ -791,12 +789,15 @@ export function makeBaseOrMergeRollupPublicInputs( /** * Makes arbitrary previous rollup data. * @param seed - The seed to use for generating the previous rollup data. - * @param blockNumber - The block number to use for generating the previous rollup data. + * @param globalVariables - The global variables to use when generating the previous rollup data. * @returns A previous rollup data. */ -export function makePreviousRollupData(seed = 0, blockNumber: number | undefined = undefined): PreviousRollupData { +export function makePreviousRollupData( + seed = 0, + globalVariables: GlobalVariables | undefined = undefined, +): PreviousRollupData { return new PreviousRollupData( - makeBaseOrMergeRollupPublicInputs(seed, blockNumber), + makeBaseOrMergeRollupPublicInputs(seed, globalVariables), makeDynamicSizeBuffer(16, seed + 0x50), makeVerificationKey(), seed + 0x110, @@ -810,9 +811,9 @@ export function makePreviousRollupData(seed = 0, blockNumber: number | undefined * @param blockNumber - The block number to use for generating the root rollup inputs. * @returns A root rollup inputs. */ -export function makeRootRollupInputs(seed = 0, blockNumber: number | undefined = undefined): RootRollupInputs { +export function makeRootRollupInputs(seed = 0, globalVariables?: GlobalVariables): RootRollupInputs { return new RootRollupInputs( - [makePreviousRollupData(seed, blockNumber), makePreviousRollupData(seed + 0x1000, blockNumber)], + [makePreviousRollupData(seed, globalVariables), makePreviousRollupData(seed + 0x1000, globalVariables)], makeTuple(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, fr, 0x2000), makeTuple(CONTRACT_TREE_ROOTS_TREE_HEIGHT, fr, 0x2100), makeTuple(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, fr, 0x2100), @@ -834,12 +835,11 @@ export function makeRootRollupInputs(seed = 0, blockNumber: number | undefined = */ export function makeRootRollupPublicInputs( seed = 0, - blockNumber: number | undefined = undefined, globalVariables: GlobalVariables | undefined = undefined, ): RootRollupPublicInputs { return RootRollupPublicInputs.from({ endAggregationObject: makeAggregationObject(seed), - globalVariables: globalVariables ?? makeGlobalVariables((seed += 0x100), blockNumber), + globalVariables: globalVariables ?? makeGlobalVariables((seed += 0x100)), startPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), endPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), startNullifierTreeSnapshot: makeAppendOnlyTreeSnapshot((seed += 0x100)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 09f4f4079b2..bf06fc09ccf 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -107,9 +107,9 @@ describe('sequencer/solo_block_builder', () => { mockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); // Create mock outputs for simulator - baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(0, blockNumber, globalVariables); - baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(0, blockNumber, globalVariables); - rootRollupOutput = makeRootRollupPublicInputs(0, blockNumber, globalVariables); + baseRollupOutputLeft = makeBaseOrMergeRollupPublicInputs(0, globalVariables); + baseRollupOutputRight = makeBaseOrMergeRollupPublicInputs(0, globalVariables); + rootRollupOutput = makeRootRollupPublicInputs(0, globalVariables); // Set up mocks prover.getBaseRollupProof.mockResolvedValue(emptyProof); From 03cc42eb820d42d072513c8b44f848ad3d83cb1e Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:17:01 +0000 Subject: [PATCH 19/58] feat: read trees against historic block root --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 2 +- .../abis/combined_historic_tree_roots.hpp | 23 +++- .../aztec3/circuits/abis/global_variables.hpp | 11 ++ circuits/cpp/src/aztec3/circuits/hash.hpp | 21 +++- .../base/native_base_rollup_circuit.cpp | 50 ++++++++- .../root/native_root_rollup_circuit.cpp | 12 +- .../circuits/rollup/test_utils/utils.cpp | 103 ++++++++++++++++-- .../circuits/rollup/test_utils/utils.hpp | 11 ++ .../cpp/src/aztec3/utils/circuit_errors.hpp | 1 + 9 files changed, 211 insertions(+), 23 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index ad54b8f1bfd..c7d6136049e 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -444,7 +444,7 @@ CBIND(abis__silo_nullifier, aztec3::circuits::silo_nullifier); /** * @brief Computes the block hash from the block information. */ -CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash); +CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash_with_globals); /** * @brief Generates a signed tx request hash from it's pre-image diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp index a9751da17e8..a2991e28d46 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp @@ -1,6 +1,8 @@ #pragma once #include "private_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" @@ -20,13 +22,18 @@ template struct CombinedHistoricTreeRoots { PrivateHistoricTreeRoots private_historic_tree_roots{}; + // TODO(Maddiaa) Experiment adding the rest of the block hash data here. + fr public_data_tree_root = 0; + fr prev_global_variables_hash = 0; // for serialization, update with new fields - MSGPACK_FIELDS(private_historic_tree_roots); + MSGPACK_FIELDS(private_historic_tree_roots, public_data_tree_root, prev_global_variables_hash); boolean operator==(CombinedHistoricTreeRoots const& other) const { - return private_historic_tree_roots == other.private_historic_tree_roots; + return private_historic_tree_roots == other.private_historic_tree_roots && + public_data_tree_root == other.public_data_tree_root && + prev_global_variables_hash == other.prev_global_variables_hash; }; template CombinedHistoricTreeRoots> to_circuit_type(Builder& builder) const @@ -35,9 +42,12 @@ template struct CombinedHistoricTreeRoots { // Capture the circuit builder: auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(builder); }; + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; CombinedHistoricTreeRoots> data = { to_circuit_type(private_historic_tree_roots), + to_ct(public_data_tree_root), + to_ct(prev_global_variables_hash), }; return data; @@ -47,9 +57,12 @@ template struct CombinedHistoricTreeRoots { { static_assert(std::is_same, NCT>::value); auto to_native_type = [&](T& e) { return e.template to_native_type(); }; + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; CombinedHistoricTreeRoots data = { to_native_type(private_historic_tree_roots), + to_nt(public_data_tree_root), + to_nt(prev_global_variables_hash), }; return data; @@ -60,13 +73,17 @@ template struct CombinedHistoricTreeRoots { static_assert(!(std::is_same::value)); private_historic_tree_roots.set_public(); + public_data_tree_root.set_public(); + prev_global_variables_hash.set_public(); } }; template std::ostream& operator<<(std::ostream& os, CombinedHistoricTreeRoots const& historic_tree_roots) { - return os << "private_historic_tree_roots: " << historic_tree_roots.private_historic_tree_roots << "\n"; + return os << "private_historic_tree_roots: " << historic_tree_roots.private_historic_tree_roots << "\n" + << "public_data_tree_root: " << historic_tree_roots.public_data_tree_root << "\n" + << "prev_global_variables_hash: " << historic_tree_roots.prev_global_variables_hash << "\n"; } } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp index 67267e67247..10a3df5ac6d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp @@ -50,6 +50,7 @@ template struct GlobalVariables { return globals; }; + fr hash() const { std::vector inputs; @@ -60,6 +61,16 @@ template struct GlobalVariables { return NCT::compress(inputs, GeneratorIndex::GLOBAL_VARIABLES); } + + void set_public() + { + static_assert(!(std::is_same::value)); + + chain_id.set_public(); + version.set_public(); + block_number.set_public(); + timestamp.set_public(); + } }; template void read(uint8_t const*& it, GlobalVariables& globals) diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 08531b1344d..6755150a4ff 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -138,7 +138,8 @@ typename NCT::fr silo_nullifier(typename NCT::address contract_address, typename return NCT::compress(inputs, aztec3::GeneratorIndex::OUTER_NULLIFIER); } -template typename NCT::fr compute_block_hash(typename abis::GlobalVariables globals, + +template typename NCT::fr compute_block_hash(typename NCT::fr globals_hash, typename NCT::fr private_data_tree_root, typename NCT::fr nullifier_tree_root, typename NCT::fr contract_tree_root, @@ -147,6 +148,24 @@ template typename NCT::fr compute_block_hash(typename abis::Globa { using fr = typename NCT::fr; + std::vector const inputs = { + globals_hash, private_data_tree_root, nullifier_tree_root, + contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, + }; + + // TODO(Maddiaa): does this need an index? + return NCT::compress(inputs); +} + +template typename NCT::fr compute_block_hash_with_globals(typename abis::GlobalVariables globals, + typename NCT::fr private_data_tree_root, + typename NCT::fr nullifier_tree_root, + typename NCT::fr contract_tree_root, + typename NCT::fr l1_to_l2_data_tree_root, + typename NCT::fr public_data_tree_root) +{ + using fr = typename NCT::fr; + std::vector const inputs = { globals.hash(), private_data_tree_root, nullifier_tree_root, contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 90fba771174..670ffc43909 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -159,6 +159,52 @@ void perform_historical_private_data_tree_membership_checks(DummyBuilder& builde } } +/** + * @brief Check all of the provided commitments against the historical tree roots + * + * @param constantBaseRollupData + * @param baseRollupInputs + */ +void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, BaseRollupInputs const& baseRollupInputs) +{ + // For each of the historic_private_data_tree_membership_checks, we need to do an inclusion proof + // against the historical root provided in the rollup constants + auto historic_root = baseRollupInputs.constants.start_historic_blocks_tree_roots_snapshot.root; + + for (size_t i = 0; i < 2; i++) { + // Rebuild the block hash + auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.historic_tree_roots; + auto historic_tree_roots = historic_block.private_historic_tree_roots; + + auto private_data_tree_root = historic_tree_roots.private_data_tree_root; + auto nullifier_tree_root = historic_tree_roots.nullifier_tree_root; + auto contract_tree_root = historic_tree_roots.contract_tree_root; + auto l1_to_l2_data_tree_root = historic_tree_roots.l1_to_l2_messages_tree_root; + + + auto previous_block_hash = compute_block_hash(historic_block.prev_global_variables_hash, + private_data_tree_root, + nullifier_tree_root, + contract_tree_root, + l1_to_l2_data_tree_root, + historic_block.public_data_tree_root); + + abis::MembershipWitness const historic_root_witness = + baseRollupInputs.historic_blocks_tree_root_membership_witnesses[i]; + + check_membership( + builder, + previous_block_hash, + historic_root_witness.leaf_index, + historic_root_witness.sibling_path, + historic_root, + format(BASE_CIRCUIT_ERROR_MESSAGE_BEGINNING, + "historical root is in rollup constants but not in historic block tree roots at kernel input ", + i, + " to this base rollup circuit")); + } +} + void perform_historical_contract_data_tree_membership_checks(DummyBuilder& builder, BaseRollupInputs const& baseRollupInputs) { @@ -553,9 +599,7 @@ BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyBuilder& builder, BaseRol components::compute_kernels_calldata_hash(baseRollupInputs.kernel_data); // Perform membership checks that the notes provided exist within the historic trees data - perform_historical_private_data_tree_membership_checks(builder, baseRollupInputs); - perform_historical_contract_data_tree_membership_checks(builder, baseRollupInputs); - perform_historical_l1_to_l2_message_tree_membership_checks(builder, baseRollupInputs); + perform_historical_blocks_tree_membership_checks(builder, baseRollupInputs); AggregationObject const aggregation_object = aggregate_proofs(baseRollupInputs); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 14b78a6c0ee..d41c1410fb0 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -141,12 +141,12 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu // Build the block hash for this iteration from the tree roots and global variables // Then insert the block into the historic blocks tree - auto block_hash = compute_block_hash(left.constants.global_variables, - right.end_private_data_tree_snapshot.root, - right.end_nullifier_tree_snapshot.root, - right.end_contract_tree_snapshot.root, - new_l1_to_l2_messages_tree_snapshot.root, - right.end_public_data_tree_root); + auto block_hash = compute_block_hash_with_globals(left.constants.global_variables, + right.end_private_data_tree_snapshot.root, + right.end_nullifier_tree_snapshot.root, + right.end_contract_tree_snapshot.root, + new_l1_to_l2_messages_tree_snapshot.root, + right.end_public_data_tree_root); // Update the historic blocks tree auto end_historic_blocks_tree_snapshot = components::insert_subtree_to_snapshot_tree( diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 13a7a58768f..79504d230b0 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -2,6 +2,7 @@ #include "nullifier_tree_testing_harness.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp" @@ -75,7 +76,9 @@ std::array get_empty_l1_to_l2_messages( } BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + fr prev_global_variables_hash, MerkleTree& private_data_tree, + MerkleTree& nullifier_tree, MerkleTree& contract_tree, MerkleTree& public_data_tree, MerkleTree& l1_to_l2_msg_tree) @@ -92,12 +95,16 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne MerkleTree historic_l1_to_l2_msg_tree = MerkleTree(historic_l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); + MemoryStore historic_blocks_tree_store; + MerkleTree historic_blocks_tree = MerkleTree(historic_blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); + // Historic trees are initialised with an empty root at position 0. historic_private_data_tree.update_element(0, private_data_tree.root()); historic_contract_tree.update_element(0, contract_tree.root()); MemoryStore tmp_store; historic_l1_to_l2_msg_tree.update_element(0, MerkleTree(tmp_store, L1_TO_L2_MSG_TREE_HEIGHT).root()); + ConstantRollupData const constantRollupData = { .start_tree_of_historic_private_data_tree_roots_snapshot = { .root = historic_private_data_tree.root(), @@ -113,15 +120,6 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne }, }; - for (size_t i = 0; i < 2; i++) { - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root = - private_data_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root = - contract_tree.root(); - kernel_data[i] - .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.l1_to_l2_messages_tree_root = - l1_to_l2_msg_tree.root(); - } BaseRollupInputs baseRollupInputs = { .kernel_data = kernel_data, .start_private_data_tree_snapshot = { @@ -186,6 +184,39 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne baseRollupInputs.start_public_data_tree_root = public_data_tree.root(); + // create the original historic blocks tree leaf + auto block_hash = compute_block_hash(prev_global_variables_hash, + private_data_tree.root(), + nullifier_tree.root(), + contract_tree.root(), + l1_to_l2_msg_tree.root(), + public_data_tree.root()); + historic_blocks_tree.update_element(0, block_hash); + baseRollupInputs.constants.start_historic_blocks_tree_roots_snapshot = { + .root = historic_blocks_tree.root(), + .next_available_leaf_index = 1, + }; + + // Set historic tree roots data in the public inputs. + for (size_t i = 0; i < 2; i++) { + kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root = + private_data_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root = + nullifier_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root = + nullifier_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root = + contract_tree.root(); + kernel_data[i] + .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.l1_to_l2_messages_tree_root = + l1_to_l2_msg_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.blocks_tree_root = + historic_blocks_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.public_data_tree_root = public_data_tree.root(); + kernel_data[i].public_inputs.constants.historic_tree_roots.prev_global_variables_hash = + prev_global_variables_hash; + } + // Then we collect all sibling paths for the reads in the left tx, and then apply the update requests while // collecting their paths. And then repeat for the right tx. for (size_t i = 0; i < 2; i++) { @@ -232,6 +263,14 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne }; baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[1] = baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[0]; + baseRollupInputs.historic_blocks_tree_root_membership_witnesses[0] = { + .leaf_index = 0, + .sibling_path = get_sibling_path(historic_blocks_tree, 0, 0), + }; + baseRollupInputs.historic_blocks_tree_root_membership_witnesses[1] = + baseRollupInputs.historic_blocks_tree_root_membership_witnesses[0]; + + baseRollupInputs.kernel_data = kernel_data; return baseRollupInputs; } @@ -248,10 +287,56 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne MemoryStore public_data_tree_store; MerkleTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + return base_rollup_inputs_from_kernels( std::move(kernel_data), private_data_tree, contract_tree, public_data_tree, l1_to_l2_messages_tree); } +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + abis::GlobalVariables global_variables) +{ + MemoryStore private_data_store; + MerkleTree private_data_tree = MerkleTree(private_data_store, PRIVATE_DATA_TREE_HEIGHT); + MemoryStore nullifier_data_store; + MerkleTree nullifier_tree = MerkleTree(nullifier_data_store, PRIVATE_DATA_TREE_HEIGHT); + MemoryStore contract_tree_store; + MerkleTree contract_tree = MerkleTree(contract_tree_store, CONTRACT_TREE_HEIGHT); + MemoryStore l1_to_l2_messages_store; + MerkleTree l1_to_l2_messages_tree = MerkleTree(l1_to_l2_messages_store, L1_TO_L2_MSG_TREE_HEIGHT); + + MemoryStore public_data_tree_store; + MerkleTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + + return base_rollup_inputs_from_kernels(std::move(kernel_data), + global_variables.hash(), + private_data_tree, + nullifier_tree, + contract_tree, + public_data_tree, + l1_to_l2_messages_tree); +} + +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + MerkleTree& private_data_tree, + MerkleTree& contract_tree, + MerkleTree& public_data_tree, + MerkleTree& l1_to_l2_msg_tree) +{ + MemoryStore nullifier_tree_store; + MerkleTree nullifier_tree = MerkleTree(nullifier_tree_store, NULLIFIER_TREE_HEIGHT); + + abis::GlobalVariables prev_globals; + + return base_rollup_inputs_from_kernels(std::move(kernel_data), + prev_globals.hash(), + private_data_tree, + nullifier_tree, + contract_tree, + public_data_tree, + l1_to_l2_msg_tree); +} + std::array, 2> get_previous_rollup_data(DummyBuilder& builder, std::array kernel_data) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp index 4b9a314c938..bf39e70ac0e 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp @@ -47,7 +47,18 @@ using nullifier_tree_testing_values = std::tuple kernel_data); BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + abis::GlobalVariables global_variables); + +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + MerkleTree& private_data_tree, + MerkleTree& contract_tree, + MerkleTree& public_data_tree, + MerkleTree& l1_to_l2_msg_tree); + +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + fr prev_global_variables_hash, MerkleTree& private_data_tree, + MerkleTree& nullifier_tree, MerkleTree& contract_tree, MerkleTree& public_data_tree, MerkleTree& l1_to_l2_msg_tree); diff --git a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp index 12011e3d079..a63cf2a4df4 100644 --- a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp +++ b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp @@ -73,6 +73,7 @@ enum CircuitErrorCode : uint16_t { BASE__INVALID_PUBLIC_DATA_UPDATE_REQUESTS = 4006, BASE__INVALID_CHAIN_ID = 4007, BASE__INVALID_VERSION = 4008, + BASE__INVALID_BLOCK_HASH = 4009, MERGE_CIRCUIT_FAILED = 6000, From 3670fac7bc6f04d5212f9a8d694d4affb8e76ef4 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 14:50:27 +0000 Subject: [PATCH 20/58] feat: remove other checks from the base rollup --- circuits/cpp/src/aztec3/circuits/hash.hpp | 1 - .../src/aztec3/circuits/rollup/base/.test.cpp | 56 +++--------- .../base/native_base_rollup_circuit.cpp | 86 ------------------- 3 files changed, 13 insertions(+), 130 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 6755150a4ff..ff2399a58d5 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -153,7 +153,6 @@ template typename NCT::fr compute_block_hash(typename NCT::fr glo contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, }; - // TODO(Maddiaa): does this need an index? return NCT::compress(inputs); } diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 32d59de3fa6..2e09c166324 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -4,6 +4,7 @@ #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" @@ -631,25 +632,25 @@ TEST_F(base_rollup_tests, native_calldata_hash) run_cbind(inputs, outputs); } -TEST_F(base_rollup_tests, native_compute_membership_historic_private_data_negative) +TEST_F(base_rollup_tests, native_compute_membership_historic_blocks_tree_negative) { // WRITE a negative test that will fail the inclusion proof // Test membership works for empty trees - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_compute_membership_historic_private_data_negative"); + DummyBuilder builder = DummyBuilder("base_rollup_tests__native_compute_membership_historic_blocks_tree_negative"); std::array, 2> const kernel_data = { get_empty_kernel(), get_empty_kernel() }; BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); - MemoryStore private_data_store; - auto private_data_tree = MerkleTree(private_data_store, PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); + MemoryStore blocks_store; + auto blocks_tree = MerkleTree(blocks_store, HISTORIC_BLOCKS_TREE_HEIGHT); // Create an INCORRECT sibling path for the private data tree root in the historic tree roots. - auto hash_path = private_data_tree.get_sibling_path(0); - std::array sibling_path{}; - for (size_t i = 0; i < PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT; ++i) { + auto hash_path = blocks_tree.get_sibling_path(0); + std::array sibling_path{}; + for (size_t i = 0; i < HISTORIC_BLOCKS_TREE_HEIGHT; ++i) { sibling_path[i] = hash_path[i] + 1; } - inputs.historic_private_data_tree_root_membership_witnesses[0] = { + inputs.historic_blocks_tree_root_membership_witnesses[0] = { .leaf_index = 0, .sibling_path = sibling_path, }; @@ -658,43 +659,12 @@ TEST_F(base_rollup_tests, native_compute_membership_historic_private_data_negati aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); ASSERT_TRUE(builder.failed()); - ASSERT_EQ( - builder.get_first_failure().message, - "Membership check failed: base_rollup_circuit: historical root is in rollup constants but not in historic " - "private data tree roots at kernel input 0 to this base rollup circuit"); + ASSERT_EQ(builder.get_first_failure().message, + "Membership check failed: base_rollup_circuit: historical root is in rollup constants but not in " + "historic block tree roots at kernel input 0 to this " + "base rollup circuit"); } -TEST_F(base_rollup_tests, native_compute_membership_historic_contract_tree_negative) -{ - // Test membership works for empty trees - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_compute_membership_historic_contract_tree_negative"); - std::array, 2> const kernel_data = { get_empty_kernel(), get_empty_kernel() }; - BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); - - MemoryStore contract_tree_store; - auto contract_tree = MerkleTree(contract_tree_store, CONTRACT_TREE_ROOTS_TREE_HEIGHT); - - - // Create an INCORRECT sibling path for contract tree root in the historic tree roots. - auto hash_path = contract_tree.get_sibling_path(0); - std::array sibling_path{}; - for (size_t i = 0; i < CONTRACT_TREE_ROOTS_TREE_HEIGHT; ++i) { - sibling_path[i] = hash_path[i] + 1; - } - inputs.historic_contract_tree_root_membership_witnesses[0] = { - .leaf_index = 0, - .sibling_path = sibling_path, - }; - - BaseOrMergeRollupPublicInputs const outputs = - aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); - - ASSERT_TRUE(builder.failed()); - ASSERT_EQ( - builder.get_first_failure().message, - "Membership check failed: base_rollup_circuit: historical root is in rollup constants but not in historic " - "contract data tree roots at kernel input 0 to this base rollup circuit"); -} TEST_F(base_rollup_tests, native_constants_dont_change) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 670ffc43909..20b75161524 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -125,40 +125,6 @@ NT::fr calculate_commitments_subtree(DummyBuilder& builder, BaseRollupInputs con return commitments_tree.root(); } -/** - * @brief Check all of the provided commitments against the historical tree roots - * - * @param constantBaseRollupData - * @param baseRollupInputs - */ -void perform_historical_private_data_tree_membership_checks(DummyBuilder& builder, - BaseRollupInputs const& baseRollupInputs) -{ - // For each of the historic_private_data_tree_membership_checks, we need to do an inclusion proof - // against the historical root provided in the rollup constants - auto historic_root = baseRollupInputs.constants.start_tree_of_historic_private_data_tree_roots_snapshot.root; - - for (size_t i = 0; i < 2; i++) { - NT::fr const leaf = - baseRollupInputs.kernel_data[i] - .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root; - abis::MembershipWitness const historic_root_witness = - baseRollupInputs.historic_private_data_tree_root_membership_witnesses[i]; - - check_membership( - builder, - leaf, - historic_root_witness.leaf_index, - historic_root_witness.sibling_path, - historic_root, - format( - BASE_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historical root is in rollup constants but not in historic private data tree roots at kernel input ", - i, - " to this base rollup circuit")); - } -} - /** * @brief Check all of the provided commitments against the historical tree roots * @@ -205,58 +171,6 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas } } -void perform_historical_contract_data_tree_membership_checks(DummyBuilder& builder, - BaseRollupInputs const& baseRollupInputs) -{ - auto historic_root = baseRollupInputs.constants.start_tree_of_historic_contract_tree_roots_snapshot.root; - - for (size_t i = 0; i < 2; i++) { - NT::fr const leaf = - baseRollupInputs.kernel_data[i] - .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root; - abis::MembershipWitness const historic_root_witness = - baseRollupInputs.historic_contract_tree_root_membership_witnesses[i]; - - check_membership( - builder, - leaf, - historic_root_witness.leaf_index, - historic_root_witness.sibling_path, - historic_root, - format( - BASE_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historical root is in rollup constants but not in historic contract data tree roots at kernel input ", - i, - " to this base rollup circuit")); - } -} - -void perform_historical_l1_to_l2_message_tree_membership_checks(DummyBuilder& builder, - BaseRollupInputs const& baseRollupInputs) -{ - auto historic_root = baseRollupInputs.constants.start_tree_of_historic_l1_to_l2_msg_tree_roots_snapshot.root; - - for (size_t i = 0; i < 2; i++) { - NT::fr const leaf = - baseRollupInputs.kernel_data[i] - .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.l1_to_l2_messages_tree_root; - abis::MembershipWitness const historic_root_witness = - baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[i]; - - check_membership( - builder, - leaf, - historic_root_witness.leaf_index, - historic_root_witness.sibling_path, - historic_root, - format( - BASE_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historical root is in rollup constants but not in historic l1 to l2 data tree roots at kernel input ", - i, - " to this base rollup circuit")); - } -} - NT::fr create_nullifier_subtree( std::array const& nullifier_leaves) { From e0129f83bc96e3be30096d95315c9c2150f747fd Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:03:48 +0000 Subject: [PATCH 21/58] feat: update ts and snapshot --- .../circuits.js/src/cbind/circuits.gen.ts | 22 ++++++++++++++++++- .../kernel/__snapshots__/index.test.ts.snap | 8 +++++++ .../structs/kernel/combined_constant_data.ts | 14 +++++++++--- .../__snapshots__/base_rollup.test.ts.snap | 4 ++++ .../circuits.js/src/tests/factories.ts | 2 +- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 700ef22cb9e..bdb63de836a 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -698,21 +698,41 @@ export function fromPrivateHistoricTreeRoots(o: PrivateHistoricTreeRoots): Msgpa interface MsgpackCombinedHistoricTreeRoots { private_historic_tree_roots: MsgpackPrivateHistoricTreeRoots; + public_data_tree_root: Buffer; + prev_global_variables_hash: Buffer; } export function toCombinedHistoricTreeRoots(o: MsgpackCombinedHistoricTreeRoots): CombinedHistoricTreeRoots { if (o.private_historic_tree_roots === undefined) { throw new Error('Expected private_historic_tree_roots in CombinedHistoricTreeRoots deserialization'); } - return new CombinedHistoricTreeRoots(toPrivateHistoricTreeRoots(o.private_historic_tree_roots)); + if (o.public_data_tree_root === undefined) { + throw new Error('Expected public_data_tree_root in CombinedHistoricTreeRoots deserialization'); + } + if (o.prev_global_variables_hash === undefined) { + throw new Error('Expected prev_global_variables_hash in CombinedHistoricTreeRoots deserialization'); + } + return new CombinedHistoricTreeRoots( + toPrivateHistoricTreeRoots(o.private_historic_tree_roots), + Fr.fromBuffer(o.public_data_tree_root), + Fr.fromBuffer(o.prev_global_variables_hash), + ); } export function fromCombinedHistoricTreeRoots(o: CombinedHistoricTreeRoots): MsgpackCombinedHistoricTreeRoots { if (o.privateHistoricTreeRoots === undefined) { throw new Error('Expected privateHistoricTreeRoots in CombinedHistoricTreeRoots serialization'); } + if (o.publicDataTreeRoot === undefined) { + throw new Error('Expected publicDataTreeRoot in CombinedHistoricTreeRoots serialization'); + } + if (o.prevGlobalVariablesHash === undefined) { + throw new Error('Expected prevGlobalVariablesHash in CombinedHistoricTreeRoots serialization'); + } return { private_historic_tree_roots: fromPrivateHistoricTreeRoots(o.privateHistoricTreeRoots), + public_data_tree_root: toBuffer(o.publicDataTreeRoot), + prev_global_variables_hash: toBuffer(o.prevGlobalVariablesHash), }; } diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index b5c9ff365f4..7a139cd4717 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -419,6 +419,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 +public_data_tree_root: 0x106 +prev_global_variables_hash: 0x107 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -956,6 +958,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 +public_data_tree_root: 0x106 +prev_global_variables_hash: 0x107 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -1465,6 +1469,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 +public_data_tree_root: 0x106 +prev_global_variables_hash: 0x107 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -1699,6 +1705,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 +public_data_tree_root: 0x106 +prev_global_variables_hash: 0x107 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 2a6dd78f921..3e4b6f1aaeb 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -105,10 +105,18 @@ export class CombinedHistoricTreeRoots { * Root of the trees relevant for kernel circuits. */ public readonly privateHistoricTreeRoots: PrivateHistoricTreeRoots, + /** + * Previous globals hash + */ + public readonly prevGlobalVariablesHash: Fr, + /** + * Current public state tree hash. TODO(): THIS IS NOT A NICE SOLUTION TO THIS PROBLEM TO GET THE BLOCK HASH + */ + public readonly publicDataTreeRoot: Fr, ) {} toBuffer() { - return serializeToBuffer(this.privateHistoricTreeRoots); + return serializeToBuffer(this.privateHistoricTreeRoots, this.prevGlobalVariablesHash, this.publicDataTreeRoot); } toString() { @@ -117,7 +125,7 @@ export class CombinedHistoricTreeRoots { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new CombinedHistoricTreeRoots(reader.readObject(PrivateHistoricTreeRoots)); + return new CombinedHistoricTreeRoots(reader.readObject(PrivateHistoricTreeRoots), reader.readFr(), reader.readFr()); } isEmpty() { @@ -125,7 +133,7 @@ export class CombinedHistoricTreeRoots { } static empty() { - return new CombinedHistoricTreeRoots(PrivateHistoricTreeRoots.empty()); + return new CombinedHistoricTreeRoots(PrivateHistoricTreeRoots.empty(), Fr.ZERO, Fr.ZERO); } } diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap index cd0b307febc..27e808f5c28 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap @@ -213,6 +213,8 @@ l1_to_l2_messages_tree_root: 0x203 blocks_tree_root: 0x204 private_kernel_vk_tree_root: 0x205 +public_data_tree_root: 0x205 +prev_global_variables_hash: 0x206 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -456,6 +458,8 @@ l1_to_l2_messages_tree_root: 0x303 blocks_tree_root: 0x304 private_kernel_vk_tree_root: 0x305 +public_data_tree_root: 0x305 +prev_global_variables_hash: 0x306 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index e341e278b70..0794a64473d 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -122,7 +122,7 @@ export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeR * @returns A combined historic tree roots object. */ export function makeCombinedHistoricTreeRoots(seed: number): CombinedHistoricTreeRoots { - return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed)); + return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), fr(seed + 5), fr(seed + 6)); } /** From acd241345d66c8928af9ffd89cab9fd6396d8cab Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 1 Aug 2023 18:41:47 +0000 Subject: [PATCH 22/58] feat: remove old tree checks in base rollup --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 8 +++ .../cpp/src/aztec3/circuits/abis/c_bind.h | 2 + circuits/cpp/src/aztec3/circuits/hash.hpp | 9 ++- .../base/native_base_rollup_circuit.cpp | 8 ++- .../aztec-node/src/aztec-node/server.ts | 7 +- yarn-project/circuits.js/src/abis/abis.ts | 52 +++++++++++++-- .../circuits.js/src/cbind/circuits.gen.ts | 23 +++++++ .../src/structs/global_variables.ts | 10 +++ .../structs/kernel/combined_constant_data.ts | 10 +-- .../circuits.js/src/tests/factories.ts | 4 +- .../block_builder/solo_block_builder.test.ts | 28 ++++---- .../src/block_builder/solo_block_builder.ts | 64 +++++++------------ .../src/sequencer/public_processor.ts | 9 ++- .../src/sequencer/sequencer.ts | 2 +- .../sequencer-client/src/sequencer/utils.ts | 11 +++- .../merkle_tree_operations_facade.ts | 6 +- .../server_world_state_synchroniser.test.ts | 2 +- .../world-state/src/world-state-db/index.ts | 5 +- .../src/world-state-db/merkle_trees.ts | 39 +++++++---- 19 files changed, 203 insertions(+), 96 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index c7d6136049e..5ca145154a6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -446,6 +446,14 @@ CBIND(abis__silo_nullifier, aztec3::circuits::silo_nullifier); */ CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash_with_globals); +// TODO: FIX NAMES +CBIND(abis__compute_block_hash_with_globals_hash, aztec3::circuits::compute_block_hash); + +/** + * @brief Computes the hash of the global variables + */ +CBIND(abis__compute_globals_hash, aztec3::circuits::compute_globals_hash); + /** * @brief Generates a signed tx request hash from it's pre-image * This is a WASM-export that can be called from Typescript. diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 482052d6218..4015371bdef 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -39,6 +39,8 @@ CBIND_DECL(abis__compute_unique_commitment); CBIND_DECL(abis__silo_commitment); CBIND_DECL(abis__silo_nullifier); CBIND_DECL(abis__compute_block_hash); +CBIND_DECL(abis__compute_block_hash_with_globals_hash); +CBIND_DECL(abis__compute_globals_hash); WASM_EXPORT void abis__compute_message_secret_hash(uint8_t const* secret, uint8_t* output); WASM_EXPORT void abis__compute_contract_leaf(uint8_t const* contract_leaf_preimage_buf, uint8_t* output); diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index ff2399a58d5..f75720add79 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -153,7 +153,7 @@ template typename NCT::fr compute_block_hash(typename NCT::fr glo contract_tree_root, l1_to_l2_data_tree_root, public_data_tree_root, }; - return NCT::compress(inputs); + return NCT::compress(inputs, aztec3::GeneratorIndex::BLOCK_HASH); } template typename NCT::fr compute_block_hash_with_globals(typename abis::GlobalVariables globals, @@ -173,6 +173,13 @@ template typename NCT::fr compute_block_hash_with_globals(typenam return NCT::compress(inputs, aztec3::GeneratorIndex::BLOCK_HASH); } +template typename NCT::fr compute_globals_hash(typename abis::GlobalVariables globals) +{ + info("cbind globals hash: ", globals.hash()); + return globals.hash(); +} + + /** * @brief Calculate the Merkle tree root from the sibling path and leaf. * diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 20b75161524..120a22f8809 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -137,6 +137,8 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas // against the historical root provided in the rollup constants auto historic_root = baseRollupInputs.constants.start_historic_blocks_tree_roots_snapshot.root; + info("expected root: ", historic_root); + for (size_t i = 0; i < 2; i++) { // Rebuild the block hash auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.historic_tree_roots; @@ -146,18 +148,20 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas auto nullifier_tree_root = historic_tree_roots.nullifier_tree_root; auto contract_tree_root = historic_tree_roots.contract_tree_root; auto l1_to_l2_data_tree_root = historic_tree_roots.l1_to_l2_messages_tree_root; - + auto public_data_tree_root = historic_block.public_data_tree_root; auto previous_block_hash = compute_block_hash(historic_block.prev_global_variables_hash, private_data_tree_root, nullifier_tree_root, contract_tree_root, l1_to_l2_data_tree_root, - historic_block.public_data_tree_root); + public_data_tree_root); abis::MembershipWitness const historic_root_witness = baseRollupInputs.historic_blocks_tree_root_membership_witnesses[i]; + info("historic root witness: ", historic_root_witness.leaf_index, " ", historic_root_witness.sibling_path); + check_membership( builder, previous_block_hash, diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index f6bf19bc260..d347501515f 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -3,6 +3,7 @@ import { CONTRACT_TREE_HEIGHT, CircuitsWasm, Fr, + GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT, PRIVATE_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; @@ -77,7 +78,11 @@ export class AztecNodeService implements AztecNode { const p2pClient = await createP2PClient(config, new InMemoryTxPool(), archiver); // now create the merkle trees and the world state syncher - const merkleTreeDB = await MerkleTrees.new(levelup(createMemDown()), await CircuitsWasm.get()); + const genesisConfig = GlobalVariables.genesis( + BigInt(config.chainId), + BigInt(config.version), + ); //TODO: throw this in a helper? + const merkleTreeDB = await MerkleTrees.new(genesisConfig, levelup(createMemDown()), await CircuitsWasm.get()); const worldStateSynchroniser = new ServerWorldStateSynchroniser(merkleTreeDB, archiver); // start both and wait for them to sync from the block source diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 18a6b2b27f4..b65dd66c021 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -6,7 +6,9 @@ import chunk from 'lodash.chunk'; import { abisComputeBlockHash, + abisComputeBlockHashWithGlobalsHash, abisComputeCommitmentNonce, + abisComputeGlobalsHash, abisComputeUniqueCommitment, abisSiloCommitment, abisSiloNullifier, @@ -302,11 +304,14 @@ export function siloNullifier(wasm: IWasmModule, contract: AztecAddress, innerNu /** * Computes the block hash given the blocks globals and roots. - * A siloed nullifier effectively namespaces a nullifier to a specific contract. * @param wasm - A module providing low-level wasm access. - * @param contract - The contract address. - * @param innerNullifier - The nullifier to silo. - * @returns A siloed nullifier. + * @param globals - The global variables to put into the block hash. + * @param privateDataTree - The root of the private data tree. + * @param nullifierTreeRoot - The root of the nullifier tree. + * @param contractTreeRoot - The root of the contract tree. + * @param l1ToL2DataTreeRoot - The root of the l1 to l2 data tree. + * @param publicDataTreeRoot - The root of the public data tree. + * @returns The block hash. */ export function computeBlockHash( wasm: IWasmModule, @@ -329,6 +334,45 @@ export function computeBlockHash( ); } + +export function computeBlockHashWithGloabalsHash( + wasm: IWasmModule, + globalsHash: Fr, + privateDataTreeRoot: Fr, + nullifierTreeRoot: Fr, + contractTreeRoot: Fr, + l1ToL2DataTreeRoot: Fr, + publicDataTreeRoot: Fr, +): Fr { + wasm.call('pedersen__init'); + return abisComputeBlockHashWithGlobalsHash( + wasm, + globalsHash, + privateDataTreeRoot, + nullifierTreeRoot, + contractTreeRoot, + l1ToL2DataTreeRoot, + publicDataTreeRoot, + ); +} + +/** + * Computes the globals hash given the globals. + * @param wasm - A module providing low-level wasm access. + * @param globals - The global variables to put into the block hash. + * @returns The globals hash. + */ +export function computeGlobalsHash( + wasm: IWasmModule, + globals: GlobalVariables, +): Fr { + wasm.call('pedersen__init'); + return abisComputeGlobalsHash( + wasm, + globals, + ); +} + const ARGS_HASH_CHUNK_SIZE = 32; const ARGS_HASH_CHUNK_COUNT = 16; diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index bdb63de836a..6a8528ed8b7 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -1548,6 +1548,29 @@ export function abisComputeBlockHash( ]), ); } +export function abisComputeBlockHashWithGlobalsHash( + wasm: IWasmModule, + arg0: Fr, + arg1: Fr, + arg2: Fr, + arg3: Fr, + arg4: Fr, + arg5: Fr, +): Fr { + return Fr.fromBuffer( + callCbind(wasm, 'abis__compute_block_hash_with_globals_hash', [ + toBuffer(arg0), + toBuffer(arg1), + toBuffer(arg2), + toBuffer(arg3), + toBuffer(arg4), + toBuffer(arg5), + ]), + ); +} +export function abisComputeGlobalsHash(wasm: IWasmModule, arg0: GlobalVariables): Fr { + return Fr.fromBuffer(callCbind(wasm, 'abis__compute_globals_hash', [fromGlobalVariables(arg0)])); +} export function privateKernelDummyPreviousKernel(wasm: IWasmModule): PreviousKernelData { return toPreviousKernelData(callCbind(wasm, 'private_kernel__dummy_previous_kernel', [])); } diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index 10509a5d015..170aedfc41d 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -31,6 +31,16 @@ export class GlobalVariables { return new GlobalVariables(...GlobalVariables.getFields(fields)); } + /** + * Get the genesis GlobalVariables given a chainId and version. + * @param chainId - The chainId of the L2 block. + * @param version - The version of the L2 block. + * @returns GlobalVariables for the genesis block. + */ + static genesis(chainId: bigint, version: bigint): GlobalVariables { + return new GlobalVariables(new Fr(chainId), new Fr(version), Fr.zero(), Fr.zero()); + } + static empty(): GlobalVariables { return new GlobalVariables(Fr.zero(), Fr.zero(), Fr.zero(), Fr.zero()); } diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 3e4b6f1aaeb..bf3985d6c6a 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -105,18 +105,18 @@ export class CombinedHistoricTreeRoots { * Root of the trees relevant for kernel circuits. */ public readonly privateHistoricTreeRoots: PrivateHistoricTreeRoots, - /** - * Previous globals hash - */ - public readonly prevGlobalVariablesHash: Fr, /** * Current public state tree hash. TODO(): THIS IS NOT A NICE SOLUTION TO THIS PROBLEM TO GET THE BLOCK HASH */ public readonly publicDataTreeRoot: Fr, + /** + * Previous globals hash + */ + public readonly prevGlobalVariablesHash: Fr, ) {} toBuffer() { - return serializeToBuffer(this.privateHistoricTreeRoots, this.prevGlobalVariablesHash, this.publicDataTreeRoot); + return serializeToBuffer(this.privateHistoricTreeRoots, this.publicDataTreeRoot, this.prevGlobalVariablesHash); } toString() { diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 0794a64473d..ecfea7406fb 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -121,8 +121,8 @@ export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeR * @param seed - The seed to use for generating the combined historic tree roots. * @returns A combined historic tree roots object. */ -export function makeCombinedHistoricTreeRoots(seed: number): CombinedHistoricTreeRoots { - return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), fr(seed + 5), fr(seed + 6)); +export function makeCombinedHistoricTreeRoots(seed: number, globalsHash?: Fr): CombinedHistoricTreeRoots { + return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), globalsHash ?? fr(seed + 5) , fr(seed + 6)); } /** diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index bf06fc09ccf..251fee1b18b 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -96,8 +96,9 @@ describe('sequencer/solo_block_builder', () => { blockNumber = 3; globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO); - builderDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); - expectsDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); + // TODO: really don;t like this init pattern + builderDb = await MerkleTrees.new(levelup(createMemDown()), globalVariables).then(t => t.asLatest()); + expectsDb = await MerkleTrees.new(levelup(createMemDown()), globalVariables).then(t => t.asLatest()); vks = getVerificationKeys(); simulator = mock(); prover = mock(); @@ -121,7 +122,8 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + console.log("global vars: ", globalVariables); + const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, globalVariables); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; @@ -169,7 +171,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(expectsDb); + kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(expectsDb, globalVariables); const tx = await makeProcessedTx( new Tx( @@ -202,7 +204,6 @@ describe('sequencer/solo_block_builder', () => { // Update l1 to l2 data tree // And update the root trees now to create proper output to the root rollup circuit await updateL1ToL2MessagesTree(mockL1ToL2Messages); - await expectsDb.updateHistoricRootsTrees(); rootRollupOutput.endContractTreeSnapshot = await getTreeSnapshot(MerkleTreeId.CONTRACT_TREE); rootRollupOutput.endNullifierTreeSnapshot = await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE); rootRollupOutput.endPrivateDataTreeSnapshot = await getTreeSnapshot(MerkleTreeId.PRIVATE_DATA_TREE); @@ -322,7 +323,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, globalVariables); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), @@ -339,6 +340,7 @@ describe('sequencer/solo_block_builder', () => { processedTx.data.end.encryptedLogsHash = to2Fields(L2Block.computeKernelLogsHash(processedTx.encryptedLogs)); processedTx.data.end.unencryptedLogsHash = to2Fields(L2Block.computeKernelLogsHash(processedTx.unencryptedLogs)); + return processedTx; }; @@ -411,12 +413,6 @@ describe('sequencer/solo_block_builder', () => { updateVals[0] = 19777494491628650244807463906174285795660759352776418619064841306523677458742n; updateVals[1] = 10246291467305176436335175657884940686778521321101740385288169037814567547848n; - await builderDb.batchInsert( - MerkleTreeId.NULLIFIER_TREE, - updateVals.map(v => toBufferBE(v, 32)), - BaseRollupInputs.NULLIFIER_SUBTREE_HEIGHT, - ); - // new added values const tx = await makeEmptyProcessedTx(); tx.data.end.newNullifiers[0] = new Fr( @@ -425,8 +421,16 @@ describe('sequencer/solo_block_builder', () => { tx.data.end.newNullifiers[1] = new Fr( 17490072961923661940560522096125238013953043065748521735636170028491723851741n, ); + const txs = [tx, await makeEmptyProcessedTx(), await makeEmptyProcessedTx(), await makeEmptyProcessedTx()]; + // Must be built after the txs are created + await builderDb.batchInsert( + MerkleTreeId.NULLIFIER_TREE, + updateVals.map(v => toBufferBE(v, 32)), + BaseRollupInputs.NULLIFIER_SUBTREE_HEIGHT, + ); + const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index f45b5d5f33b..1596a1e3f6a 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -26,7 +26,7 @@ import { VerificationKey, makeTuple, } from '@aztec/circuits.js'; -import { computeBlockHash, computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeBlockHashWithGloabalsHash, computeContractLeaf } from '@aztec/circuits.js/abis'; import { toFriendlyJSON } from '@aztec/circuits.js/utils'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -107,6 +107,7 @@ export class SoloBlockBuilder implements BlockBuilder { ].map(tree => this.getTreeSnapshot(tree)), ); + // Check txs are good for processing this.validateTxs(txs); @@ -313,7 +314,7 @@ export class SoloBlockBuilder implements BlockBuilder { // Update the root trees with the latest data and contract tree roots, // and validate them against the output of the root circuit simulation this.debug(`Updating and validating root trees`); - await this.db.updateHistoricRootsTrees(); + await this.db.updateHistoricBlocksTree(left[0].constants.globalVariables); await this.updateHistoricBlocksTree(left[0].constants.globalVariables); await this.validateRootOutput(rootOutput); @@ -367,9 +368,6 @@ export class SoloBlockBuilder implements BlockBuilder { protected async validateRootOutput(rootOutput: RootRollupPublicInputs) { await Promise.all([ this.validateTrees(rootOutput), - this.validateRootTree(rootOutput, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, 'Contract'), - this.validateRootTree(rootOutput, MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, 'PrivateData'), - this.validateRootTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, 'L1ToL2Message'), this.validateTree(rootOutput, MerkleTreeId.BLOCKS_TREE, 'HistoricBlocks'), this.validateTree(rootOutput, MerkleTreeId.L1_TO_L2_MESSAGES_TREE, 'L1ToL2Message'), ]); @@ -546,42 +544,19 @@ export class SoloBlockBuilder implements BlockBuilder { return new MembershipWitness(height, index, assertLength(path.toFieldArray(), height)); } - protected getContractMembershipWitnessFor(tx: ProcessedTx) { - return this.getMembershipWitnessFor( - tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.contractTreeRoot, - MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, - ); - } - protected getDataMembershipWitnessFor(tx: ProcessedTx) { - return this.getMembershipWitnessFor( - tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.privateDataTreeRoot, - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, - ); - } - - protected getL1ToL2MessageMembershipWitnessFor(tx: ProcessedTx) { + protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { + const historicTreeRoots = tx.data.constants.historicTreeRoots; + const {privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot} = historicTreeRoots.privateHistoricTreeRoots; + const wasm = await CircuitsWasm.get(); + const blockHash = computeBlockHashWithGloabalsHash(wasm, historicTreeRoots.prevGlobalVariablesHash, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot, historicTreeRoots.publicDataTreeRoot); return this.getMembershipWitnessFor( - tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, + blockHash, + MerkleTreeId.BLOCKS_TREE, + HISTORIC_BLOCKS_TREE_HEIGHT, ); } - protected getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { - // TODO(MADDIAA): Currently stubbed until logic is implemented - // https://github.com/AztecProtocol/aztec-packages/issues/1162 - void tx; - return Promise.resolve(this.makeEmptyMembershipWitness(HISTORIC_BLOCKS_TREE_HEIGHT)); - // return this.getMembershipWitnessFor( - // tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.historicBlocksTreeRoot, - // MerkleTreeId.HISTORIC_BLOCKS_TREE, - // HISTORIC_BLOCKS_TREE_HEIGHT, - // ); - } - protected async getConstantBaseRollupData(globalVariables: GlobalVariables): Promise { return ConstantBaseRollupData.from({ baseRollupVkHash: DELETE_FR, @@ -729,6 +704,11 @@ export class SoloBlockBuilder implements BlockBuilder { MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), ); + // Note these are no longer needed, but are included to decrease change set + const mockContractMembershipWitnesses = MembershipWitness.empty(CONTRACT_TREE_ROOTS_TREE_HEIGHT, 0n); + const mockPrivateDataMembershipWitnesses = MembershipWitness.empty(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, 0n); + const mockL1ToL2MembershipWitnesses = MembershipWitness.empty(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, 0n); + return BaseRollupInputs.from({ constants, startNullifierTreeSnapshot, @@ -748,16 +728,16 @@ export class SoloBlockBuilder implements BlockBuilder { lowNullifierMembershipWitness: lowNullifierMembershipWitnesses, kernelData: [this.getKernelDataFor(left), this.getKernelDataFor(right)], historicContractsTreeRootMembershipWitnesses: [ - await this.getContractMembershipWitnessFor(left), - await this.getContractMembershipWitnessFor(right), + mockContractMembershipWitnesses, + mockContractMembershipWitnesses ], historicPrivateDataTreeRootMembershipWitnesses: [ - await this.getDataMembershipWitnessFor(left), - await this.getDataMembershipWitnessFor(right), + mockPrivateDataMembershipWitnesses, + mockPrivateDataMembershipWitnesses ], historicL1ToL2MsgTreeRootMembershipWitnesses: [ - await this.getL1ToL2MessageMembershipWitnessFor(left), - await this.getL1ToL2MessageMembershipWitnessFor(right), + mockL1ToL2MembershipWitnesses, + mockL1ToL2MembershipWitnesses ], historicBlocksTreeRootMembershipWitnesses: [ await this.getHistoricTreesMembershipWitnessFor(left), diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 62e47464978..b4b8b2a51d7 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -104,13 +104,12 @@ export class PublicProcessor { /** * Makes an empty processed tx. Useful for padding a block to a power of two number of txs. - * @param chainId - The chain id of the rollup. - * @param version - The version of the rollup. + * @param globalVariables - The global variables for this block. * @returns A processed tx with empty data. */ - public async makeEmptyProcessedTx(chainId: Fr, version: Fr): Promise { - const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db); - return makeEmptyProcessedTx(historicTreeRoots, chainId, version); + public async makeEmptyProcessedTx(globalVariables: GlobalVariables): Promise { + const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db, globalVariables); + return makeEmptyProcessedTx(historicTreeRoots, globalVariables.chainId, globalVariables.version); } protected async processTx(tx: Tx, globalVariables: GlobalVariables): Promise { diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 5b701754a01..3397e8d3fb3 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -164,7 +164,7 @@ export class Sequencer { // Build the new block by running the rollup circuits this.log(`Assembling block with txs ${processedTxs.map(tx => tx.hash).join(', ')}`); - const emptyTx = await processor.makeEmptyProcessedTx(this.chainId, this.version); + const emptyTx = await processor.makeEmptyProcessedTx(globalVariables); const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, globalVariables); this.log(`Assembled block ${block.number}`); diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 4c68c11e1ff..bcbf1e47952 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -1,11 +1,16 @@ -import { CombinedHistoricTreeRoots, Fr, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { CircuitsWasm, CombinedHistoricTreeRoots, Fr, GlobalVariables, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; import { MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations } from '@aztec/world-state'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations) { +export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables) { + const wasm = await CircuitsWasm.get(); + const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); + + return new CombinedHistoricTreeRoots( new PrivateHistoricTreeRoots( Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PRIVATE_DATA_TREE)).root), @@ -15,5 +20,7 @@ export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations) { Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.BLOCKS_TREE)).root), Fr.ZERO, ), + Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE)).root), + prevGlobalsHash, ); } diff --git a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts index 411e1f81697..610a2f86d43 100644 --- a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts +++ b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts @@ -2,6 +2,7 @@ import { LowLeafWitnessData } from '@aztec/merkle-tree'; import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types'; import { CurrentCommitmentTreeRoots, LeafData, MerkleTreeDb, MerkleTreeOperations, TreeInfo } from '../index.js'; +import { GlobalVariables } from '@aztec/circuits.js'; /** * Wraps a MerkleTreeDbOperations to call all functions with a preset includeUncommitted flag. @@ -115,10 +116,11 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations { /** * Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, PRIVATE_DATA_TREE_ROOTS_TREE) * the current roots of the corresponding trees (CONTRACT_TREE, PRIVATE_DATA_TREE). + * @param globalVariables - The current global variables to include in the block hash. * @returns Empty promise. */ - public updateHistoricRootsTrees(): Promise { - return this.trees.updateHistoricRootsTrees(this.includeUncommitted); + public updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise { + return this.trees.updateHistoricBlocksTree(globalVariables, this.includeUncommitted); } /** diff --git a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts index 9f7990560ee..610d5919b72 100644 --- a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts +++ b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts @@ -128,7 +128,7 @@ describe('server_world_state_synchroniser', () => { SiblingPath.ZERO(32, INITIAL_LEAF, pedersen); }; //Promise.resolve(); }), - updateHistoricRootsTrees: jest.fn().mockImplementation(() => Promise.resolve()), + updateHistoricBlocksTree: jest.fn().mockImplementation(() => Promise.resolve()), commit: jest.fn().mockImplementation(() => Promise.resolve()), rollback: jest.fn().mockImplementation(() => Promise.resolve()), handleL2Block: jest.fn().mockImplementation(() => Promise.resolve()), diff --git a/yarn-project/world-state/src/world-state-db/index.ts b/yarn-project/world-state/src/world-state-db/index.ts index 79c454bd30a..4c6f8a50f91 100644 --- a/yarn-project/world-state/src/world-state-db/index.ts +++ b/yarn-project/world-state/src/world-state-db/index.ts @@ -1,4 +1,4 @@ -import { MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js'; +import { GlobalVariables, MAX_NEW_NULLIFIERS_PER_TX } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { LeafData, LowLeafWitnessData } from '@aztec/merkle-tree'; import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types'; @@ -174,7 +174,8 @@ export interface MerkleTreeOperations { * Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, PRIVATE_DATA_TREE_ROOTS_TREE, L1_TO_L2_MESSAGES_TREE_ROOTS_TREE) * the current roots of the corresponding trees (CONTRACT_TREE, PRIVATE_DATA_TREE, L1_TO_L2_MESSAGES_TREE). */ - updateHistoricRootsTrees(): Promise; + // TODO: i currently dont love that the global variabels are leaked in this abstraction + updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise; /** * Batch insert multiple leaves into the tree. diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 05dd52fc9bb..7bca12def71 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -4,6 +4,7 @@ import { CONTRACT_TREE_ROOTS_TREE_HEIGHT, CircuitsWasm, Fr, + GlobalVariables, HISTORIC_BLOCKS_TREE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, @@ -41,6 +42,7 @@ import { PublicTreeId, TreeInfo, } from './index.js'; +import { computeBlockHash, computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A convenience class for managing multiple merkle trees. @@ -53,9 +55,10 @@ export class MerkleTrees implements MerkleTreeDb { /** * Initialises the collection of Merkle Trees. + * @param genesisConfig - The genesis config to use for initialising the trees. * @param optionalWasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). */ - public async init(optionalWasm?: IWasmModule) { + public async init(genesisConfig: GlobalVariables, optionalWasm?: IWasmModule) { const wasm = optionalWasm ?? (await CircuitsWasm.get()); const hasher = new Pedersen(wasm); const contractTree: AppendOnlyTree = await newTree( @@ -137,20 +140,21 @@ export class MerkleTrees implements MerkleTreeDb { this.jobQueue.start(); // The roots trees must contain the empty roots of their data trees - await this.updateHistoricRootsTrees(true); - const historicRootsTrees = [contractTreeRootsTree, privateDataTreeRootsTree, l1Tol2MessagesRootsTree]; + await this.updateHistoricBlocksTree(genesisConfig, true); + const historicRootsTrees = [historicBlocksTree]; await Promise.all(historicRootsTrees.map(tree => tree.commit())); } /** * Method to asynchronously create and initialise a MerkleTrees instance. * @param db - The db instance to use for data persistance. + * @param genesisConfig - Initial global variables to initialise the blockHash. * @param wasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). * @returns - A fully initialised MerkleTrees instance. */ - public static async new(db: levelup.LevelUp, wasm?: IWasmModule) { + public static async new(db: levelup.LevelUp, genesisConfig: GlobalVariables = GlobalVariables.empty(), wasm?: IWasmModule) { const merkleTrees = new MerkleTrees(db); - await merkleTrees.init(wasm); + await merkleTrees.init(genesisConfig, wasm); return merkleTrees; } @@ -180,17 +184,24 @@ export class MerkleTrees implements MerkleTreeDb { /** * Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, PRIVATE_DATA_TREE_ROOTS_TREE, L1_TO_L2_MESSAGES_TREE_ROOTS_TREE) * the current roots of the corresponding trees (CONTRACT_TREE, PRIVATE_DATA_TREE, L1_TO_L2_MESSAGES_TREE). + * @param globals - The global variables to use for hashing. * @param includeUncommitted - Indicates whether to include uncommitted data. */ - public async updateHistoricRootsTrees(includeUncommitted: boolean) { - for (const [newTree, rootTree] of [ - [MerkleTreeId.PRIVATE_DATA_TREE, MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE], - [MerkleTreeId.CONTRACT_TREE, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE], - [MerkleTreeId.L1_TO_L2_MESSAGES_TREE, MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE], - ] as const) { - const newTreeInfo = await this.getTreeInfo(newTree, includeUncommitted); - await this.appendLeaves(rootTree, [newTreeInfo.root]); - } + public async updateHistoricBlocksTree(globals: GlobalVariables, includeUncommitted: boolean) { + const wasm = await CircuitsWasm.get(); + + // TODO maybe use the same pattern as function below + const treePromises = ([ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + ] as const).map(tree => this.getTreeInfo(tree, includeUncommitted)) + const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); + + const blockHash = computeBlockHash(wasm, globals, trees[0], trees[1], trees[2],trees[3], trees[4]); + await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } /** From 2bc675f4e493c51ef0083116a7988f827e993c73 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 14:14:23 +0000 Subject: [PATCH 23/58] fix --- yarn-project/aztec-node/src/aztec-node/server.ts | 3 ++- .../src/block_builder/solo_block_builder.test.ts | 1 - .../sequencer-client/src/block_builder/solo_block_builder.ts | 1 - yarn-project/world-state/src/world-state-db/merkle_trees.ts | 1 + 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index d347501515f..241da5138da 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -82,7 +82,7 @@ export class AztecNodeService implements AztecNode { BigInt(config.chainId), BigInt(config.version), ); //TODO: throw this in a helper? - const merkleTreeDB = await MerkleTrees.new(genesisConfig, levelup(createMemDown()), await CircuitsWasm.get()); + const merkleTreeDB = await MerkleTrees.new(levelup(createMemDown()), genesisConfig, await CircuitsWasm.get()); const worldStateSynchroniser = new ServerWorldStateSynchroniser(merkleTreeDB, archiver); // start both and wait for them to sync from the block source @@ -193,6 +193,7 @@ export class AztecNodeService implements AztecNode { public async sendTx(tx: Tx) { // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value if (tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.isEmpty()) { + // get the globals tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest()); } this.log.info(`Received tx ${await tx.getTxHash()}`); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 251fee1b18b..0343f0736ab 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -122,7 +122,6 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - console.log("global vars: ", globalVariables); const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, globalVariables); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 1596a1e3f6a..deb8ed827c0 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -315,7 +315,6 @@ export class SoloBlockBuilder implements BlockBuilder { // and validate them against the output of the root circuit simulation this.debug(`Updating and validating root trees`); await this.db.updateHistoricBlocksTree(left[0].constants.globalVariables); - await this.updateHistoricBlocksTree(left[0].constants.globalVariables); await this.validateRootOutput(rootOutput); diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 7bca12def71..dcb1999c5f9 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -152,6 +152,7 @@ export class MerkleTrees implements MerkleTreeDb { * @param wasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). * @returns - A fully initialised MerkleTrees instance. */ + // TODO: remove genesis config public static async new(db: levelup.LevelUp, genesisConfig: GlobalVariables = GlobalVariables.empty(), wasm?: IWasmModule) { const merkleTrees = new MerkleTrees(db); await merkleTrees.init(genesisConfig, wasm); From 1b8be8cfc4864935d74066b83acf38a26f63273c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:22:53 +0000 Subject: [PATCH 24/58] fix: get previous globals in transactions --- .../archiver/src/archiver/archiver.ts | 20 +++++ .../aztec-node/src/aztec-node/http-node.ts | 10 +++ .../aztec-node/src/aztec-node/server.ts | 28 ++++--- .../src/aztec_rpc_server/aztec_rpc_server.ts | 79 ++++++++++++++----- .../structs/kernel/combined_constant_data.ts | 2 +- .../src/integration_l1_publisher.test.ts | 11 ++- yarn-project/p2p/src/client/mocks.ts | 9 +++ .../block_builder/solo_block_builder.test.ts | 10 +-- .../src/sequencer/public_processor.ts | 9 ++- .../src/sequencer/sequencer.ts | 8 +- .../sequencer-client/src/sequencer/utils.ts | 2 +- .../types/src/interfaces/aztec-node.ts | 7 ++ yarn-project/types/src/l2_block_source.ts | 7 ++ 13 files changed, 161 insertions(+), 41 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 79169374591..fe4cba1e615 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -267,6 +267,26 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource return this.store.getL2Blocks(from, limit); } + /** + * Gets an l2 block. + * @param number - The block number to return (inclusive). + * @returns The requested L2 block. + */ + public async getL2Block(number: number): Promise { + // TODO CLEAN UP + if (number < 0) { + number = this.store.getBlocksLength(); + if (number === 0) { + return Promise.resolve(undefined); + } + } + const blocks = await this.store.getL2Blocks(number, 1); + if (blocks.length === 0) { + return Promise.resolve(undefined); + } + return blocks[0]; + } + /** * Lookup the L2 contract data for this contract. * Contains the contract's public function bytecode. diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.ts b/yarn-project/aztec-node/src/aztec-node/http-node.ts index 0264828de1f..bf27835d828 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.ts @@ -43,6 +43,16 @@ export class HttpNode implements AztecNode { return respJson.isReady; } + async getBlock(number: number): Promise { + const url = new URL(`${this.baseUrl}/get-block`); + url.searchParams.append('number', number.toString()); + const response = await (await fetch(url.toString())).json(); + const block = response.blocks as string; + if (!block) { + return Promise.resolve(undefined); + } + return Promise.resolve(L2Block.decode(Buffer.from(block, 'hex'))); + } /** * Method to request blocks. Will attempt to return all requested blocks but will return only those available. * @param from - The start of the range of blocks to return. diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 241da5138da..8a1651a7c13 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -78,11 +78,7 @@ export class AztecNodeService implements AztecNode { const p2pClient = await createP2PClient(config, new InMemoryTxPool(), archiver); // now create the merkle trees and the world state syncher - const genesisConfig = GlobalVariables.genesis( - BigInt(config.chainId), - BigInt(config.version), - ); //TODO: throw this in a helper? - const merkleTreeDB = await MerkleTrees.new(levelup(createMemDown()), genesisConfig, await CircuitsWasm.get()); + const merkleTreeDB = await MerkleTrees.new(levelup(createMemDown()), await CircuitsWasm.get()); const worldStateSynchroniser = new ServerWorldStateSynchroniser(merkleTreeDB, archiver); // start both and wait for them to sync from the block source @@ -120,6 +116,15 @@ export class AztecNodeService implements AztecNode { return (await this.p2pClient.isReady()) ?? false; } + /** + * Get the a given block. + * @param number - The block number being requested. + * @returns The blocks requested. + */ + public async getBlock(number: number): Promise{ + return await this.blockSource.getL2Block(number); + } + /** * Method to request blocks. Will attempt to return all requested blocks but will return only those available. * @param from - The start of the range of blocks to return. @@ -191,10 +196,15 @@ export class AztecNodeService implements AztecNode { * @param tx - The transaction to be submitted. */ public async sendTx(tx: Tx) { - // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value - if (tx.data.constants.historicTreeRoots.privateHistoricTreeRoots.isEmpty()) { - // get the globals - tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest()); + // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value - CAN WE remove this i think the + // kernel already supplies it + if (tx.data.constants.historicTreeRoots.isEmpty()) { + + // TODO: make this more robust - base case is for the first rollup + const blockNumber = await this.blockSource.getBlockHeight(); + const prevBlock = await this.getBlock(blockNumber); + const globals = prevBlock ? prevBlock.globalVariables: GlobalVariables.empty(); + tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest(), globals); } this.log.info(`Received tx ${await tx.getTxHash()}`); await this.p2pClient!.sendTx(tx); diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index cc28f44a278..8ee70d15c31 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -5,7 +5,10 @@ import { } from '@aztec/acir-simulator'; import { AztecAddress, + CircuitsWasm, + CombinedHistoricTreeRoots, FunctionData, + GlobalVariables, PartialContractAddress, PrivateHistoricTreeRoots, PrivateKey, @@ -23,6 +26,7 @@ import { DeployedContract, ExecutionRequest, KeyStore, + L2Block, L2BlockL2Logs, LogType, MerkleTreeId, @@ -44,6 +48,7 @@ import { KernelOracle } from '../kernel_oracle/index.js'; import { KernelProver } from '../kernel_prover/kernel_prover.js'; import { getAcirSimulator } from '../simulator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A remote Aztec RPC Client implementation. @@ -154,6 +159,17 @@ export class AztecRPCServer implements AztecRPC { return await this.node.getPublicStorageAt(contract, storageSlot.value); } + public async getBlock(blockNumber: number): Promise { + // If a negative block number is provided the current block height is fetched. + if (blockNumber < 0){ + blockNumber = await this.node.getBlockHeight(); + + // TODO: FIX HACK + if (blockNumber == 0) return undefined; + } + return await this.node.getBlock(blockNumber); + } + public async isContractDeployed(contractAddress: AztecAddress): Promise { return !!(await this.node.getContractInfo(contractAddress)); } @@ -172,6 +188,7 @@ export class AztecRPCServer implements AztecRPC { const newContract = deployedContractAddress ? await this.db.getContract(deployedContractAddress) : undefined; const tx = await this.#simulateAndProve(txRequest, newContract); + console.log(tx); await this.db.addTx( TxDao.from({ @@ -321,31 +338,20 @@ export class AztecRPCServer implements AztecRPC { ); const portalContract = await contractDataOracle.getPortalContractAddress(contractAddress); - const currentRoots = this.db.getTreeRoots(); - const historicRoots = PrivateHistoricTreeRoots.from({ - contractTreeRoot: currentRoots[MerkleTreeId.CONTRACT_TREE], - nullifierTreeRoot: currentRoots[MerkleTreeId.NULLIFIER_TREE], - privateDataTreeRoot: currentRoots[MerkleTreeId.PRIVATE_DATA_TREE], - l1ToL2MessagesTreeRoot: currentRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], - blocksTreeRoot: currentRoots[MerkleTreeId.BLOCKS_TREE], - privateKernelVkTreeRoot: Fr.ZERO, - }); - return { contractAddress, functionAbi, portalContract, - historicRoots, }; } - async #simulate(txRequest: TxExecutionRequest, contractDataOracle?: ContractDataOracle) { + async #simulate(txRequest: TxExecutionRequest, prevBlockData: CombinedHistoricTreeRoots, contractDataOracle?: ContractDataOracle, ) { // TODO - Pause syncing while simulating. if (!contractDataOracle) { contractDataOracle = new ContractDataOracle(this.db, this.node); } - const { contractAddress, functionAbi, portalContract, historicRoots } = await this.#getSimulationParameters( + const { contractAddress, functionAbi, portalContract} = await this.#getSimulationParameters( txRequest, contractDataOracle, ); @@ -354,7 +360,7 @@ export class AztecRPCServer implements AztecRPC { try { this.log('Executing simulator...'); - const result = await simulator.run(txRequest, functionAbi, contractAddress, portalContract, historicRoots); + const result = await simulator.run(txRequest, functionAbi, contractAddress, portalContract, prevBlockData.privateHistoricTreeRoots); this.log('Simulation completed!'); return result; @@ -372,12 +378,12 @@ export class AztecRPCServer implements AztecRPC { * @param contractDataOracle - Optional instance of ContractDataOracle for fetching and caching contract information. * @returns The simulation result containing the outputs of the unconstrained function. */ - async #simulateUnconstrained(execRequest: ExecutionRequest, contractDataOracle?: ContractDataOracle) { + async #simulateUnconstrained(execRequest: ExecutionRequest, prevBlockData: CombinedHistoricTreeRoots = CombinedHistoricTreeRoots.empty(), contractDataOracle?: ContractDataOracle) { if (!contractDataOracle) { contractDataOracle = new ContractDataOracle(this.db, this.node); } - const { contractAddress, functionAbi, portalContract, historicRoots } = await this.#getSimulationParameters( + const { contractAddress, functionAbi, portalContract } = await this.#getSimulationParameters( execRequest, contractDataOracle, ); @@ -390,7 +396,7 @@ export class AztecRPCServer implements AztecRPC { functionAbi, contractAddress, portalContract, - historicRoots, + prevBlockData.privateHistoricTreeRoots, ); this.log('Unconstrained simulation completed!'); @@ -412,15 +418,52 @@ export class AztecRPCServer implements AztecRPC { async #simulateAndProve(txExecutionRequest: TxExecutionRequest, newContract: ContractDao | undefined) { // TODO - Pause syncing while simulating. + //TODO(MADDIAA) MAYBE WE SHOULD GET THE LATEST BLOCK TREE ROOTS HERE AND PASS THEM DOWN EVERYWHERE? + + + + + + + + // Add values that allow us to reconstruct the block hash + const wasm = await CircuitsWasm.get(); + const latestBlock = await this.getBlock(-1) + const latestGlobals = latestBlock?.globalVariables ?? GlobalVariables.empty(); + const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); + const treeRoots = this.db.getTreeRoots(); + + const historicTreeRoots = new CombinedHistoricTreeRoots( + new PrivateHistoricTreeRoots( + treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], + treeRoots[MerkleTreeId.NULLIFIER_TREE], + treeRoots[MerkleTreeId.CONTRACT_TREE], + treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], + treeRoots[MerkleTreeId.BLOCKS_TREE], + Fr.ZERO, + ), + treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], + prevBlockGlobalVariablesHash + ); + + const contractDataOracle = new ContractDataOracle(this.db, this.node); + // TODO: maybe could put above in this kernel oracle const kernelOracle = new KernelOracle(contractDataOracle, this.node); - const executionResult = await this.#simulate(txExecutionRequest, contractDataOracle); + const executionResult = await this.#simulate(txExecutionRequest, historicTreeRoots, contractDataOracle); const kernelProver = new KernelProver(kernelOracle); this.log(`Executing kernel prover...`); const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult); this.log('Proof completed!'); + + + // TODO: FIX HACK< OVERWRITING THE ROOTS HERE + publicInputs.constants.historicTreeRoots = historicTreeRoots; + + + const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index bf3985d6c6a..8643f88ee0d 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -129,7 +129,7 @@ export class CombinedHistoricTreeRoots { } isEmpty() { - return this.privateHistoricTreeRoots.isEmpty(); + return this.privateHistoricTreeRoots.isEmpty() && this.publicDataTreeRoot.isZero() && this.prevGlobalVariablesHash.isZero(); } static empty() { diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 2ba1655bc8f..1d350dd689d 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -87,6 +87,9 @@ describe('L1Publisher integration', () => { let builder: SoloBlockBuilder; let builderDb: MerkleTreeOperations; + // The global variables of the last rollup + let prevGlobals: GlobalVariables; + beforeEach(async () => { deployerAccount = privateKeyToAccount(deployerPK); const { @@ -147,10 +150,12 @@ describe('L1Publisher integration', () => { publisherPrivateKey: PrivateKey.fromString(sequencerPK), l1BlockPublishRetryIntervalMS: 100, }); + + prevGlobals = GlobalVariables.empty(); }, 100_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); const tx = await makeEmptyProcessedTxFromHistoricTreeRoots( historicTreeRoots, new Fr(config.chainId), @@ -164,7 +169,7 @@ describe('L1Publisher integration', () => { const kernelOutput = KernelCircuitPublicInputs.empty(); kernelOutput.constants.txContext.chainId = fr(config.chainId); kernelOutput.constants.txContext.version = fr(config.version); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), @@ -276,6 +281,7 @@ describe('L1Publisher integration', () => { new Fr(await rollup.read.lastBlockTs()), ); const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); + prevGlobals = globalVariables; // check that values are in the inbox for (let j = 0; j < l1ToL2Messages.length; j++) { @@ -367,6 +373,7 @@ describe('L1Publisher integration', () => { new Fr(await rollup.read.lastBlockTs()), ); const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); + prevGlobals = globalVariables; await publisher.processL2Block(block); diff --git a/yarn-project/p2p/src/client/mocks.ts b/yarn-project/p2p/src/client/mocks.ts index 752bbd8e2e9..4fb97b12235 100644 --- a/yarn-project/p2p/src/client/mocks.ts +++ b/yarn-project/p2p/src/client/mocks.ts @@ -21,6 +21,15 @@ export class MockBlockSource implements L2BlockSource { return Promise.resolve(this.l2Blocks.length - 1); } + /** + * Gets an l2 block. + * @param number - The block number to return (inclusive). + * @returns The requested L2 block. + */ + public getL2Block(number: number) { + return Promise.resolve(this.l2Blocks[number]); + } + /** * Gets up to `limit` amount of L2 blocks starting from `from`. * @param from - Number of the first block to return (inclusive). diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 0343f0736ab..174e5bf9d00 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -97,8 +97,8 @@ describe('sequencer/solo_block_builder', () => { globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO); // TODO: really don;t like this init pattern - builderDb = await MerkleTrees.new(levelup(createMemDown()), globalVariables).then(t => t.asLatest()); - expectsDb = await MerkleTrees.new(levelup(createMemDown()), globalVariables).then(t => t.asLatest()); + builderDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); + expectsDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); vks = getVerificationKeys(); simulator = mock(); prover = mock(); @@ -122,7 +122,7 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, globalVariables); + const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; @@ -170,7 +170,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(expectsDb, globalVariables); + kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(expectsDb); const tx = await makeProcessedTx( new Tx( @@ -322,7 +322,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, globalVariables); + kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index b4b8b2a51d7..41f41d10cbe 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -104,12 +104,13 @@ export class PublicProcessor { /** * Makes an empty processed tx. Useful for padding a block to a power of two number of txs. - * @param globalVariables - The global variables for this block. + * @param prevGlobals - The global variables for the previous block. + * @param currentGlobalVariables - The global variables for this block. * @returns A processed tx with empty data. */ - public async makeEmptyProcessedTx(globalVariables: GlobalVariables): Promise { - const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db, globalVariables); - return makeEmptyProcessedTx(historicTreeRoots, globalVariables.chainId, globalVariables.version); + public async makeEmptyProcessedTx(prevGlobals: GlobalVariables, currentGlobalVariables: GlobalVariables): Promise { + const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db, prevGlobals); + return makeEmptyProcessedTx(historicTreeRoots, currentGlobalVariables.chainId, currentGlobalVariables.version); } protected async processTx(tx: Tx, globalVariables: GlobalVariables): Promise { diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 3397e8d3fb3..1684161b199 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -164,7 +164,13 @@ export class Sequencer { // Build the new block by running the rollup circuits this.log(`Assembling block with txs ${processedTxs.map(tx => tx.hash).join(', ')}`); - const emptyTx = await processor.makeEmptyProcessedTx(globalVariables); + + // Get the prev globals from the block source + + // TODO CLEANUP + const prevBlock = await this.l2BlockSource.getL2Block(-1); + const prevGlobals = prevBlock ? prevBlock.globalVariables: GlobalVariables.empty(); + const emptyTx = await processor.makeEmptyProcessedTx(prevGlobals, globalVariables); const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, globalVariables); this.log(`Assembled block ${block.number}`); diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index bcbf1e47952..81a6d983f07 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -6,7 +6,7 @@ import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables) { +export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty()) { const wasm = await CircuitsWasm.get(); const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); diff --git a/yarn-project/types/src/interfaces/aztec-node.ts b/yarn-project/types/src/interfaces/aztec-node.ts index 44773c41f43..a4139e21f18 100644 --- a/yarn-project/types/src/interfaces/aztec-node.ts +++ b/yarn-project/types/src/interfaces/aztec-node.ts @@ -26,6 +26,13 @@ export interface AztecNode extends DataCommitmentProvider, L1ToL2MessageProvider */ isReady(): Promise; + /** + * Get the a given block. + * @param number - The block number being requested. + * @returns The blocks requested. + */ + getBlock(number: number): Promise; + /** * Method to request blocks. Will attempt to return all requested blocks but will return only those available. * @param from - The start of the range of blocks to return. diff --git a/yarn-project/types/src/l2_block_source.ts b/yarn-project/types/src/l2_block_source.ts index 184266ae42b..4d6540ef996 100644 --- a/yarn-project/types/src/l2_block_source.ts +++ b/yarn-project/types/src/l2_block_source.ts @@ -10,6 +10,13 @@ export interface L2BlockSource { */ getBlockHeight(): Promise; + /** + * Gets an l2 block. If a negative number is passed, the block returned is the most recent. + * @param number - The block number to return (inclusive). + * @returns The requested L2 block. + */ + getL2Block(number: number): Promise; + /** * Gets up to `limit` amount of L2 blocks starting from `from`. * @param from - Number of the first block to return (inclusive). From c464ec23ca5d9d52d9122894f73fe17f309898b3 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:23:24 +0000 Subject: [PATCH 25/58] feat: remove old historic trees from the smart contract --- l1-contracts/src/core/libraries/Decoder.sol | 85 ++++++++----------- .../src/synchroniser/synchroniser.ts | 2 +- yarn-project/types/src/l2_block.ts | 66 +++----------- .../src/world-state-db/merkle_trees.ts | 48 ++++++----- 4 files changed, 77 insertions(+), 124 deletions(-) diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 9c9c9cbe89f..9111cbd3d09 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -19,57 +19,46 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * ------------------- * * | byte start | num bytes | name - * | --- | --- | --- + * | --- | --- | --- * | 0x0000 | 0x20 | chain-id * | 0x0020 | 0x20 | version * | 0x0040 | 0x20 | L2 block number * | 0x0060 | 0x20 | L2 timestamp - * | 0x0080 | 0x20 | startPrivateDataTreeSnapshot.root - * | 0x00a0 | 0x04 | startPrivateDataTreeSnapshot.nextAvailableLeafIndex - * | 0x00a4 | 0x20 | startNullifierTreeSnapshot.root - * | 0x00c4 | 0x04 | startNullifierTreeSnapshot.nextAvailableLeafIndex - * | 0x00c8 | 0x20 | startContractTreeSnapshot.root - * | 0x00e8 | 0x04 | startContractTreeSnapshot.nextAvailableLeafIndex - * | 0x00ec | 0x20 | startTreeOfHistoricPrivateDataTreeRootsSnapshot.root - * | 0x010c | 0x04 | startTreeOfHistoricPrivateDataTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x0110 | 0x20 | startTreeOfHistoricContractTreeRootsSnapshot.root - * | 0x0130 | 0x04 | startTreeOfHistoricContractTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x0134 | 0x20 | startPublicDataTreeRoot - * | 0x0154 | 0x20 | startL1ToL2MessagesTreeSnapshot.root - * | 0x0174 | 0x04 | startL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex - * | 0x0178 | 0x20 | startTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.root - * | 0x0198 | 0x04 | startTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x019c | 0x20 | startBlocksTreeSnapshot.root - * | 0x01bc | 0x04 | startBlocksTreeSnapshot.nextAvailableLeafIndex - * | 0x01c0 | 0x20 | endPrivateDataTreeSnapshot.root - * | 0x01e0 | 0x04 | endPrivateDataTreeSnapshot.nextAvailableLeafIndex - * | 0x01e4 | 0x20 | endNullifierTreeSnapshot.root - * | 0x0204 | 0x04 | endNullifierTreeSnapshot.nextAvailableLeafIndex - * | 0x0208 | 0x20 | endContractTreeSnapshot.root - * | 0x0228 | 0x04 | endContractTreeSnapshot.nextAvailableLeafIndex - * | 0x022c | 0x20 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.root - * | 0x024c | 0x04 | endTreeOfHistoricPrivateDataTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x0250 | 0x20 | endTreeOfHistoricContractTreeRootsSnapshot.root - * | 0x0270 | 0x04 | endTreeOfHistoricContractTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x0274 | 0x20 | endPublicDataTreeRoot - * | 0x0294 | 0x20 | endL1ToL2MessagesTreeSnapshot.root - * | 0x02b4 | 0x04 | endL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex - * | 0x0300 | 0x20 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.root - * | 0x02d8 | 0x04 | endTreeOfHistoricL1ToL2MessagesTreeRootsSnapshot.nextAvailableLeafIndex - * | 0x02dc | 0x20 | endBlocksTreeSnapshot.root - * | 0x02fc | 0x04 | endBlocksTreeSnapshot.nextAvailableLeafIndex - * | 0x0300 | a * 0x20 | newCommitments (each element 32 bytes) - * | 0x0300 + a * 0x20 | 0x04 | len(newNullifiers) denoted b - * | 0x0304 + a * 0x20 | b * 0x20 | newNullifiers (each element 32 bytes) - * | 0x0304 + (a + b) * 0x20 | 0x04 | len(newPublicDataWrites) denoted c - * | 0x0308 + (a + b) * 0x20 | c * 0x40 | newPublicDataWrites (each element 64 bytes) - * | 0x0308 + (a + b) * 0x20 + c * 0x40 | 0x04 | len(newL2ToL1msgs) denoted d - * | 0x030c + (a + b) * 0x20 + c * 0x40 | d * 0x20 | newL2ToL1msgs (each element 32 bytes) - * | 0x030c + (a + b + d) * 0x20 + c * 0x40 | 0x04 | len(newContracts) denoted e - * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 | e * 0x20 | newContracts (each element 32 bytes) - * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x20 | e * 0x34 | newContractData (each element 52 bytes) - * | 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | 0x04 | len(l1ToL2Messages) denoted f - * | K := 0x0310 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | f * 0x20 | l1ToL2Messages (each element 32 bytes) + * | 0x0080 | 0x20 | last eth block hash + * | 0x00a0 | 0x20 | startPrivateDataTreeSnapshot.root + * | 0x00c0 | 0x04 | startPrivateDataTreeSnapshot.nextAvailableLeafIndex + * | 0x00c4 | 0x20 | startNullifierTreeSnapshot.root + * | 0x00e4 | 0x04 | startNullifierTreeSnapshot.nextAvailableLeafIndex + * | 0x00e8 | 0x20 | startContractTreeSnapshot.root + * | 0x0108 | 0x04 | startContractTreeSnapshot.nextAvailableLeafIndex + * | 0x010c | 0x20 | startPublicDataTreeRoot + * | 0x012c | 0x20 | startL1ToL2MessagesTreeSnapshot.root + * | 0x014c | 0x04 | startL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex + * | 0x0150 | 0x20 | startHistoricBlocksTreeSnapshot.root + * | 0x0170 | 0x04 | startHistoricBlocksTreeSnapshot.nextAvailableLeafIndex + * | 0x0174 | 0x20 | endPrivateDataTreeSnapshot.root + * | 0x0194 | 0x04 | endPrivateDataTreeSnapshot.nextAvailableLeafIndex + * | 0x0198 | 0x20 | endNullifierTreeSnapshot.root + * | 0x01b8 | 0x04 | endNullifierTreeSnapshot.nextAvailableLeafIndex + * | 0x01bc | 0x20 | endContractTreeSnapshot.root + * | 0x01dc | 0x04 | endContractTreeSnapshot.nextAvailableLeafIndex + * | 0x01e0 | 0x20 | endPublicDataTreeRoot + * | 0x0200 | 0x20 | endL1ToL2MessagesTreeSnapshot.root + * | 0x0220 | 0x04 | endL1ToL2MessagesTreeSnapshot.nextAvailableLeafIndex + * | 0x0224 | 0x20 | endHistoricBlocksTreeSnapshot.root + * | 0x0244 | 0x04 | endHistoricBlocksTreeSnapshot.nextAvailableLeafIndex + * | 0x0244 | a * 0x20 | newCommitments (each element 32 bytes) + * | 0x0244 + a * 0x20 | 0x04 | len(newNullifiers) denoted b + * | 0x0248 + a * 0x20 | b * 0x20 | newNullifiers (each element 32 bytes) + * | 0x0248 + (a + b) * 0x20 | 0x04 | len(newPublicDataWrites) denoted c + * | 0x024c + (a + b) * 0x20 | c * 0x40 | newPublicDataWrites (each element 64 bytes) + * | 0x024c + (a + b) * 0x20 + c * 0x40 | 0x04 | len(newL2ToL1msgs) denoted d + * | 0x0250 + (a + b) * 0x20 + c * 0x40 | d * 0x20 | newL2ToL1msgs (each element 32 bytes) + * | 0x0250 + (a + b + d) * 0x20 + c * 0x40 | 0x04 | len(newContracts) denoted e + * | 0x0254 + (a + b + d) * 0x20 + c * 0x40 | e * 0x20 | newContracts (each element 32 bytes) + * | 0x0254 + (a + b + d) * 0x20 + c * 0x40 + e * 0x20 | e * 0x34 | newContractData (each element 52 bytes) + * | 0x0254 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | 0x04 | len(l1ToL2Messages) denoted f + * | K := 0x0254 + (a + b + d) * 0x20 + c * 0x40 + e * 0x54 | f * 0x20 | l1ToL2Messages (each element 32 bytes) * | K + f * 0x20 | 0x04 | byteLen(newEncryptedLogs) denoted g * | K + f * 0x20 + 0x04 | g | newEncryptedLogs * | K + f * 0x20 + 0x04 + g | 0x04 | byteLen(newUnencryptedLogs) denoted h @@ -106,7 +95,7 @@ library Decoder { uint256 private constant START_TREES_BLOCK_HEADER_OFFSET = 0x80; // The size of the block header elements - uint256 private constant TREES_BLOCK_HEADER_SIZE = 0x140; + uint256 private constant TREES_BLOCK_HEADER_SIZE = 0xd4; // Where the end of trees metadata begns in the block uint256 private constant END_TREES_BLOCK_HEADER_OFFSET = diff --git a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts index 6a5cc776112..25ed2005219 100644 --- a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts +++ b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts @@ -139,7 +139,7 @@ export class Synchroniser { [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: block.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot.root, [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: block.endTreeOfHistoricContractTreeRootsSnapshot.root, [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: block.endTreeOfHistoricPrivateDataTreeRootsSnapshot.root, - [MerkleTreeId.BLOCKS_TREE]: Fr.ZERO, // Mocked for this pr - see #1162 + [MerkleTreeId.BLOCKS_TREE]: block.endHistoricBlocksTreeSnapshot.root, }; await this.db.setTreeRoots(roots); } diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index 1f89bb16097..f53a501dd69 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -69,7 +69,7 @@ export class L2Block { /** * The tree snapshot of the historic private data tree roots at the start of the rollup. */ - public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic contract tree roots at the start of the rollup. */ @@ -85,11 +85,11 @@ export class L2Block { /** * The tree snapshot of the historic L2 message tree roots at the start of the rollup. */ - public startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic blocks tree at the start of the rollup. */ - public startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot, + public startHistoricBlocksTreeSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the private data tree at the end of the rollup. */ @@ -105,11 +105,11 @@ export class L2Block { /** * The tree snapshot of the historic private data tree roots at the end of the rollup. */ - public endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic contract tree roots at the end of the rollup. */ - public endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree root of the public data tree at the end of the rollup. */ @@ -121,7 +121,7 @@ export class L2Block { /** * The tree snapshot of the historic L2 message tree roots at the end of the rollup. */ - public endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, + public endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic blocks tree at the end of the rollup. */ @@ -400,20 +400,14 @@ export class L2Block { this.startPrivateDataTreeSnapshot, this.startNullifierTreeSnapshot, this.startContractTreeSnapshot, - this.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.startTreeOfHistoricContractTreeRootsSnapshot, this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, - this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.startHistoricBlocksTreeSnapshot, this.endPrivateDataTreeSnapshot, this.endNullifierTreeSnapshot, this.endContractTreeSnapshot, - this.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.endTreeOfHistoricContractTreeRootsSnapshot, this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, - this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.endHistoricBlocksTreeSnapshot, this.newCommitments.length, this.newCommitments, @@ -453,20 +447,14 @@ export class L2Block { const startPrivateDataTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const startNullifierTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const startContractTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const startTreeOfHistoricPrivateDataTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const startTreeOfHistoricContractTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const startPublicDataTreeRoot = reader.readObject(Fr); const startL1ToL2MessageTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const startHistoricBlocksTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endPrivateDataTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endNullifierTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endContractTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endTreeOfHistoricPrivateDataTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endTreeOfHistoricContractTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endPublicDataTreeRoot = reader.readObject(Fr); const endL1ToL2MessageTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); - const endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const endHistoricBlocksTreeSnapshot = reader.readObject(AppendOnlyTreeSnapshot); const newCommitments = reader.readVector(Fr); const newNullifiers = reader.readVector(Fr); @@ -485,20 +473,20 @@ export class L2Block { startPrivateDataTreeSnapshot, startNullifierTreeSnapshot, startContractTreeSnapshot, - startTreeOfHistoricPrivateDataTreeRootsSnapshot, - startTreeOfHistoricContractTreeRootsSnapshot, + startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), + startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), startPublicDataTreeRoot, startL1ToL2MessageTreeSnapshot, - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), startHistoricBlocksTreeSnapshot, endPrivateDataTreeSnapshot, endNullifierTreeSnapshot, endContractTreeSnapshot, - endTreeOfHistoricPrivateDataTreeRootsSnapshot, - endTreeOfHistoricContractTreeRootsSnapshot, + endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), + endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), endPublicDataTreeRoot, endL1ToL2MessageTreeSnapshot, - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, + endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, @@ -555,20 +543,14 @@ export class L2Block { this.startPrivateDataTreeSnapshot, this.startNullifierTreeSnapshot, this.startContractTreeSnapshot, - this.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.startTreeOfHistoricContractTreeRootsSnapshot, this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, - this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.startHistoricBlocksTreeSnapshot, this.endPrivateDataTreeSnapshot, this.endNullifierTreeSnapshot, this.endContractTreeSnapshot, - this.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.endTreeOfHistoricContractTreeRootsSnapshot, this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, - this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.endHistoricBlocksTreeSnapshot, this.getCalldataHash(), this.getL1ToL2MessagesHash(), @@ -587,11 +569,8 @@ export class L2Block { this.startPrivateDataTreeSnapshot, this.startNullifierTreeSnapshot, this.startContractTreeSnapshot, - this.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.startTreeOfHistoricContractTreeRootsSnapshot, this.startPublicDataTreeRoot, this.startL1ToL2MessageTreeSnapshot, - this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.startHistoricBlocksTreeSnapshot, ); return sha256(inputValue); @@ -607,11 +586,8 @@ export class L2Block { this.endPrivateDataTreeSnapshot, this.endNullifierTreeSnapshot, this.endContractTreeSnapshot, - this.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - this.endTreeOfHistoricContractTreeRootsSnapshot, this.endPublicDataTreeRoot, this.endL1ToL2MessageTreeSnapshot, - this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, this.endHistoricBlocksTreeSnapshot, ); return sha256(inputValue); @@ -785,33 +761,15 @@ export class L2Block { `startPrivateDataTreeSnapshot: ${inspectTreeSnapshot(this.startPrivateDataTreeSnapshot)}`, `startNullifierTreeSnapshot: ${inspectTreeSnapshot(this.startNullifierTreeSnapshot)}`, `startContractTreeSnapshot: ${inspectTreeSnapshot(this.startContractTreeSnapshot)}`, - `startTreeOfHistoricPrivateDataTreeRootsSnapshot: ${inspectTreeSnapshot( - this.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - )}`, - `startTreeOfHistoricContractTreeRootsSnapshot: ${inspectTreeSnapshot( - this.startTreeOfHistoricContractTreeRootsSnapshot, - )}`, `startPublicDataTreeRoot: ${this.startPublicDataTreeRoot.toString()}`, `startL1ToL2MessageTreeSnapshot: ${inspectTreeSnapshot(this.startL1ToL2MessageTreeSnapshot)}`, - `startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: ${inspectTreeSnapshot( - this.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - )}`, `startHistoricBlocksTreeSnapshot: ${inspectTreeSnapshot(this.startHistoricBlocksTreeSnapshot)}`, `endPrivateDataTreeSnapshot: ${inspectTreeSnapshot(this.endPrivateDataTreeSnapshot)}`, `endNullifierTreeSnapshot: ${inspectTreeSnapshot(this.endNullifierTreeSnapshot)}`, `endContractTreeSnapshot: ${inspectTreeSnapshot(this.endContractTreeSnapshot)}`, `endPublicDataTreeRoot: ${this.endPublicDataTreeRoot.toString()}`, - `endTreeOfHistoricPrivateDataTreeRootsSnapshot: ${inspectTreeSnapshot( - this.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - )}`, - `endTreeOfHistoricContractTreeRootsSnapshot: ${inspectTreeSnapshot( - this.endTreeOfHistoricContractTreeRootsSnapshot, - )}`, `endPublicDataTreeRoot: ${this.endPublicDataTreeRoot.toString()}`, `endL1ToL2MessageTreeSnapshot: ${inspectTreeSnapshot(this.endL1ToL2MessageTreeSnapshot)}`, - `endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: ${inspectTreeSnapshot( - this.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - )}`, `endHistoricBlocksTreeSnapshot: ${inspectTreeSnapshot(this.endHistoricBlocksTreeSnapshot)}`, `newCommitments: ${inspectFrArray(this.newCommitments)}`, `newNullifiers: ${inspectFrArray(this.newNullifiers)}`, diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index dcb1999c5f9..f059597c857 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -58,7 +58,7 @@ export class MerkleTrees implements MerkleTreeDb { * @param genesisConfig - The genesis config to use for initialising the trees. * @param optionalWasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). */ - public async init(genesisConfig: GlobalVariables, optionalWasm?: IWasmModule) { + public async init(optionalWasm?: IWasmModule) { const wasm = optionalWasm ?? (await CircuitsWasm.get()); const hasher = new Pedersen(wasm); const contractTree: AppendOnlyTree = await newTree( @@ -140,7 +140,8 @@ export class MerkleTrees implements MerkleTreeDb { this.jobQueue.start(); // The roots trees must contain the empty roots of their data trees - await this.updateHistoricBlocksTree(genesisConfig, true); + // The first leaf in the tree contains empty roots + await this.updateHistoricBlocksTree(GlobalVariables.empty(), true); const historicRootsTrees = [historicBlocksTree]; await Promise.all(historicRootsTrees.map(tree => tree.commit())); } @@ -153,9 +154,9 @@ export class MerkleTrees implements MerkleTreeDb { * @returns - A fully initialised MerkleTrees instance. */ // TODO: remove genesis config - public static async new(db: levelup.LevelUp, genesisConfig: GlobalVariables = GlobalVariables.empty(), wasm?: IWasmModule) { + public static async new(db: levelup.LevelUp, wasm?: IWasmModule) { const merkleTrees = new MerkleTrees(db); - await merkleTrees.init(genesisConfig, wasm); + await merkleTrees.init(wasm); return merkleTrees; } @@ -202,6 +203,9 @@ export class MerkleTrees implements MerkleTreeDb { const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); const blockHash = computeBlockHash(wasm, globals, trees[0], trees[1], trees[2],trees[3], trees[4]); + console.log(globals); + + console.log("ADDING block hash: ", blockHash.toString()); await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } @@ -515,16 +519,8 @@ export class MerkleTrees implements MerkleTreeDb { compareRoot(l2Block.endNullifierTreeSnapshot.root, MerkleTreeId.NULLIFIER_TREE), compareRoot(l2Block.endPrivateDataTreeSnapshot.root, MerkleTreeId.PRIVATE_DATA_TREE), compareRoot(l2Block.endPublicDataTreeRoot, MerkleTreeId.PUBLIC_DATA_TREE), - compareRoot(l2Block.endTreeOfHistoricContractTreeRootsSnapshot.root, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE), - compareRoot( - l2Block.endTreeOfHistoricPrivateDataTreeRootsSnapshot.root, - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - ), compareRoot(l2Block.endL1ToL2MessageTreeSnapshot.root, MerkleTreeId.L1_TO_L2_MESSAGES_TREE), - compareRoot( - l2Block.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot.root, - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - ), + compareRoot(l2Block.endHistoricBlocksTreeSnapshot.root, MerkleTreeId.BLOCKS_TREE), ]; const ourBlock = rootChecks.every(x => x); if (ourBlock) { @@ -534,6 +530,7 @@ export class MerkleTrees implements MerkleTreeDb { this.log(`Block ${l2Block.number} is not ours, rolling back world state and committing state from chain..`); await this._rollback(); + // Sync the append only trees for (const [tree, leaves] of [ [MerkleTreeId.CONTRACT_TREE, l2Block.newContracts], [MerkleTreeId.PRIVATE_DATA_TREE, l2Block.newCommitments], @@ -545,25 +542,34 @@ export class MerkleTrees implements MerkleTreeDb { ); } + // Sync the indexed trees await (this.trees[MerkleTreeId.NULLIFIER_TREE] as StandardIndexedTree).batchInsert( l2Block.newNullifiers.map(fr => fr.toBuffer()), BaseRollupInputs.NULLIFIER_SUBTREE_HEIGHT, ); + // Sync the public data tree for (const dataWrite of l2Block.newPublicDataWrites) { if (dataWrite.isEmpty()) continue; const { newValue, leafIndex } = dataWrite; await this._updateLeaf(MerkleTreeId.PUBLIC_DATA_TREE, newValue.toBuffer(), leafIndex.value); } - for (const [newTree, rootTree] of [ - [MerkleTreeId.PRIVATE_DATA_TREE, MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE], - [MerkleTreeId.CONTRACT_TREE, MerkleTreeId.CONTRACT_TREE_ROOTS_TREE], - [MerkleTreeId.L1_TO_L2_MESSAGES_TREE, MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE], - ] as const) { - const newTreeRoot = this.trees[newTree].getRoot(true); - await this._appendLeaves(rootTree, [newTreeRoot]); - } + // Sync the blocks tree. + const treeRoots = (await Promise.all([ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + ].map( tree => this.trees[tree].getRoot(true)))).map( root => Fr.fromBuffer(root)); + + const wasm = await CircuitsWasm.get(); + const blockHash = computeBlockHash(wasm, l2Block.globalVariables, treeRoots[0], treeRoots[1], treeRoots[2], treeRoots[3], treeRoots[4]); + // Add the block to the historic blocks tree + await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]) + + await this._commit(); } for (const treeId of merkleTreeIds()) { From 135717900276c249a809066855e318f8e9bea849 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:35:22 +0000 Subject: [PATCH 26/58] fix: update decoder test --- l1-contracts/src/core/libraries/Decoder.sol | 2 +- l1-contracts/test/Decoder.t.sol | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/l1-contracts/src/core/libraries/Decoder.sol b/l1-contracts/src/core/libraries/Decoder.sol index 9111cbd3d09..26f9b835924 100644 --- a/l1-contracts/src/core/libraries/Decoder.sol +++ b/l1-contracts/src/core/libraries/Decoder.sol @@ -19,7 +19,7 @@ import {Hash} from "@aztec/core/libraries/Hash.sol"; * ------------------- * * | byte start | num bytes | name - * | --- | --- | --- + * | --- | --- | --- * | 0x0000 | 0x20 | chain-id * | 0x0020 | 0x20 | version * | 0x0040 | 0x20 | L2 block number diff --git a/l1-contracts/test/Decoder.t.sol b/l1-contracts/test/Decoder.t.sol index 65031430de6..2dada0f1932 100644 --- a/l1-contracts/test/Decoder.t.sol +++ b/l1-contracts/test/Decoder.t.sol @@ -25,10 +25,10 @@ contract DecoderTest is Test { Rollup internal rollup; bytes internal block_empty_1 = - hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f658462190000000100000000000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000006027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000040050f7a38e7222792175befc9d6af3433c94309b86f3d2cccb3d9dafb178071a000000022bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f119000000022b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000102bc197200c41b8fdfb11e86d0670056ce5d36d22815e3acd48f5f8ae9283f1190000000200000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000"; + hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000002b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000103babeb39cf7cb3fd320ec225367ac5e834aaec3e7b48bb3239d0da39fa4a20000000120efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000402adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000006027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000042b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda5410000001019133ced5bd7348dae0f82a7195910ca141c7b5c1894a7c5f9fa53290c79f3ed0000000200000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000"; bytes internal block_mixed_1 = - hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda54100000000135bc361c9ed85a1b86f54458c343d580d84efb1e147cd568fa6abd4231a402d000000010ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f65846219000000012b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000ef76ed2c9210c834484aa185fdcfe317880955e8594b319f701f39f6584621900000001000000000000000000000000000000000000000000000000000000000000000000000000235f4e41a2440aa28f9ac14e7eed447ddd2e539179cee4c0941e6e408d2443e50000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000600b6abbab461cfb072b267bfc1ecf8dc3c943736341baf11c5c829e345c49b509000000041c1b17b2cb59cc2314fb65fe31dcfdb1b014630fab522a263d9935601ff78a5c000000022d02c42204d7182da24e9ca1e3244fbff1e00efb8c85ee3a1ac9488fe2e3aa9d0000000229c0d0effa4242b8d2e372cfcdfa8bb57160715fa3640a3404a9bba93725a1072fbbd267a1c9b23b3ac1609b2c2a7961a0338c56d62607d5f8d6b6a29e7fe4cb000000101d223d0a7bbe8cd9eace6507ee0fa9dbf84565685a1c6ceb978cdd46c47025ea00000002000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000524000000000000000000000000000000000000000000000000000000000000052e0000000000000000000000000000000000000000000000000000000000000525000000000000000000000000000000000000000000000000000000000000052f00000000000000000000000000000000000000000000000000000000000005260000000000000000000000000000000000000000000000000000000000000530000000000000000000000000000000000000000000000000000000000000052700000000000000000000000000000000000000000000000000000000000005310000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005660000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000056700000000000000000000000000000000000000000000000000000000000005710000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000058600000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000000000000000587000000000000000000000000000000000000000000000000000000000000059100000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc0000009032919c6c48569ad3995dcb38bf54bf0a64eaf2ab4a09b89d5fe62b546ea493cb7e154c8d7319cc6741e9261c18158e9a2ae25a94035c7f40013180d9f0677d86b20f519aec6e004794170760434f67d6290b14b3fea0d8fa492168cb4f16db80e0175f63f5d30176012ed150cf4dc8eccb35226069218640bd5d5f1169891d64bc7c8cca5a28ab43356dda22635b469e00000090a64ae8b0b581f76e18912727d134244722d5f1a1152201e11af9e17b6386501cc229830d13fc61ca4f3909e1d044558278c4984df6017c2490791e2fcebdbc383b392fce281e8038d0025a8414bac2df7562752fea2197d04bb267ad6e60b5cb269eb54db977d4dff99e752694a816a3bb2ecd63ff62dd485ec57c3f6d30d90fbbc2a75f7ec6892c9aa64562a4705d58000000900d839faaaacf7c3b79f8666bcbfab5e541ed111b466363d72115aa52c984d3aa2be9ce56e1f9fb5979d5c1ca9cf7dd659657e22788ad2f785ff87388068dd8f5b17cfce021dc7f86a547b53ebfbf1ecbd05855b26e3f032fc77838310cb0ef203bbb801f5b3674921b51302618386411d1937232aeac35ee35916a1e3c5b7abc51e95c87c933a67f20717fad8f9a17b7000001bc00000090fa7f303a3193e77865c057fb17f81ab062c5c42acfcf3850fe53a4d79c0ec2d41a41aad98ad84b67a20c7901708adc8ce8fc7b224a5f794bbcd56c13af92c5477c787c07c90c0b45365815bfd5cddd643d3dab4d849fc99a168bf8930b470a1dc7802c06a15a833c4a71eb908bb40d7664018e009d0df85585b925572eee9dfd59fe17bb1c987e6c68b1c737622945c30000009060030c28dfc1b1c4e1aa8b5acb9c422faf2061961744ec6c843f0767824a64d6e4ac0b5e1952fd92cea37ab9d71e3ae4b7bce4aa22206d097bf0799f292c051a3d941af630a012c9467dde09aeca2a01f26bc9353639a5ed21dbd32fc535ba5c455aefea2fcc7ae3b23b10f57b92c3632cdb1c7c526d55026e2c788b491b30fcc25897324b9ae424644c178cc272445a0000009012350c4eaa6d8ee1d3ef8a6d04764ccf617bad3929aa0b95279496c3de694af182ff27551997c27428ef9d39f8b04b9a56333850898c7b44b75d65833508626747d46fd9198d34802d866fa219bfc86d7efe4a02c2e2b2c61902142c5f3c6035cb5373796e70aacea36219fb3c11604f98c69b62fa41c3954ce91f81cdbf178ae695cbdf1063c374fd2411b5dbf1e25d000001bc00000090669b3f837e8678fe80a310c884eb1982ceee50c02e69af4c324eae776b778b95caf6f4dd5130f6d86d855c02a89b320116a7168510739e056e863e4daf4e19de6e9b358c0b9af6f9910785ea3a634a2bce01c91abbd26369e801c2e59b9fa5ba07b87633f036c5e6ca5f1410b57a1c97321d1c78e432fac44df10a8c6cfd92e2ab21c9c104e645342cf068dd95e1d61500000090c6114d81b430e49b3f1d334eaaa772337c7933f186f5c19507ffb03d5990629dd83057865cfbce3def5197e05dacd6282ca98b3260c50feaebe0caa8ae7334e08eb260d3dfea44b192bba1702328ec5c2923c908fdb309ce9860b3b49f16b7cd20fc82e399fd27332afc4cec6f729b4c7afb4b8779092df1e8e78d396c9e5c81fcec99462ff2d1ce817176c5155321730000009030b3e7e792982ef0a074b22b0b1d630d3ed0b4e4e84787a363e2b8361bdf6159ff78d923aec5a32a52395a23807ba1f5056c9af302c41dd8232e7913465c076e97ab51c077fc859910ce131e0520288d529bbe19e8bf4c75144f705943db33dc310bcde2eac64cdf8306dce09008366e0027945cc31f4158c397555d3543882c0c90497119652d36500bb5ac8688bd6b000001bc000000901f67b7d0079c803d61732410de021b576bbcbd611d36624af5d12c34db9284d5fbd1a2204fa791eac5aed12ca3def29d02e392b9b396909518ee9e12bade1290b67b93879866c93ee634fc74de12fd2c5b72b8b88ae268d160eaa2a4187ca0e5bf717589fccf00bdf738ee93e18eb656ce215adff7597c1958942c040a9b2ae305d3b1c8894c49cd43e9cd9c4bf4659200000090e039d0466d3b87b024c22613677d52a6d802d389b554b9e1a1de6db54f643485af5679a9d1d4d8b27259e3951e8c4e9191cc003aaa7db209938f7009765f403ec136859fbd41f5cf1dfa0556b4530072d333ebe5f317ed48f3c610fd09a0a5389aa24b92be7eaaf9c7af4a6e39cb0bedb3eca77a812e5ce8b19a18c9a4122f9cc83f2e5eda063bf576e7b7e502b0ca35000000903c0b11b374c2e98fe6f1d29b72a2d04506cad0debd584356a17daee8a72a13071e58327137fc0eee19f21ded60baae55a76882c2d8d81d7363d03f61d38d89b613222324d433651f595c3611b0661dc9d19e6fd51df22747a810d7d8ad4de07c201502dabfc9a743227f7073055284fa9fd64a3f9f0adedbd0a35a8b274fec74343b810aa4a2fe2f70f3082b695f5d38000001bc0000009078ccb4ecf4d59cbc95dbf42743b3cbfac3c5a00d08a59e5b6d37c476a6c72ceb859ec4ef0bb4cf5db82a73af1ca2ab67829710ba5a6f862166fb7a754a93400434217d6d8fd0ab54f60ca82e2b541684ba5262c186e8811764891e841cb1977c712c141ab5d0425ea6e51813fd46d6699acfd9c314aec104fba27f33c865a4a8f06977c823c9a2a2531b3ecc11e3f7b200000090d3d3ff59fbcf129f1e782bd5d0520e963a1c8be7972f5a1f1de11372a722f24cff6e5141a44fcb3a71e20dfc0ab068a51c85efc4c2948415c99877649764e36fc8aa257d32dcb7ccc14185ac6cfb8559d94c53b6c2acb9ab399f6daa3c9a16138966e8ec31838a0ae2e099550c6831a25ca1715022229656ca35cd932a7afa5f838318df47f8c4e3be6695f61ce1d75e00000090e20a131283a707113c216e677b844a72e96484f9c62c16b2e9bdeffae9975aa15fd8c5610ced4505dc51cecec7ecb38c0de915316908e35af445f9012651cd623ce9400aef48dd980b3a1798f95e59428c5225f3883fe11e29653c6cd83f04c47d5db50cc30d2d6ef6f7fc794db67648eccaa7c79af87183775998557855c95247bc99736360d1e5f45f4e7acbc4eabc000001bc00000090e44e831c63efe672ceea838719aa748a3404018ebed3736948121cf5ea66e525ea6b86fd92778be4abda5f153f14cb485c5d4e2d99fcddab45bfaa48053e722abcd3e9ceec5ddc813b5dda943e0e04511e4dbdcb6a159ae1c407350ddaf4fee745471958900139a827ecbff5701e209201cf09b7bd788ad7cde71b1b937a7db8632ac1a9a09f0f5923fcbd567d58d7270000009097e8b7e7dd5656ac8ff699b939d4f9b725f77a0e865137730509a1f4c4494fcd604c5835bbbb963b09ca81121aff5ad58af690ba8f569a134f77a3e1b482a970e83db5d35c16e7e5f1ca1a53c877979d11ac128c5d0d8763953dcf19d4ea483b4e711ac14c7ae9be1977cbfe74586eeda135defdea313336b7cc027b19689638a1083de1322c7de6d5eb4a6ad0430cf90000009004da51e829eca1ba32d643b64c55e4216a1d5a72ffc28fe82fc487c28147a4c8157ac97c9f1eccfd9f44802ca941fcf9b80dbb4933567a6d07c77dd454b27c14b08fe0a44b29aace45717e59cdd5a29d8e5fb84a7d826994193f222e2aff2fbacefb33f8c66123b54b70dfce248052f38e5851fce0c9bb7bfda11912bef7c1e6933737f387911fd6597d2fe47cf5263b000001bc00000090ed23feff905e99d8ccf57e7bcd81113e59d8fa9e3ed0a396f40ef2fce9ecde050e81e277624e18cc63d13747ff86dae359de61d134bf5c65bed07b51cb394934288230220c42096464830f865907c830dfba93723370301a82cd51b0aa7e136e7a6efd05e69340002e7851c9868fcd79bfc44d600f30694cd80d3726e36adc1abfd1375299aeee7939383a986a9a950600000090e8a0277df93d8955e44770957102bd105c674381e88137b8ebb1df240ac944bb78651a8a6a987e0df32317e8b7a24951c5676da55ed3cc8c20e1ac63508fda4e73ca9ac8e11bbff6cafede14c2e2a6f0bad65b8dfe184eeaf11bf20c1070c52b6a7072fb47758932b282d8c0dfe3f5f93d979eadc5696b878254a72e8eefa4bbfa836345241873975b318b34f3201ba60000009003087a4774e22a77d429d2dc113cba00a043aa7ca12118d429e76f38f5d326f29281ec729d984682bc60e6c36ffcfa956f9cf5325fbd0d5f822b9ae89fae01f14d5e5d3b6b4013b9d73f2b6cca3c890a41521268ef4384947022bee5689a7ecd653ad06e277f7f5ec769b843db985cfd44bc9e428996fa3b2cdccad71c65caa65d14770536a89ac9217e23da6f9f44ff000001bc000000902a8fadaabd5bb94de0d968ca498a521f22f07c98b20d150a7c53b058decabcc377ac11e7364bbfc6d35be37e6f7128e93af80167b176f957dfc8b6f404a60b564eb804d7cedcfe0dcacdc8f2547ebee8e8d6c1f21f48f31d29e1d3bc19b1e19effdca933be3e8059ec3a49628f38fa732fb90389c261ad7da902570f36047e2fe69ec639514e578b62e91b704a6adc4a000000907bc14528fa34d0bbdbbba7eadd6adefc2e84b514c98e8e66b088dd68e3b95c7db6524034aba4e8cabb6f4b617a487533c9173260d169b2d3493bc4875a41413701eaf6802f8c134b73ef7075cd16af6b29ee0459e40ced1c3760335088ebc6504147db46cd73266bb411eb4f0e0b2720277cea3e3846e720a14f3de27e20f8f9c69139c3a0b21da816e1456f65fea7d30000009051867f83337dbcaba0e9048b9f4236b3ceaeb0ceb62723c19a39b5d95674fe336647775703edd689ceb375d76bda7fb46380d0ba2779d29ae9472e877d23cf31024485ed54ffd7f6bcbde3fdbbc8f9c296c3539f7ed5d8c3f7d800b86065e8c7c971adaec9f6a67e93f374b9d53e380fb3cdf8b7689086ce6e68fc10933afc801271cc41f41d4e72f4d9279a39c490e400000e00000001bc000000905ec7abdb571f75438855f49c61bb5b0536a6cc5039ad70e43322ef819d229cfbeb6ae7e327065ecd84b3a105adbeae9889d7774e79311c3047c306ee502fee5a44608c6f41c62373566baeba784202c192542cd61797805e0b6499e4e026c5bf4270d90b2eedde8ef0d16c189a740625dc5978352f977c089383319b972924149d49656f4462cd15fc03fe4c4eac06e00000009085df2a5a2dca9dd0c7db47523797586c8f071967c1ade4cf73407a1e64030f826f441f7cccfa3cdf8c8f67464f6b4b92f87a29f1df6461fe1529d60eae18daa5ca9579ad0621da5d865da25cb4b00527f53ab6dabfe1365b8e476f2e7cf23ac348f9d238b8ad6a062cee43a2667bba4f64705e524450387a6a27d1f42bb941638665324b8628110520a54cf89e03123a00000090e3ec6b1cdd993341df9e6fca1e87cee49ef0c562e2484e08fa7f3395db06f49ef314b6e967d959f8724d52d8d6080f8cf83ed3e4a278b71341de2c409e0099b645e4cd28d9a3562f094896a0087be8c58468d11896bd129f550ab0320764d4de5e0ecdb1fffe7ef94a48b62ea5d67790d370bee611946c4958aa6110c79512b4c825fd8cc612ee4416dea27413c25249000001bc000000906bbd80c8714ae681429925c1339daab4cdccd0b38a4b77f7ac1635848b4b208a4ca68157053ac7ef3f8784daa31df3a89d0a47d3674b71d68dfa1fd05ba31575bd33e9ff08a237c73e3227c90858010e1c28442e0304be0bf92c14af5fc0e40dbc61a9298dbe338d5c4d4c20fbdce40890eeb3ab2b178f766765d6d10a1d8585b668a21f8fd709bb8be150c1c9fca415000000902fd7e4c8c4a034be0ff2fb7d544b4238a1c5c0d7908d63e91e0409100a14721d57eea9b7505d93e245d9f1907538f55677ad91041c03fa494990ae7283fcef27cee8160f9052dfa5f337b6b6cc1c239f82fbb8c1aab4959582fd7eda08d699ac283aefd052191c6aa21605ed63fadf764e8f1b6bf8a5bf8f272db5e2f9b3d7080acd090486ff64532c20a9e345576529000000902e680548156f1a87ca514126d198b26f1384f0fdbf0684adad70f50257a4bc3eb047b09df002fa0b56304fb60a99091494100b3ad0d458761d22b65914fe4957a30b25a96fc30c0fa6819994a4751d00042596ad7d61a3ce938d076f3c64b33ab292508fd21843d42f0c717180d26eff1701596ad124af6770bd2adbde5437b0a3913771f01bb060705dc5935fe72699000001bc00000090856dbdcd28dcd6c005073a5ae5ca091833abc7ae70c8f39c71643c78dc095e06bb935c63593caf713a4761f3071bb78ca684a6d8f92c56f8a85f030e747176b6edefee6b9507bedbc566a40eea2f2c12345d73aaad5b0a0e58573262cb658604216945f84ba3418d6579ee7b054a478282bcd6f8c677e8f78d384a156efbc1b74d0d93da3519bc966ef4df0e343bb2e5000000907591ba28ccba8b9c50764e549380fc267f82883b39b0f119caa19989c85b6614f019543fd72993b0deb0eb63f76b156cccb91b703d5f49d0242cdc8f87d7900b33b5b51b8ba6239877500059b79e4a5693a9a211d0856f66cf28a0e513bd21011ca9960fa442e2139b2c1346d54051d740cd766ccf8bc210acf8e7f89d2e5a5c531958a1d70e5b4aae8b1bcdfd2eaa280000009097a8bb9b27821be4c9cde2b825c84974189febf913d0fe5b1a85592718e74e5fbc8a58cc0793243798ff7e63873e6427165d50b6f1ae2fcc1827a3caba99edf55b2f0509fee702b0c97cada31161528a9d057cc169194d6634e89f71751ef5ac0fe340747a8772b0835492418d440d533867663a23eeb7d0b0da24c00edc66364d61f2698d266de3e15c913ed7d585bb000001bc000000908d620422cf728c49d8dca210bde4ac29173c54a0c59706d70b14e9a61428e749842194d69a1e8c1922b95316eb2861d2952a9facd19a44a4fe4deebbdb18ebd5207a6c5270518f6675b019a53b959f72a57a5b3a3eb775d44d189a307c15ab8fa3d68e10ced78df01c6aa0c7603cab8105596d30f80a6ffb2a6988aea795b79b4ab9141e1b4e789cce72810fd8137cad0000009060c64a4e5095fecb00c34552b9d6b95d925ae761c542e5e334357d59a883cb8f9e4f978f6c3392eb975ef6967b1927bcbc62881059e4ba890e062dc5a841fb30f365d0f5cefda395664a61bb0c7fc1d463923ecc307425d06060e1b55c0b5408e3682f52af0cbd6d02f53e30ad3fd51b0db716c08cc98aa926a0ec4429bbe3c5cba30e1ebf91ac3358a7c7348627182b000000902d7bc27a2901195a20cd31878f961703cb0089010d4279644a48f3d70069299e06cc8cd17cb55d21f0b0450b198a084630addc95e308dcb4af448dd14918cd8bca521e86125c8348686c0ce96cbd830262506e29741966c523c7bebffe2e7742816369dc22e300524d3abac6a59a27948b896c08e59cceae6de386c6011659bd950d443594b2894f5b88c8e756719f1f000001bc00000090a2e2164ce724dc79fa8a048b747319e92e8cc376f3972901b3359b826a7c3b5fa29b6b171635834a32302d6b3fccefa551013dbe2b6bf0944b73a6df7cc74148746ce0dcc8ace06123c0bdb84a2ff5c28da3485f9eda726143372c9e5149c0e3de65b1bdcc6123bb9c74f516153e1cdf89da6880a962efafd1a50467f31a7c5deb5ce3003ddd5e1a30b13d62615e23af00000090f90c3f9d00a529470c7b8320bf7215c68e96bb59b4535f456ed51403481f01dafe2495d7204b227020cf4872beee0d136b4d538f6cc90688c5889b7838d04d983551790ef8d0d8f93ab4c0a58bd2d9717bbed6055287e1e374cce22e762326f5c96f39ff0dd5e7e0ee77b661a53ac7494431aa3d6ef27822a442b7001dabb1e9adadff492ff1895c82335763bf6c8131000000905956e739385f93c95a1000cab5a7110b84b54357e443a2765fcc0573561c9326773fe6503c2536caf61e3b1e2588f5b560d99a6b83aca8297e4199d879987f467fefeb4c29572d521c6e1cea5ddd60b184d16e8ad14a60160ccff796a488bcb642e45a3a222d91735c9a094758af8cf401c62ac9e43706467021c2f2acc3da7af83775e36cd80fdb06c4c320b575480a000001bc000000904a69629cad93b331b5e5de04b86a338785b62e85ef949002bccb0bcf34ef996cedd9926890e0ee07322d59d552baa0a44b242ae38d6b90b41327ac59b5bb9a073acea238eeb523f2f10c2205aec802dee142296b43a8274b498af825e574ebb6be7a97bf7a7d78a68f4239a9fa1862d63dd7fff4f6ef9f4e2f65e1329cb98f13972076a6fc3cb94e37b2ee65a4c3fb750000009028a56df2a84845a9d904aea29480e238cf1eaa499f4d38c11e96e24ab05989f6d3c7c9aa1d1852a5969bedff0d2b583535dac5ea8c39e793b66c4b46838d80dfa30163da022f1e057573a6a027a5e181fd02208255a784345d641bc3c0bece1c6d4bc1b4822db16e4012c6035aa153aa1c0b0eece8d6171cf9d3d076bb33eed8b97cceb7c3b7bec8924b4519973c9efb00000090247aa902ae72f8aa2e3a894d37dbeda6f5396d2c0a6da124d8bc4d5288ff3f6db84376bf6482ce899d206dc0c1eeaf87313b0310fd2c54eca869b20f1e6f6bf9982c50000ca1ecae5d985a0e78491d89b5746664e4d9c5b9975b4a8cfde77a7d05873eaad38de6ea341e7905a7acfc38b1ce20456cef5901c8da14f69c6c1334d2e83896fd2796ef7440dd97479bc674000001bc000000907e82eabd4bc50187ccf1f7db45e3a913c5d9ab33fe4e70a7abff858d105dd8eebbb6ecf2f6f0d617872a555fecf79f01c648253546beb3c5d99de4527303582aa283057d2d1697c61ad2dd8640747354834e8420299b3a76d4549282fabd7b31771ba313d37205bbbe369f903b23a983eec886411d66eb05b4dbcdb15865da5530ed5ce6163aa840cc977c7c36fa3f06000000903ae26dadf99332d5d17a04a4b4afb6bfe2d99ca9ba48c0f52b0784e45bb645fb703bc4d11803fc9ae683daa2318e4fc359622a3cd946e65bab5816b8725207004446dcdebe0669192b21c8a8ebbe7cfee887de9bd3b5e130715560a9dc182e7c1aa0f2422363c4ed8bd07147f3272b9da3aa2fbe4233ed7416b15b10b801e3441af61d61a42e8256babb5a3da9a5ef57000000901974c3577265874c6605dac4c5f1d6d54d3b2da3d62307e97f09ee041355e007722a47f573d723cec64463e96878be364e228164b00fd4f2c661b330670e8ed9172035b11d16483953c335c835d71c9bd8e041ced32243671fbef2245709961bf3cf84b7c426179c6df13f6bc68dfa0fc68ee70d66ad02a181fb0ef23c2b1d971ffa1484f85a48e65136dd4faf97f92c000001bc00000090e30d104221c154bd269689e3bfc8640b2c70ffd3eeca50b981e592b4897ebeef990e56db03f5ac15fbdd5b109803f84bdf30a735e523a3f07b918ddc46ce5919f44e84c4be459acd2404ee0111f8ebc05063f7418d97e704e4c1732eb2408a027dabfdc838ead495ae8009eb580bcf391b6e3e2120b3b0d55763390047c664075fbbc2fd20b63b4369ffd309e5072ba700000090dd87636db931635adb5b575c946f067e8420a61fbce791a0ffd7c9932ad45ae77e8a24a08d5e865290ac7a408cb59683e661806aa46d242a5f7a6dee9a1609c6924784b6d2f619b2e3bcb481b96a6e7662c1962d8cda151d452ca27c60f61e4823937b0a7c685f9e2af8a9416562b1ac676f1edbf638c7b1a21cc0d67715cb18aeaaffe2265fdd061915ca026dc6cd11000000908ea2c469fc0b0ae2102e4f406f415a262ed2098525933f79559de3b9f8d91b49263c32eb885078071594323c294c71ed3a0cc4522d057cdde1ab6e7c25b79a8688060993dce8797dae1e9d33f7a13fa5fce01d18e786ebdc26338a363ed0c57c0f4b02d564bb6fd9550e9be8182c102756160941f4a92c69a47c9282bbfb2921447e47542ce3607bc935c341145f598300000e00000001bc00000090943fe22184fe3f67d222df0e9c627ba0592ae251e3c0310f07b208aaa1a90a7a2f741e0a782e59ab6445287acebde8de40d8ecc6a2d3dfefb6d04a517ffce738a2916a2c898b5a75215663ab4363a5116c6af2efd1529732f0214e1fa47e46074d2062e4e779b3be47baac5662b3457fdbddd246dcb39712e22b956dbfa2f552854b768f3180edb584a38d25080edbff00000090d9b5d959210ab32a66b08fa8fdeeb14eda3ec06277a633113c8ffa1a3dfb208baa006de8dc5e31ec33518e3ab3b62bb2e18ca760d577d28064e1339de09dcf78710780488f24c4d862b55e1c292e84fb65631bc0fa2634a57bdc3a577a7bce8f50fb953969e32e09dac676599b0ba045e21b625efe54bedd0d576e12040812ac94091f5f52499a6aa82a916a15ca8a2500000090d1c297771ad9f29475a98e51259921bcfd8e23069eee19674fb3ff7ad061ffbd8a1a0cfb470f96b98f1fb155d86b31543fb422b7d125bd502e51258536f3e98b20face7c0f707ee1d875a55e3c5406f314fd062c8b1e19b815fc523e95a8edb72e33e984c7095ea7972bb3103802556df82c4b4084ba131bf290a846adf08e10a08bdd03773c0bcbb6074426e0473ecd000001bc000000906fee03c1031c963c37854cc26d00d5939c19765689071ee547c26d67ddf6ae0c92ffded67da6e80837f43a3570dd69c5b4a2f5cf997f5e2ae8b5111048ce7f33b2834754a0037fe5fd5ce6e573fe8b30c563f20e677206a94ec782805f0588addbd575825fb17f2e5e2f5194133265056e6c810b225a3bdf683ce0dc240748eb50e977c31c3b3ae20ab33321ee3b39010000009094b9d079b7bfdfa091bbd55d5544fd4dee37df45651fc2a86818e8d62d6d7fdbd211c81133434271d4cbf95ba8bca248dfe4f73baab1afe37c3865f794a2abff37d01d540f745076bd7ba5e0e9e042f33372ed5da6d49e6f9b7e2399eca136a69e42fdb02c76b80b76e7f0d0467673d542d35f792295be5736d83323fc3865b112267cb03057a3f2aa21ae3fb1ab0d82000000902558670db8ab6a0254f058bbb09be6b22c21d9fc7f25ca1bc47bab5699e1fa762e9a139cdcde0953e6cd1078b4b23ee163739b560f6ec865e39bc20ec4306e5319f5952f25631733f74ab250e10a4feae52a02a4b7d94cd600aa53f18b28fc41e603f9f198c06b91d181c5ad37e326fc40eaadb7e823d09fcab6233cd4a53297bd1a13884ebc344b76b7ec33886f5071000001bc00000090c3a167fc49d620e300cad9e8306d2d70b238289de78eaa6c1febe1d2dfb04c43f17204de7c2dee51033933293a21e1515812115e6daf8340b44768fd155027684c4df71236e0e7ba4c8043cc2c9e7b8c1a6a65b15f31f988bb13a8f886429bf7c5a2e5634605fba86c50b797404455ab0e7c56be80ff47a7268438de1c28b6ba493b7452c54fe3ed6f96848b06a144bc00000090ada4f4e507cb51f0f4bca7c8317b1e5b3499219bb49adbf7085b9ed02e1e0072ba66e2fb2be5365ecd02af0e76d9399f320f448da83038c529b563e26534d39898db5a0ce32a1be52156313e8e2f47e34b81efa1969946dc858e1b76243cdf889ad80f4912a3a7326dc5184c0961a4a687711ac29cb726fa9e4e5c00bb44ec072ff482840aaeb4bec77c2e9d56cb3b780000009095e5334f913cb0b1f38c904a416d38db07bac342e2c3e325acebcc9e99d41040512750b1f49c420d1e94bb4c180ca5c64d69eef59c7d4013dd558061b2cbb962f41513196083040a068fddb329e91ba353782a5b679bf43f945a052e3f446fe65ca4c01c2527d74d8ae82f8b3574b5d8d037e82c3db34bcd1b32e01c1ddd9b168c232ba10f2901542b3d47d66f7ec865000001bc00000090d653693d21553d2c9bb9dfdd080d6b27a869d494e04968b0de576beb3c4c71e169c47ee7082bd9287742e1d359582c45d56d415748828fa94c26aa28a2f97749c69a6eb88d62506db6b5129c6cc541233136f5fb6aed2276ee88fa52bd7efb0e7d0f5ca030438f4aef29284d66b12cdd8bd72ef4aa936709ecd4aa7dcebbc827f1a558962652df3c9779a5e606cc78560000009073a019800bfe79e689cff9e61a4f99ddad0079f51baa2a2adca5d2c26ee7d3b8ed155900f43bcc7cf0baaf7cfbec343fa896db821faab2afa528058f140dc64194f03c95f9dd5d1ff32aa7b7bc18f5ca196ad5f90b2e237a1abce640567bd00cff8a33458c9d593a4eaa83b24483083c3a5e30df5405ebc15a6e0fff9ec293ef4395b6761e4cc9eb8ae2b183267d0663000000904407617ec068bf7bc23eb8d4a614f254b6e9d358c5006ae7d8fe37538f87e7825b7e4f00fa02c029f9ec222652e115c274741fa4099430814d2b59b7d0154dcf51e904cee267aeb8c79b46dfec7395285566ec78b1217d006659b4ee85b65922e851781c1ece9665ec490c2953fc350869bb41dac3a331f451be397ffeb3e18e41aaa550a08bf759858c28faaf6bb2e6000001bc00000090579729993633a739a8384ab1dc6f451b10c4b7ddc23aa10d2477e35764a921dc7832cc98fe44a27465a330d903b4d1ea1e132bf8f9cba6859fe87a3c03fb7c1d809292b32e4f1581216f1c2279415788683f4c4c244db56fbc7f5ef666ba0f49b586ddbca4a1888d623493c83bc3ab92769bb9212f14dd24a91a99b0e238df71ebf96d94fc06545703358142fe8c13480000009060d05195589cb03cf182758096d085633e03400270ce487c71f45beb1c87df7ec26ce29af35d8ece3dae1d04fb30b19563d701e98437320cce4e6f1bf4995ae9580d1a7201478655f08053cf1f135cc1d55febdf176091f04dc1bc2f6b9d29d8737e14fca90a6fcc9f41b0a38690ac0522f7db33c3aff847c8094bbddcb43cfa3ccc07ee2ad4eab11f2380342c502e4400000090ed4ff7832dce8aedc9c0614b78fbb47760bfa79d6b08d02ccf13f3dcf8429dbde4f650371ef7eadd83600846f3b54c7e14cc2c659513ca05d30cf464d6a1efdf21bfffdc129aab1d9a853a49ac29631bc703a4e6eed3f51daa8f2448cdf40c3109eef826b8df8a9af2100e6cc399ad700446dddc229a7b19c35fba62e17705c2871e338e814396c01b3ee926be407a1c000001bc0000009014e257c88811c6bb3194f38f458e5ed2e64294e76297fd298a3d9ae79d0c33b2bbb75678a83f06ac67cf920bc7658d7a2d0318067474b654afd9df92b2a59ecb3865521262beb5543f246e4f0dee742eba5a3f133fde0897a7a7288821de6a1c4bafc6f1db9184400854b70cecbc439f111a814619e02cddead99f97151103b8521f96669752a80570b04f4f4039e37800000090665296cfe59cb7756a27bfa997e5544f63d012467fe867be835a5d129a6784dbc88603f8548a3e6a0e704b6c6f58e376270e1ea83e4ae9b13bcd9a2e5383ad18cbc5fb8400be7b0bd6e13763d1a4b96d24e62acc439f58b7d161f2e4a6fc44ade2a32b7e656efda3284f3534b17df94574e181efeeaf837626c0a63be3ff3385f44360b8f7f42280e37cb35d27a500ab00000090ab715a1523e6227810aa86895e6c77c72c18f94427d74578f230bcc54f7734a6a18e1c1867341a8b1f4776ffde973e999bfa7db0cf64bbc11dd9d2da5add4f40a12eedfe5ce86886cfc945fc046241e01354dd63f99f5b16256b29bb00d3d0103bb2293df9c7d0e363096dfc5f14014d16174dbbe32bcf62f7652bb02154dabe8253ba7a45c0017b12d2c999a2d381d7000001bc00000090a99adc23e14850f5883cc4b0af0cce7f7f855315507cf0597601c9bed68568f6288fb984b5a1de81c1aee6a84dab68279e9374badedc7542ae6b4a00294c9797191dc6f35c9b73005f0826bbe5aca1b1dd838aadca0aea23f45756ef87164d6bb95435a89643929ad6c2f00f67a665334a58cfcb596537a086b806cf53e53797bbc6bd7c529b79ff56c5b34324e5a2cc000000907c654afe0b718357efd6db3797fe15c44a129063f7281531fbb422e94e1af766604f3a3a43a118acb1e2d4305c0dfdbb741f23216f7acf15c16e3d7a5b5a1f4f1c19c16ff797ac4476a2f390c8d68f9263521bf8a9ed20ae27cbe370c5afbddf978cc656f4042f60cbeb02a86eb6cfaef36768cd9f3975e17957b8e6e41442d579e246e085244f4930cf503b3a5d721200000090e84aed46f3f676441633e515584398a58c8e27605b19078d3db234b6ca566a4f38a43f2889088dc7e6aba0fc595d9ceaebf5ea6f7d10e87f1cc517fba9a66153a92160a45ffa0349b20c0403bd3e8608be4c5482d9eda052d2d9eb7a27c6ee8e870ef32e31517a0a798cf34df89b010ed0031a5a0bb65abe8036367658543a93506a4e4962ce49d23e9ffbb8e924ff2e000001bc000000906fe8f93e56c6ad3842921334a914b7ace1d7cd3f4077962473abc16a902dc7593280497f6bab5dbf9c3ab0ff7c8ecde40c94db2a36bc09f752854adf27e3ba8f86708771d8803bbd86b870a752f8fb4365bce3f1609a23f830f43b8373c8e8b83f8dfa7a3a761b03d22cc80db35a598acd8fd1a1d2b5f8c152f144d46bbc821e9538387d749df672a1920597c60fc46a00000090d211afb2529a2d2b5d7c2638c0ceaf28cdc63b363ffacab2f4981c8ab935cc96f928950ad4de82878bca7bafa5c8c468500fca3a8093ca30e4f89424cb7a50129f17302ae479381013ac183b5e4a5bb419b6c22746658810b5ddf90955e1929d3f4dfdbe3f3cb03aca9319662df0fc567dd5a2978f6d78afd18bb34e2e2192d4315a1386a1a6c83e15d69f3270f06f5800000090c37b040bca12a49b876d83897ca9b0d4893a2393a2b527171560ac44ce72a83bbf0c1565dca0d381d87c12b0f15a33e6ca89acef1786e647e42027b7f2592e88a332e4667862f2bea786c6457fc901cef597b59f2c043b6794c84f9bd671bcc5123ab5ca48228e72d3bb2b0d4b47de9f309a676b08eb1d2271d568bd93df1df9395d444aa5265ec0e14e90bc3954565700000e00000001bc000000900101d350ace76eb7217c7a1556db7f589c5089e452c6da631bc234432a7e67fcae47fb056f7f45d666f72c8fc05d86c0279831b1a2bc08a299c2447552dc0ba83f92f3a7e44457465abfe165bca0c22693107c1955a42a9bec0c929161f3f62554f50bee006d66f280e9694fc9ac29cf2393f963c3d373377b91547d48ad22488f627984c471ab86ae2b0a8667b5a8a1000000904dce6f999e8159eea70962a4dd34417d5622a7878320de80774f28d7ccb2dc50e63db3ca85692a1bcd2688c5061b81fd4eeec450908f3991ba35d6f5a93436b33dcfbcc111197a7d5c46c49e711a3f9f93cba3d6fae23dd857b7dd2d48b782121fd6c249ae67de48f8d7364782b7920bfee9fc34aee28704721764df276e053755b2e2d977129dfd83736baf83e0948b0000009058145f0182e57b082ec149774f3a972279810debe83e2b4fc941d426795baacef254420c62a92dadff80d04549271c58dd49c9b3b6e681a8bebf6ab276e5729078d62fba15d0357356cbfc9cb1aacac3fc7ddd76f4befbe60f0f191a1170a22d4994cce145ed3d85f4b7dc1dc862b8044802bf7c9aa68a5ac6825016c84bc069c7b6bf9300b5cec11d3f23fcd4cbce1e000001bc0000009006937a40cd590bb84521a1090bf6d114e4d8171bb146f0346e8a9b5210ecb96e29340f504eb5dfe305f908b99d17ac697154deda8bf4afb074857c01373966fa5ffa6a7ed1997680fb6314b1d7ce70d4917a6914a91175fe5b505e7257f374bb75188f3f0653234d069998a325adffef290cd7c317e22ba887cb4c665bef5661069f4d733175260ff543193cf47b5d8800000090a671cecc85173df036c450ac6d018dc33161fc98cc15fbaca2de57142383da676541a4e4c422e254b837d9488854971106d41e2ad9c97f5fc0e7b33b44a57012e8048406f695996d9e1e832576a5422f8bf42a834b23b3d15851a95b18b407dfa8d32b2d5c2a2a7dc1d7e242e35402b29862b96da10efb098a6d2ab30a18c33a81779500ce61da3a74338e0344aabaeb000000904525e0c63b3d40eb031917ca6b412984152b1c296a7a13417120b8b15108f3b05427981ae30b8d587702c59402171b77a0225c36702437a838468d84f78961885e9e1c568fffc040e8b23a306a81952537420be70973d0625ddc1a7f3a23102938e176805a819e717b100da6790d7c3c67183f6708283b2fbf2b57b2cbd415679755a61c0362f7d2953266a8b365ee81000001bc000000901bec1920921d1e9be956ac80602091ac15fa3ba11c31abc644ba1ea6b7cb5a248298e0c317bc6bd3f5036208d80829d7f1aec1a231d8bd8e142eafb63c8edb95683ee864c6b0c2f0717ff70ba0cdbc27ff5378c025544c115ce0dd1ada3a0769da1c7079d270309dc15fae733f81530469aa5f6730516b574d62fd04e17b6a13a1d2d9c7653e47fe03ee1d54828c1ea7000000904b8f449362cd7938355446d0472cdcdd685613d341c0e53c681514712de1a03bb890d72f5e0c3bc0a292254e29cb07ea51f679bb53885498d408ff09468b7c0fcab9c32d586c3dd49ca5ad65647aa800b30c2bf46fdeed46482f0cba44b5c052b2d53d3dedf99613885d17432b5fb38ddfccdf2c85409a020fb5c54ff9e99770946deb80da063d1af3a3dac76fb23d060000009078445b7d3c5541be6191dd737454f22837c57360aa4da78715448f6b68d57a5f4560d2d0a7743e9c21b27fc7dc97ab6990b806fa4c981a06aaadefd9b4d973970fedf8926237a7be3b1023524783ea199be8202455bd9a3e32e053d3100c90b37a7749bc636429ece3ada6cad78aede8a5547b3e0480c62ec3ab7c8d846f6eb443b845349a87a91c97af526d0dbf4a13000001bc0000009086fcca38f09c08b660a3c3756c87bac93fcb575fcf5b1b03c867300982f3d12111344413a29c7bdbd996f1da12dbe0a955d43c2486b77bb33cd850359199e5521475a110c25702e2c945e333447ee4396c8cf0e41c2eb0b68a452d7022b1f249e929b68f4d46ceddf498216e25b87e69ca287e152846c883128aba03d94e801f3adf4e35caf3f75ce3c73d9d0fbaa74e000000903a1395c95b1dfa7727fab06373b484e37623ec93d242e1f98c0e931b9af47cf690673ee8af1e127d2e0b7788dce562c0b9d426536661b275c29c0ec104ee40234c4ebe8d62b667618c2861534e3add713e4d53680f14654afab0c4b9ba48c485bc5c6fd921f111fb90e9b0cead094dc910efb8b1c22d56f91cf3c4cf21131345768c6261fb42798aa2542fa3f21ecd82000000906655084969d959c6ae04b88ec65a582cd3169856bc8b730384dbea6d6795129ab8d5a27b56db9f8a2e397ea3e65dd5da52f120e909ce58ff4aa35910d44fcf54f0608099812687c7e473489ba061383f4dc2343744ed1217ff97824f52648557112e494a127db6fe039bb412c847e5473b1ffb6aaa6f9bd5f18bc4ebc6489d55d9c44ab28e48f5dd78d58e83c0cf0342000001bc00000090211151f24e8543583487341e8b501f2cd752571df81d43adb95288cc3d76c84d944464c0455f91e841c0f3a9fae9fd26ad96bc513da3d2c4a992909a99d65073686eccf7875e40499b66ca96870f132fb5f4334fc188e2c6a511adee46b495694a5e58489a7aa6135329d1ead8c9b520856ba2dff114d39cb558fe02369cf294b30db002bed764d93b85e0ae2d9bf030000000904c317b2e54b8f05ec940e0e8632faeedeb887f9655dee11957841ad50bb05e0c24a7323d53a2e685627c0492ff1190c2e28a719bb5c5024fa6dfbf72bc8908651e1dc4efb20dfba730e0229322a411e780d63a363bbe5bacc3ca442e14f7a1443210a133f88a0f51f0c5913550a1d5ca02560f3fa6d5e2b18ec17267b14cad3be808d32edd2e4acefda1441632b1991100000090483fa1706e391f4cbe5c9a386b98a7b7f655327431c82b6d1830a1939f982c81c5d5e60016ada2cb363c287465ba00ce32288759ea281dc56b407e8694827f043f0f6f3ed73f633e06e003121e4cda84ff0b499280594ec92cf36536f5eff82612e26dabe34876735435946928ab0e3dade20c12680af47cfcc72deb8f77fead1429dc46db9356f78f9a370ddf467a16000001bc000000905b0a2bea9a87fa8552e069cfa33d68008add3aca8276af590cdda1d06c73009393011e7a9b09c35de0e9c5d5420bf0e7f78322d20a2cfe5fcf2e60cfc87ae867e6286f81edf25f005858c9f8cd5dc960c9dd493e3467d40cf2fb0dee94b8c514f5bba1f029d0d938e602c0a6fb94047579e51ac9a91a440123287f50a1ee3b7c556c68a87a3ba194e66f9dfa10a2467100000090f366e9402265e88f1d235fce61ca4211ae2054d3b634ee2e3ae025429a360dea4984cb32579eb84794a6658e88f3652f75e0218b487cf3a1b90dee4546bd4358dd151125ba7d719b0ba0055a368ef8f99c1798faeae593d81ff18dd7bc73aa9c1da04b40025bff1d1c0aa93bcc0656299f670a6be2d9dcea4a1a63105e315eb9e97fc4a6cb5405c8eb605614113af6a4000000907bec28c4c3651a3821ff43a0615398d0fdcaf53610bcf13e8630a1c0e83358d094aafb287de1f557b3aee9987a30ddae141fd4c1062e0ae0dd2e89b53f6fcb1bd60f2e0fd1f5ee3734a03ac2fbcb85c3188ed896502d4e8f6d6910899807dcc70a8231db1c474efc392be22b350a4deac49a5e5d9e57319f7e2e0de955b6cc0f8d295b1f79092800c2a04dae9a599bcc000001bc000000900bc1f6d5eb35de4eaf9d3ae4a86a3fa21c3f75bb1c42836dacc9471f4ca7b69c3861f0a738a1da6bd0808725b08ce19816ae3b35749b00dddc7bf6b88285665b48dfda84327e134db48f37ce25f21b161e2b0cf3bde27a5155a04f2bcd7e1bc59971f5839be54f8e9aef3bd1986ca51ec03ecaf46a2e056e785664552b98b6c8aff828950f214e88f3fe9d59e9c92b220000009012963f6b5cacc9f03f7363beda8db4c9398c71e1de79d3ae024619b0911e9855cc31a7e1f3d1ccacec9b1cd5bb50a41bdc71d6d43dc68da3302dd7808e56c5cddb0ae0b81cc377059535c31c0a9766784d3ed0f4dba5e775e9042de1cdec34450b707941502a2ff85bb3526a81414b2eb3f5e1b21092eb4d2ff118f1eedbff795c948dc36b8636c50a318a80375da3b1000000902f22c8f25dad0ebbf338b82f0a7fcc79902ee80e2ec0e7104140f0c6339554f55cf6c4fe9ebb22cf2799160edefc20dceb259dce3f12cb30381e02551bb3d9f5e16f3449ffcf2cb7e45fac07a8d290b458fa30df7fa6b52edcfb81d78b664b7ff578d851bf31c6916cfae3321b6d90e7a16528f695f22103feefe9305e69ac946abb76d4190d3669f064ad19c27072e2000001bc00000090a961e5ace383de1ff8eed1d17ec81cd1fcb2ef4bc0509c62cb0484e3563faa61d821959b7c1cb50b100152f566c58e1e7484423aa9a962deecb16c7025e1e9f753e1236a72cc1032c17b6579bb09273ea4cd3f75d4bd11046326afa3d08795c7e276d242d94332f50d3e7064a2420f4071ab7233fccaa7052b4e44396843db61cfe57f365d8d8aa19f5702bb3481b84b00000090b7260f6f6b2805460ed6b462cf4985db955961eb0e9634706f594ba25450faa57f4d7b75b8ca78080230a03e1a2f8ffaa67fa5cffe71abc549babfee5c5d19da176a269012420b728dcc78f286482047d44b3e6f50a07bafb68a8482d404e300487a8d463f5d667bc473811f916817b67659a45f95d083aba4d106508fe8125e00667f35005e3f234931f2c31cd77ee00000009065aa5239076311ef1a52a0bcfa20a1c9c6a887eab93b6afec9d69507d7657c86ec840a5b760f18b498307580ef5b3fe8352d451ed4f74a2af3ac6dfca221b1478dde322ff387450e51aedc28591e5bcff32f9a4b5626556737b058912372033d0088d8c705f72baaf1e20ac20f73fe0417a0317bdf5538e148ca68e089d4b4c0a3276825845b198e269ff0a490a8b0ff000033a000000ce40000012800000090fbea4f098f672aa12ac0ef989f89014096ba08a83b50d68b2f5cd25dca09099d52c0c881d2096c71f0ce4212189840aae9a5251527523ed261d1d65a9a2d6039b80da7a3bbf0f2ab4ac0e962f3b2d46bb1f178356cc92f3f1e114a4df060dbc5137e0e384feab4c574bc676f51cd09531ce8233920b54525941671a0a83825e39fd5acda465917a095d485df3c16f60300000090db0de2971b2417ca96298753125d2e11dc4ea5541a358facb3113eb3ae317282c8a07f88fff4c122f34e60dfee619a3ff506c47f855d9359074980371590e6d931f90aab8ef9507e4b7d61cfd57d4ddea7bfe0bde1a69100fa2cef228d1fe7c02826f63964e5a354322ea8e8df15b71f16f7a84ae8fd347f1bac007a5b80a161b191122f5295d5a528732a50c548e9fb00000128000000909819560794dfb5073c22672a07bdb94687ef6962208a35c0c668e26779cfb6e0b01a02104b716b66713d3fba174e89973c75f72d0c0b2bec94b5f90ae38a1c95f4b2ee2ada51f4a4fc2140558b8f2aa247f3bb8a9ae02d92a9cfbe27ecbe2ef3490de77227c09badb8f9ccd9ef54ba6398f9aedaf3457503b80851ed22ddcdcc925b5e85e2f5ed53f65b1375fd370fef00000090596df10e31677e2c4208d17f06012e16b42f6aa208546587b39d13ddd3738b22925b35fac05d993a7917a4fbbf5d23c2231e9555aa0dbcc35fc6b12f3df31a0c2caa1cef186e4b9bb2caa824a1a216767766b34bc4712ec51f590a06350c2ae6acfad5da63bd56c15d0f909d93b307f1a2739eba554feb0d9334a7dc6323224e51d1b79bacce8b55b1e29d22500f403800000128000000901fc1414e0539fe1d7054291dd11969f15e478bfab43a27defb11ead7b67f65bae7638e0298f524e4ee4437c409612148e80b20fd2092ef395dad14be4320ab068bfcd8366fa7a3fd4a1ae13ec5aa0933a1d74f294c8ff2d456c097eb62719b6e2cec660272720ca54401e409859b784770923e0b6a05b1957f0c5a71b7760a1bf15e0587ffa2b1a8c2bd2488ed8fdc60000000903117c2410c5e26c798a3d878defebf75a538a828af6205694e6e6b347dfc536455234f53be06d0c3a1d219d231acd819e254b970abcb3e3406d1857521aae8229ab909cb4303320ffe9e5a000bb0694833e197c20dd244ceeef843c2f59e9f165e6ebaa9c8bed4cec922aba70485a2ac8fc8b8c0d50e9a519e1fe96f3d0cec57048fc21f638b17ef85d07d8d3b98998f0000012800000090c80aa2c16a07934be76adcddc5136e9e7aa68356129d3202ad7d47fe37a04f08663d063302b79b4b2207dd76f1e29bfb686e781c5ad644019160d3696847f9d65b7309a8b64b38f72500cc5bb45e462c3b05d2ba9fd728bb89e52729be628c4e531b376be88b3826e7f52eeb65675731f23dc2383cf8776cc0f689d330ee6d6c4b185f39503935bd186dd88249bacfdc000000901ce3c103951aed49a3bf1b4f24e190713a34fec8c0fca5dd9ceced8c6d33177d7e601422282cb2e074382ef2e4b5b06e49a6391bdc8e105aa96027f1154d422e975ea23778e9ef85444003e192ac19e07e1788a9bc95646158200c2089498454d39a54cba148856cf25e558148fcc6bd5d3060c09c3ae2fd5882932be386d80f080bb5027a6a59a2755b3172cf44a63c000001280000009065a8a613c0e26831b8ca18eb4581906720d49226650c2ba29097de1c85233c53e33c65cce697215aefb3a2c8b2a04977ad3ab808657607d8575707e73a800961b9385566eb9ecd5d502f0eed16ab30c9f4db07a4263ccd6f965baa14dca7cf3284cc9ee3677e440fcd5d0bf58c51d8b46c493fba214352fa79782b8af1b6944c0abeea8db8d3c3a27aeb81bfdb7d02ce00000090ac20ff8853989dea6e27beba93e50ef7b8fb8d7609835534dfe3f006e1c72e1455b783fdf369a43562976236248377a4a19437415716469472f8a7145cfa26034c5acde370813a86d5a86c2e381b0310faa6b609d987c1b72894fcbcd2bd7cb5d86d004a2e682bda86f0ddbc03deb3d4a259e0b62613ba11de27338c00c7caedcdd0291c385b272961d9910ce1ebd4bc0000012800000090b72e8d33fe7621cd02f00131c0841ce8c9cbd1a0ecd4e0d265950fe1a4945e44b22c8e49cd2d2a10ac4017b83c48fbe52dc6f6ba5a4a26aa348fdcfdb23ad2d624323d38667567225973339a0a7670972d5405ce8c65511bb1d471207e1aee38fe796cd153c317f551424c7819c22cbe7bab56f3aed106aea9e454fcc5a1d5f8aa49e5059fef332738540e956b813e1b000000907962adb0b70c292698764b7cbc5e9c04d526eb7d07a11788fb8f922fea897e6e361cc78305b982b6be79afdf7bf56082fa49fbd5a7faa27b6cdb5918e34ad6afd141fccaaf3623c25dafdeeb95766ea9b67f1f0c7406dc9db9ef2fd22f49c19e7c7beccfa65ac95aa14687e04e0f6f9199e8966b2028ff1cfd5e0e416259e88ddfe3b1a3ce07032065635d7bf620ef1f000001280000009078c27cccf4f93e1f533472b29be3556488ffb81e6d5c23d4e6ddc1c95c0813f137d931de9e1deb7514c6345769a9e9c81c84f1a0d11c9a416483924d5fcb658d7db53cb8f4397c20c6830e0acdec296e80bf31061fb2e4ab5923477547ad9470bfa318739cc084776c6a85c013c11cace48a96630185d1eeb7d611353a212d72e2167fb2596b0fde2900292e2c4f555500000090424ad519386ad2c2a851f8618ae38cf82188ca881ab8245c48dda17aa7e3780a532031fe08773a7b76e6abe18a1c9053e19671b648c6f6e34ed7013ff29d46524e231c3d2583a528664a2eabbcf314117d8aeda77604535a22e324178d70447a2967238fb2849fcd54add439637f8aaa41f528c708b732763ca002e12a6bb9609c729a9b5321b903acd103c0c3d2da5d000001280000009099baaf560b23120459bc2b7dd4e3394972b7a5cffe1a0b48e63cbc6f8e1de5e86d7029b5b4bc444a7e40f64c5c2cf9894b80db8eeef05737884e3951f7496b2a8dfeba25803a4a45cf74b86c18778c9ee824d178b8c9e68ab7c30a9f3ffd4c27aeba94b9ec35e36d1f529824c687a91bae25f6342df759102a4c1d26a574ac7d638b901cb986a747cf504fec96554ffa00000090a18d1c688ccebe26064abf94ba6479dd2304c052b795e0652764bc6c6d7957031765e600502d98f895c66c9d909c6bc996a86052d393322718c7aee47ac3129b35252dbf285bc9fd98d4ebbdf9e0383ff86265bf2de6caa6bcf586ad211ea9d372e884568f307d55e20f12688fa1b8f657c6b05d55bb32b32b1b3d301b9534b593ff8f9cef59a2ae8d9079872c9b8fef0000012800000090ee1a5e14183e22c8297e3c9680119f3982eb78d5be8d47da5cb5f161b9ca53ba0339b189acaaca6c9da63457b0d7572e8a5f87a090c2a7cba681ca0f08927874e07cf404be06e211fed4b50af0b06a30d56e091f3ade7bfe23d78ea893e86a3dd0a8bc0d99acf8e7aa87a5ae37b2e580fde0ac0839f691bc1153d697d1092c73afec71e6df80805bacdeb129180cb730000000900b5eb19d702ec095aa5affae930a09690f55db66415673f78368f3deca9f16e816cf1472c3d0d1e614ebb912d0f79c0d4243cbf9b9c47ff6a5d0227ac4473db597bd96b0f0161aec2bdb8c0953d146d894300891a47f857acd8fc0901d22097252840e767f474ec8f257017d17282869a48e63a62dedcb1df0e93ea7882f4886a331ffe168609e711f1435f37fce99df000001280000009099bc21489dd17cf0f7a544c062151d53afdb7d6c1629b1e74aa5ae48b357b84f03af30c0cfc306e13a91948df92a9be093c5852f616a1489e510567f4c28eb73d3c3caef42befbf24855d042c2a007c86dfdd55b748fc675ced1cdb353fd7f5cd0db2674bb87a1a5b2beaff27878c2ac93a6e1d7d68264065303a987a86035747a07fd9db76eb25fb7fbbc093743f54900000090c5f8b464dad6bd6adbff5452956b90f959d3b822f8f15eb55b3f5c9fc81ca7874eba1237fb746e9c4423c9c4f92ec8635bfdd6bf829481d8894bd9ae6cce74adc48237309a87c53d198b517edfffdee0f5df57c0e7d4df314cd6479fe04dc03ac59f7a43b4854b13b23408cc728da1e4e2dd128906aa8068f396970c6d391e199d4f47dd4b32e0da795d9637f9999a5d00000128000000902b963c82d1c317bef3bf998565e9783f029902333bb0936cca1e735d310983a64dd9ac05541013a4d5fd880c2a0f831d4a03ef134277bfb4b37e989fa3e77a657a10a9c4cc6f8d1b967750d91442358817bbb5fe2a5e6228841137796f9f28d5bf48583548e71974be4f8854d738d953a8a76017a2cda01a375b484ef6cc286a4a5b72f2514a22d29bb229df40cd9b1b0000009055d3a3f63ac11fb543522f2bcfa099382d8a42ce205317d51ccba0fd3c20465664b7ebaacbd58f09eed67254a0d565461e60ef718c7c5086c95793e474c07810a99879a28619dbbf636c4ce9b989eb19357d86bbd788d304cc6a3b4ca8a2c9cd0f4d04190c9d666f7b33b2f0cb2fec1d830a39d854815dab239835ed4f7151227709ee5e177fd86acc1fd68097819f4b00000ce400000128000000901faf557d60df27116d799982c0eb24262346eeacc71c0da7086c4eb78638a79af5c7b2d8ac7c8c168d57be64e8731ee074d9b6a62b3d7f185a928617f2d1ddd9ef85f33b7a5557c0572f6c4050407020d53172866f1dc1795f05ca3c438d108a7d6708b79bc4ab7522590e4f376e7c13ec62e651193c21baf8e570f90a33d5316aa6179ef7a3c25dc353ab38bc7f65a200000090bbcb94298ab6e6e0f7429d2354763335363c2d22cf617f2f6fd5b24e9e04d8c2376f69494bed9f36e7580ad668b9de718a118a27a77eb104f56d0655cda58faf0ed58b4aaacdc8c79535fef442ad0d67ae7b885e28b5eeb61f8b1e666d92ce9841ef818e824cd5b34635b7a75b78843a5ec5a29e425111a752ad107d49defdd6956aa2cc6d08e456fe558c425444389c0000012800000090560e24b3063fafb2af8b7d188b2923c9546e5511e194d113e206e71e31c92dfeee357d175c6ae8de2e05dda1601a249db5a1babd18df2c8b1814288cb8f4b015264a2349207ddf23d57323a9dd3c1806bec586b98d8e3a05bbb259c3fa9d24cd1f60b4e6746af648b177fcc4a4f14cccfb8b6dd6aa4863d4e781dc19573475b6154f514713249c9ad583a186704a9c68000000906ece22fd5f040f715d94746bea4d7b3149ebb2ac1dee7a2f09240440cda447300edfd8167fea829990ee322caaf5882980151bf6cc1459a70710e2749c4194dffc32572d081dbff8fbcc706214db4171681c84da360f508cfd2bb7bb82c8ef73f50f5e40b19e360b7603d61ec4f68de51d56d18462042a60eeb52a47873ee6d7ed728d6d1d8783e81ee086faf3c55c9d0000012800000090dfd342e0a03090b176ff614dfbff2e66ff8ddd1e39fbdfba73190f31747619f597ba969d1deaa6f942f393bb163c772a27266308c150957cb70df175e660cf872a4d456cb040a82c0ebb98b03ed49935b502a2f513290708492dcc1f87d8442db95c03fc21cda9043da25bec7256079a75059d74d943b8cd0d7c3a6138df59d9e8a036eee06fb173e2a6a3aa7ce24e6e00000090399ef5dbdf12491f6605dc2709d502bef86d0b69a8dcac674be04a96808e7dc1b84f388d4e85719e35ab28ad07d5b373bf65a6fe2a4b685d89e20de862ec3ba2fa777cd074f4d965e34827121f82e0f8b2713a719ebb79d84001d1c9dc5ca8f24be323c15393901d31c7ecbcf4d498f96a8967e0cff09032e74094db1eed963d4aa05c85403e30d4baf56efc317de48c0000012800000090719a22b3736a09fc5ae3d090be7a467fe318de206793b66f7e47b3ac9114597fbf06c1705091d437730aaacda71bea41b9fc3c31ca694bbc42f9fb1a0d02c3ced9838ea354e40559f7799abe06f932a5dbee557d02167fd388d5f1e34029c5443a52d2618b8c7c7098770469ecb6661c95693cca053e7c013e6a9329e78a374f5ff8d88724264c6014ccbb6735eabd040000009062c0d0b15b034ef587dbab0f128840ee81405246fe1afb28203a9bb414e5c279cc46ace3ce5eeeba5fa2cc87d0e3ca0ecb59c253c5d152d8e20984c7ff1a6d218a723707f526a1799e5cb6007639897b459cc95891b4ad987e75bdac293e9862adf055507660d54e9e314dcaae88aa9ab8f0a6c000315f7e728005947dbb1153fdede88dbc543175d9e528066dc757950000012800000090706f93153ad67598ae49d8afa853045d31dddc2b6e8100b55d9d2d8914379157eeec9a66a9d3d7e3e862bc1ae2c6739900e1f5f49863b5a10ab42e7737ebf9441b1c9755242d9e1d4b21423f4a4d674db9b46e705845db570f605b969f6a894d8924e6b75125b4ba27ef89be05763dfd23467fbc9dc25a16f0df6ce22226a7e0b017abccfbcb024a6f05ad2885b8abd2000000902125e039d8a7c560353507235f0e3307b22359db717247e3f2488fff50d988bcdc582dba396a5e4ce1bbe5e6c9d36a961ff1fd51e42d1d8c73261c9f34c4ef2f20b1b980affc25b4bb4e70123b86836462f65dcb583d361529fee893736d87630990fa5212b5a13e7cbd8155bb6965e5e415183580a3cbae8022f02b2dc1134c9a795eef232d0b1a7b5eac1fc95c50d7000001280000009001d30da2c34181f712d6dff224a7536aba46d96c6c25185770cbca985aa478e0b259c618cf089489ecc8db127d27a6269e2abc7b5f22f6f9e1feabc09bdeffe9eea982b4b4e4de9e386ccbfbd73749985284e796445a5d248f0a135c2695c9157f63d65d32d71c110d45bda7ffde435a69bd7c0e6d3a1d517f6d44cf0ddabad00447af35a6310f603a8b711c299b7a2700000090d616852eca70a875e7bf22333fc8e6f3f57676ebf2bd3c93822906f9bba0b6a01a428d11381acd6a6177350ce621733337359bd79bba7449937de0fbf9fae447ad00a85e016400d7f0f4401a01aaeae7c549becaccc5cba79182871fe3161b6d38a03c1d9a64529844a49d98a6e966b36198672abc70592b205d13fb4ffe8b1ad2aa71c77ebca7e25e9a5727d25fca410000012800000090ea296472d7fb223528e8e8527997c8627f741842f385039abcaab9e542133f52c63070fe4616c395720b2d5734d4b764a35f153c52c0989ab7f82ed6c17da588581b9940fb6fdea01a947945569282006aef8c9bf49291f873b51ca495a771f03290bc78e851af883c0849507a50662394524281c61213d7c1040e9a8691517532dd47a626b09c7631abb7d57bd047b000000090929e6cf9d50a9c324e83ddc9f7e4c45b8084593f8c314e418b45dc5c850f06d55498c5b9d1679eff01e44d0d0fe0731c5b15d831584e2c96bec2c2a87a4b54366296b3d2c6ea6a550c6d6aac13cc1c440f3efc7733c9da517ea5e9946f2fa8189b79b50b847c261f93399cc02d699b6c930463782967ca8547ece9fa6d6751d3fd6e2388612779df4f5d861bdf82519d000001280000009052a2316381e4b87e894ca8ccb1e1ff0cc715190484c93dc5d38ced8eededca2f08dd71e04593b0331c184fe2a5b9615e307dd0689c345498ff267b203ac3fa8f8819edd60731bb058bed3e985eb5299bdb09dfdc047c971a0398099488cac6723b67dd94329b547b5df10bc896569a4d22fbd3216297012e641b2dbdf7511d3977e6862bf8468cdb4eca585cf8ad2cd20000009031afbf33060f96529e77557134656dbf64800a77a5323ae48bac637d5746defdca8d7fb1c5cadb3febe2657cfed18bc8ccb68f83b10083247ae470604508e448436cd838a94467c44efe1428cdf9cb5b9aaaa105f0a25cba6bfacdb40b78cea3273a98f02d1457aa8a3d70b84d8b00604b21b470a46486842c5d98f50f33e948c5accadad8871ddb91579d8a0276e9bd00000128000000902f598ff8598a2e713eb82b852b2a11d23747cecb7728a7847efd1f6a9d6711256cd2a1990fd8eff8111a6275794b3ec3c0b0fd8b2baf2027bc9bbf8ea6f9fa4ab7c76e72c8152628de7f11ddff0c9b4dd893296a038707b9188f45c2a2e7e497f728807ef15cc8d373e097e2fd117eafe4ca9892912e4ef3d5f3a19a9c60a15f291541af5fad026998c71a0dc29e440e00000090f5de76d321a5b6c0896ec3212d4d7aaa40b896df989c2db82db69bed85899db2f50974aa6e19391f62dded39b4b41f990fec8fe5129b9743464ccf72d5ee36c21c460e3f90c543cb0ece41fbfcab87bc2eb37fa647c8858e35d9f5d05175b5d847fa6849a629bba284f818e35d9fedf85f00ff1142bdcad244024950311c37d77153a13983d0a8fa9f65881d325203210000012800000090dd96bb9385388cdaeeea65993a2cd60a07613be7896c0f36714010da3326fea9c97468a5218b9cf1db9bf9cdf3be54a918bd929b37bd6011e2632cc36c24d8b994a9a2f1fe4cbfb724b76c82e71aeb3d3b59bd063228e321b3a380b4d22d667b492c68becf0f671233cf986c2ad4d8035e526a5efdd1d20c306db70142bbcb85e493c3eb19f40bb413dd81dfd15d3cd6000000905b35564e67b1c9c0a4492cfcfff048a0b559beb1d764a0e15638def7012a986d38b3015c013230772650b372161d14842f24f00ba0a48aebe8d06bd93073fadbe28f998ed268523da332a03db9750eed6558d35e38174380d98a930a9638e9e230ce88d6ddd90bead7731ad44289099f4e8f7e74144e1ce22c77ff51f40f1b908f721fdb5ee223781fc7022b8e20fea50000012800000090b778a99ba34fdeb8dc974a6c3d4ef798ef979f9c24d7cd42924f5abb2dbdacd2816c44bbbba77955d72d3bb6c67506b94eaa95b0f0a976ffa01a0947334f34ff9e30b1e30b1300d024ee2f6a2e5eba157da7bde8626212a8dadbc2a79d9e4dffb634e852ecd5798300475cd750d50994e13b4c7c0d86864f69a1b5ad6dc205e88c9409231616b9de7ecd95cc464a035e000000905ecaad4071ea34f63c7f5274cb4a336f4dd01b6b2d2ff4b22cb6e2b06d30ea5d2575da545adbfbb1c94b028e0b39cd80411d873926f2952b40a66463df544b4659b01c51f72881716ab806dc283bd1854937076d21fb716dc3a125b5d5fb24ea41afbb960b0e90ab0c8fb97e174490ab95824383aa9291fa5adfc5964ede2fefbf5a6147070941cb84abb024c6fd36ed00000ce40000012800000090816a77dd2861ab6abc85bab5a0ad19494bde13898315c2c8df5103cee389a219ecc5040df124f26cf4d6387b85f760927bc58f181ea702b7c4f095fb05d280242de916d9288a7c9443bc86ea07b85341d7c62027b86426171b3d87d923161c8b83cd038f68b95c417eb5297e03e9ce38b2fe35c05cf770ef0f7d13efd4d4b8cb326c30c3d661176b9cf33b99f6c7114300000090991967a9eadf2fe17c7694617b6970a2d9bcd127381a04c81dafab9e23cca33c470ccd326ae9fd0747d80ebb2e96bbd89fcfaef687fd886ebf398fb57dd8cc0498f477346c4aad3aeea04f1effb0ac9b3f8bb077c5fdbd5985b9ca2d8092bf643e16e96bf0c836d69afc8b486013dd04bf13a34d7ee64cd9bd41da26854903fae1a88848d2b05ac5bd897fd63c6fc29c0000012800000090ba15736f46ef5c167ab8ba5c68372af055e878d40ffe41d69e0766da43a6561254d14afd5110dcf4299122e5aeec4784e8da9564abf8e4c4455be795534766b1b8e5a503887e3baac198196dd15979190be3cccc06f93e9bbbd9f666e0e7c7b586098a904e50e56fdb2ab16ef1ad52444d8b32996354aaf0fad03fac00901e96c8f97968998639c6c743f0cab1b43244000000905d36ccb81aa0b15525c69c4ed0dcfe0fd561ccf7e4dfe12850d201b1a15b009971dc5652530dd9b5d2d63b55fe282296c42973bdff76aeab3d9fed635c3784501262203007c9577881a1acfad5cd273da74994246922adbdfd4f0a85a69f29b5e8bfd9a103476eca5405b39573f22b5bf0cef31cf35ce1b761e477707dd309c4a83e5c3058c2f684a3e9de0a71d22e4f0000012800000090cca7da7aaef650c6c03b927015b4fdf8f2e2fae5522c5ef0972368c97ecafcd62a026d9f40ac55890d54e7d555dd7a4c7454bd7d81a51b7925ad8ca4153d5fcafe0ddd8b18e6047b40fdbcdc3e4ebe73a7e1b355b70e9480a9133603c42e57a1bdffefeba01b28d358c255af8f9abd001ad4141596b3d240152608de8b3ad03c52335b4ca7478a0a3a08bab03b42fbdb00000090c836e391d5fa0d8c993129cf8197c0ca904023673426155f4bf94522b117873acec3d6b2d8dc127cbf73dfde1a54f265759a9fbc99d3235c5ad432362950785dcc5c28cff52fc6e04af694427ed5964181ced0c5019de1a305d238241a8fdbd7514b4ab980f53bbba759380d8dbe999a45e66d05ad86e7129e0313ec6f783e0d544919555fd3cf952b6809d6fc9be76f0000012800000090465ce09e0bcd6460d321220beab59a4015e23175c34105c941e35f7225ffca0912af9c173d01c7a1d763726e71b5016efd9793f504feedb4d349d6bdddfb95794702d6bb1f4aa0478fbda4e712ca51551127528597eec7a42e2e21bdfb2a7204c88fae583fa913a6362b6dcee9d900147c66974b9996e895a679d6d44f693ac5a635578a7e007d73ad3c9a4917273f6c000000900d087ec464823edab1578428b72ad7c2e7b7f7ec46efc1ffc46a403e79cd02217f84b7009bde7a78bfc857384a924eaa64d419ae65b9cfd14d9e3aff1b06ce94b25ba73e490ec983520f20a1a5d15ec2d6ee3fa169762c89e579a345c27fd31a30415c778e19f59006e7ae72fd920f29253f024ba5ab4e240c231b3f0904ee87ae9199e149ed19ce23680152d6b5bfa100000128000000900e1e0a83ca7edfe22d4407ce0882adca940eaf3da28fd8c2de2ce299a405ae597fac7a581afe50d2d3bb365724a34ab51545f59ef689b3d498c732019e44e73100874da99ddc9f7eab5472143565a0af8eefd41496ca0bee7d323bd7cad87c5189a5c084d98bd655af707e373d2475f4ed4d46dcf4d8533adae063060b5c5bae6ee4b837b245e546158833a5a461dd7c000000905ae204b4bd246e1b773a35c0dd9e2378418ac2f49699c883b3033d035bd4fa6afc9f3ef1d7b957398d0993e6ef66fb88a3d5d92f63e03c9f81a40b390fc5d365647d9193d505c160ac3bd645a783d3871057636a2d86546fabb6ef7a95da5b76f192c2d179d874a552a531554a1bedd6af02b60a5a001f0c4e04f4091f9b3539a70b11226a661f02083d11609f04feb000000128000000907de0c64c1ec668e3250130af1dd74c14ed1d2b575c6e442fb8831eceada205f55f040dfe7c98d1b813f24aec01aaf75391b9852ecf0b56b42937e7131a6cc6c5358722d7f6bec2b725a4f1c5394a24b03b84b0ef031af310385176372a3852e12b479f124da3d27ecabf9fda7d31b86ce1c086e139e51cb9e9419050a0b1ecb4f70d7637eb5ba58f91a0f93ef62d6bda00000090206ea4e903fbafc1d6263f71d22dea904742c1ec8507dd2d972183b917bdf649dcba2d0529dc2f31bea441c4bb69b017b558cd0f6929054ce782d799233e06ebf0d39289f362a6a8dd46b93cfbdbcd8efaa479ca6e4c3d51ff2dac7b502c922fa95354f6d9ab8afe32e91aa234d852ad63ff06cab78fbfee1b49d1df5ca83067339367572d3a7ad5eec0885f6f90f5620000012800000090f9744be81f7850ae91c2a4cce3f1154f7ccc0ecda71629cca83816405b696b5525b2d96661e83825d3dd218aa160243f7d652afea5da227c040b96dc6b0e2ab3173e2805dcc5befa00606e1710f88b0f9593b999e541707ee8e4de30949c7266a94073892ee8e2a4b0b1408aaa0ede8d7c7d11044dee24c3b8c1d2feda2efc962a1eeb66034d557c7e1b2edf2829da4b00000090846afc9f4b82dfe10310ead0bf499ab104437dd155955c875a1c398dc97a7b4dce9feb5a4dfadb3670c1c7cc4ac38b0a4819186b9b9418b0d614b29ee77b7dc86d4272de68c441e7fbd12ce6df8eb92fc7bc367b604e75080783e46a9062634bc8f3ebbd5ddcfd2490cd2fce178b0418236d5167335474eaed9a24ccf5eca74fd12ed5c350734fb7a7511a79d71aa6ef000001280000009045c6a543d3816e74dde0d8ef01be38b6e290f2a04aa778c485735881ef76eebea8625de34bd67011a0126453fe91ad9a9e4b3c03039de519ed42d6f70fa5fcdd99d11fa03a48407ca5fc817607fc14cd0c9f591b4425812660eb6193971fc2bf7219e90b688644d59b75f8cd71e51d0a5821d7897c855c7916633bc99e1ca69a9079f2a00d317913a9118533fb50693a000000907869aec85822ae61a89b4bce2906672ee081e29cee0aa0c0ab447d04ee6f620f466377ef3ea00bfd906772dbc6088b9bdc391ded7e97518cd6dfae7eb37eb5e10ddda4d3a480d5b89cc5f58497e46b0421b077226d162177f459587d69e4349e153d02e5bafdeb5b9a3b0fa500e8669696b63b319187c7ded452ce84329138d537c25b7fe90a48f48c6c70198817d2e30000012800000090707b32c0d9856f4ce5a5cbe92be74ad24ae54ba9d62b2a88573f61490f24081de6f78764d9f60464fad97e2679c520efa3d3f9559a390515e880f22142e9f64d88a33705f3be0a96712153b841a9fa5ff8762637a15a806d0c9d0c84dc805a49e3edf509e05590c4b8d531f2ad08d67a30b1b0b1bb2d8f51391d9f5c3f7bcc0572859f5dfe1890c412c81bddc4e9151e000000906a77358579dd11336ae6c98df29b24d26c37a1f200d1bbfdbdfc5aab14fd14b023e4cd557b3d87361faf02dd539dbaebaf288f314d557a94ac41dba0e0b36b33af7d4db550ba21410d8538196ff74369afcba9832237f6e3a7d0652ccf185afe5d47266c86fe7d337b7e38cc94f6a97160bda406ced15115b5fa460b9aeb5fc857ee76f4e974e22d9e20785ed7f5b8b00000012800000090b8141a2e25f9f7bd5df3666bbb50afb4d581d03ee0f7626be06712479fa680bcb1171ce1f26beec1f75ed0573a097847d32e64a9e9ba196f09b84b6acf8bf01d0bcf7fd13a0bac7abb87cd1843bf67bb3585fa9d262166d72462a0144d42951d8e7a14c8dbc69fc01146b4f4c85918a91b1ee4557a746a02f0accedb51e75a9da5251dc03e049bd6d884c938f9a85ee000000090b3da25bca2705df73a87c2a588bc1b0de7c222362cb7193a58d381221b19db5e88ea2e3e82df8276e74ebbb4d3ab3033c4a669a7fab615bca36b573d80d705bf2d83f452ab30e0284315707ef7732fcca38f9dd85ab717410dd9dbaed2248e6d84ddd6e23fb1e59a936eeef35a82c544923acbbb94b90448bb099696270c18b32eb2b9091f93fd13faa361d86740b17000000128000000904d9e2bda02b3215245952fcf6370aced9fa608de1161d82e72810e48fe00c0fdea268e150117c138f69bdb7c28932fcce7092b91355e45eaac5ac99b3783afd95c6e1c216d00c5eeb3057c2197731eed3afc3f0f97aa88c4f4beb8b614e1832bcceebb2ef639686a6517948803111f3406e7d1cf14b971cdcd2cf4e7392af6d75898bf092e973f838846264246eb6fbe000000908a4f8c685f9ff8f9584940ba3ebfd271464ba3a0d3e762807cdcbad1b9bf9ce31ef007c9cf29507d38a03a7d1f58133e298e62599256533b90d764aedd9b0a7ac202b8525cfe6e28927f154cb6172174ca28f0ba51a226472e7c92120f69c38c065fde43e3c49544e6eafaac74b3c5132b42d803fcd508fe127fadb194b392303785fffa0f7323eb257a51d42ea5ed1a00000ce40000012800000090df859662f0e462980330fa36679e7838fa11b87009b31e91c4871ba7197408736962e2585b9abcd153df062e1448488d64d23527be334fb78375e4450d9f4e3bb0ca90e68826c4d03b4e5aee2fe1f009dfa868881d0696610ebd5d1086665687bbf0cc9590c0d18f3db8b38c2eca2ea1c125764953281960aa004403131325eb1c4b63265e9d80b80104954299ba7799000000908034091f4c242c196dc453043dc399e11efcb8974eb1efc0beb7f7b52538b795e7b5963b8204ba4183e499ffce6e7569755b214274230b06459a4eb4c3ca24d781b6e12cf0903a5400447aba366ad6cc128f50842987fe49e1277b1d894b715614224120f00aec4d70babb55543b14c51712dbef704a85b07622f4a4d5bed3b26d4fb69cf194c9c4af636bc77270f45b00000128000000909d88d391b83c68b8e0ae8c1273cef20a2200f63443cd2d2c4267ee039848d319e87fc37422050aed6f109b1ee8b9082494a5fe48b70615297a3492703c0a0180a115336d41cfbbe73af8d73b4711fae78c1f7c566507046a2eab8256085af1b23ffdb23abde534f68d7e1dd1e08bb7f64fa081f04b28dab19637be394590f4c70fa0cde46e85fcff8aec740098d8032a0000009096beab66d26e4f4c7f0ace5c5881d7f7cbf4b3a76609680ee9387b221cedd5d0ec5cdeef0deea83ef765d868102f5d3531731045ba872d9bd243a8cb5b0b153e2c51cef1759926ea15ea5ad2c8097c788122f00c9f1ec36498f6343667c05cbadf2bb9bac9fd752e1de785eeffe79b339e47415497e87b3239661bdba3990533042888a8a6a9658a8f4a17a90ccad42a00000128000000903a8ec4b196f991da14157dd1fd76da96375a0c9df9087f9bd73b4e8cffa4aa929c43d704a3fa3d98d44af9dc5997c1d6c20f36fc8ac5fc6bb860b4a51bc5f9f312e148df8130664cb4a0785f215e33ba5204d0ac189a41de0e9519e2bce70e18b874d233b682de8a4c7d1ea52e8cd2c9ad5e723b8b03f1f068ac1ccd2eb8e4c55e93bdb2155ef76a9693aefacfc03e500000009086cd95faa9988cbcc894804a21cf7c425c178fbbecf497d93eb385e0e8cf58e7a34bbf92b86d1c1d84c33dffa02e90779919a7105a67dd1dfea5d8ec932b141e32ff839a1f486a17dca296def9f2eebcc6b66daa7a7009fd2888a762a3f54151cd7faa2c5dbdd922275fac6526250a6820b75a7288ace6be588f9d7966a40ac5c7f268063952cbe3da525f6f2236697c0000012800000090daeeec2af11545dbf5c09990b76605c1bdf6cb52b9cc6a766e31f56e84e2e52faa153c6f1f43efc0f8adaf4c8a757e1532869e27a9f6c8cfc40755f634dce270ed85d8c61a8ed21a502b1fe329bf8f22850e59b25e0b1450ee30a68137eeaafdced1e9680db651ddba81126efc4272a7eca658ab54873a8ff2ebbd5dd5685a040828330bae1c9d95eb8a4efedbe42c7c00000090013d7589150781f5b06e64ef6192fb368f1153341a015d2a8ef93bfb0fc916f5d445e52dab235dbaceece05b2705e5b927db862f7e866b2a6ad4f565ca53680d18ab29198ed8a876bce93e222bc29f5f80714fbe35f31bca179c1c77851eda9c21c96d6361f76b2f994425182e28bd8dd95f08c1a25246452d6994d0a04c6ae6d137311cd4283b27a9fad906842f4bb0000001280000009062081ec2feca512ef08b4f4b25023fb2c66500d0d121d637e9f2a0193f8028a7ebead5957be2ef765d1163ef4cf2545747481972179ccb34fc981da12e9e614d27326d7a2c2a6f29937e19c82fb48f1408a2e4f48dca8e22e1dbdc51933f0a1b2b4422ec7c2c2dbddecd7e4dd57273e5544436e2c66582bd7d93b8a76072de407eef094691b3abce63bcb04c2ddbf4f500000090389d2b355b2db69bf527026a7ac54da0c9cd68d44390b87ff6e540428345605b05160c75489cecd6a46a889bbbbb57cec55ddf6510449edfa8d0bd2e0b301ac37710589c80ff3a54af55a5b0c81a0e1a8843a4ccad816784225494bddfa57d168e857773f0c368955c3b31e63107ce7c42f6ee7e71540cf1906d800a79b995785e4a878934cc2c139c7fe3b25f6358cd0000012800000090ce782a80935bcc1a6e6c256c5a5e02d912d6df5d547a5d7bea5ad8961a24cf958c3031f76041956058db50d84fc8358b78e946a439d4559320cc965d8d31ae946d876194de0f0ea72ee9c436134343d2042fbadc05e306e637df0e8c83bbfe0d572a95c05181f557e90625ae86352d46517b2daa38554db65e5ec112500b30a79b8f433245d8d475db9d0ef1dcddd0830000009047b143a8865e5038f942f2203d6035daab83fc069e99736da50e4116df719aa0db95b736e2008d4c640ea3f3d4fd1b5cd177d184d3d9277787b2fc8d6bb64ac74b65318fe55db3f166e2e30948e5b50e36e8534f13e6b4c83746e84b50a46212a5dc1e54a42f19b6365b9461a366e2f33375d0c601275dd899e1cda62e5e23ae46416566c67a2810793468e01c1b04500000012800000090901937e75418b9e45cc2db44e4585c8bd8c4942677d1f18c857fd9f103bd5e25d38ae1055302626f49bcb63f0eeb6a014d1c8ea889178671c84161620fa5f245b4aa33c290bce2c3fdbed138110a45448681c14687f7ec59da30a0b11d01ed7d1ab505f1b4728e1f0ec188d7abc20aedccc14110b4d0f6b53ba1cb45c81dcfafe49704edad1db9aa5f84896335136ef0000000900f276ba197b3c9ff71a53ff61273675a07e6c8852983b7ba27be8a217ae30c99b0377d71836056b4baafce9a3c35170034ec69fe28944e8de19b03dd724a28382b1115b183a3cc012297daaa38fe81f7fe1180bd2cf7a89e09bccc351cf6aca55276d387727b2fac554dbe1e24d234513f89c8fc2735972fd12c12f6801cb1dd971039811a0f777cc54ea4852b88d84b0000012800000090f6c1c0b504c152f0b4cd5b9b52084aa417f75496225a656b4e3b3a3172307947b29250abe24c5155f8aa601d0debf4a520058b3dcca577d0760f2d9683f9ff8629f9efa31240a30ab5cc1527a9e8a355a5590d5acb7314de66dc1800232fe7152b40cb44acdacf9f129912decd9115f797b06787584e6197fd24fda3050f5252d3f625731774f30a018e58d3c74f0eeb00000090970ed3a2cd99fa2a04a2291e938db4a10fba2ea9af2ca053b1e90c54c7a467cc3eb225842c6fe9cd60fc357b04be4c6b8f55712a9f6cd4742e6ba6d939b4c627e25ac93a2ecb9637660955eca76673e0f8f8d841f1195403be2c3ff682946cfe34e4900ce6e15737480eb3612155aed20555bcdb0b845b599ed9d11461fe4a7dea8a2d941a02d3036de9fae4c3252b930000012800000090d61045c6be33d4e727ff45e95a63994e42ace19ccd06ca0b58ad6702f9e7e75a5f11d6394fe9f55c35d3cab5964b89958eb18bdfe194d5489b6a90f9b2efb0c8949a67661d8fb8ac6ac5e02571242379818c7d6eeb034fce0071d4eb576e7aa1bf17ad93a7c84344fcfd8b5ff17b09eb61d93e6841cf4591ac0c4337fccc42c7b24a72eb5055453e6a348b1d9828df70000000904411a31aa46d112c0d3c92512d67ccfc35f48dc19a25ffad9e18a0ece6ae015f33504cb1d4ca0300c9cabad38a38fe06c50583c5623ce42e074cbd16e417cdc71fed50dd6f51dd7fd38580cee5a7b2906f5d7e7a0e23bf3bd0c9233f307b312c2e864388ff1238c0a2fd870e348181f11ff1b6447f3d923ca5047eb54710555999281f490a9b9fca40ce4a280ff8c4940000012800000090a55c92e71af275434e59e4285d7678525ff24933ab0d08c152ab30b2ddb61afa52c57978b2a66ee2df1147fcca0dc3fadadf1a9d91b988ec5a0a0741fbff401c12fd86019108e8ef81f501fe0eca80cdfc7cbfe613debef4e908a84d885835adbf52e2937aadc4a22ae67cd4caf0130dfc647f8baad0e0995890731bad78c52187b7a4b0971696a26c6b5ff6f6d59209000000908e3e553b4b52c252d0995482c1d792c28786df240545fc528bd2cb1ca2d5c49e5bcc835ec7672b2d952bb37bee33d2b0cbafb2c994d42126ace2c9ea5a698ba48e6dc1ace56897246342f7fe7fa4be264e9375074275655f68d2e4aa3f8cddc5735447596d4ddb46dfc1ee419f30dc275659d80eb7540cf6b3bcea68bf8ce4a5edadfc83e4daeb543d1fca493b2c12620000012800000090ecf2f4bf570fccea92afaef1b751726238d64c14e225bc0bd0327e7d2625a3dea643524586a30c47c2d6a37144a012db25febaabd2a2d7103ec7e14637820dd4add4bbeda39020b0aef596f4d6b175cd9ea685590e966c0a523d39c69e0e96e4574d7ed49fe604dbcb7533ad1e421693255c967179bdd82dd9608cdad57fae40fea3b2a10bc43b0017d92bc164433b5f000000907ae74c142200367e643adacf1f2eaf162ee4a92c08bc32382dd3a4713d50886e44acd3dc465271116fed5fdcf03491306eeb1b2ec5360af9df5249b29630a233d852bb7ead6e9e726fa78ebac2171c9bc31fbd06a53a5d0b35e340e21a49c3412577ef5642e54cc9490f8eb65f8959075be6deda8eb0dcc55200263fc10116b2263df6928624ccf43ed58078a7252fba"; + hex"0000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020efbe2c7b675f26ab71689279908bbab33a6963e7e0dcb80e4c46583d094113000000002adc67712c2f7afc4e827551236adb46a693d572fbb29f3993dbedbef8d2d87d0000002027378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000002b72136df9bc7dc9cbfe6b84ec743e8e1d73dd93aecfa79f18afb86be977d3eb27378c30a97c642a3b78bd34c54beac15a4dadcd7a3378e66d2384c485fda541000000000103babeb39cf7cb3fd320ec225367ac5e834aaec3e7b48bb3239d0da39fa4a200000001235f4e41a2440aa28f9ac14e7eed447ddd2e539179cee4c0941e6e408d2443e50000004026f32989eb2870f2ed00774f54a82e8266fc2a2b3392b64e8199aacac71aabea000000600b6abbab461cfb072b267bfc1ecf8dc3c943736341baf11c5c829e345c49b5090000000429c0d0effa4242b8d2e372cfcdfa8bb57160715fa3640a3404a9bba93725a1072fbbd267a1c9b23b3ac1609b2c2a7961a0338c56d62607d5f8d6b6a29e7fe4cb000000102d81b3e2140328e322ad47f083bfb89d61aa26a26795d34e7442006f939663b300000002000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000012100000000000000000000000000000000000000000000000000000000000001220000000000000000000000000000000000000000000000000000000000000123000000000000000000000000000000000000000000000000000000000000012400000000000000000000000000000000000000000000000000000000000001250000000000000000000000000000000000000000000000000000000000000126000000000000000000000000000000000000000000000000000000000000012700000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000129000000000000000000000000000000000000000000000000000000000000012a000000000000000000000000000000000000000000000000000000000000012b000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000012d000000000000000000000000000000000000000000000000000000000000012e000000000000000000000000000000000000000000000000000000000000012f0000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f000000400000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e0000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000052a0000000000000000000000000000000000000000000000000000000000000521000000000000000000000000000000000000000000000000000000000000052b0000000000000000000000000000000000000000000000000000000000000522000000000000000000000000000000000000000000000000000000000000052c0000000000000000000000000000000000000000000000000000000000000523000000000000000000000000000000000000000000000000000000000000052d0000000000000000000000000000000000000000000000000000000000000524000000000000000000000000000000000000000000000000000000000000052e0000000000000000000000000000000000000000000000000000000000000525000000000000000000000000000000000000000000000000000000000000052f00000000000000000000000000000000000000000000000000000000000005260000000000000000000000000000000000000000000000000000000000000530000000000000000000000000000000000000000000000000000000000000052700000000000000000000000000000000000000000000000000000000000005310000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005660000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000056700000000000000000000000000000000000000000000000000000000000005710000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000058600000000000000000000000000000000000000000000000000000000000005900000000000000000000000000000000000000000000000000000000000000587000000000000000000000000000000000000000000000000000000000000059100000008000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000003210000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000361000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003810000000426fcb9639d15aabe6d792e23ab12fb9633046d4be6911a60d64471d7560d3f6809143b7d4943a3485115d37e7596938a16c91b6055f3837640d8c36b8303bb3c06fb5fb553496e5e0b48834087e036acf99d6d935dc2ebf43c82788cb5ed1c6a2f4bd77ac2bb5474d48c2856135d18168cd6f69f77143c60b3cc370319419dac0000000000000000000000000000000000000000000000000000000000001020212121212121212121212121212121212121212100000000000000000000000000000000000000000000000000000000000010404141414141414141414141414141414141414141000000000000000000000000000000000000000000000000000000000000106061616161616161616161616161616161616161610000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc00000090b1c43c1dd10fa62d46ac721c5529068d286a18a86e22787da7a222925e32a3148915e9b0ed2f8793823e9b4fc52cddfda38739e4a23cbae77fd06d498b9b8e6ea0911e8e23b97a17da9fa3777775672dd21198963bc0bbf6667d10365dd77172004b20053ff5fa88f214c7cfbb1501c5aa7c9bd36a08bcd318a70f71ef4a5837863bcc1e9a539584952bc17cb270e2d9000000907686f00e315ea807d51ecea805379caef8781be53347315fc9510f3e9db44f3e65862c9d964b0007dab956272d11e50d1338bcbaac47886108b376f34d207aa5e94ae1f2adbd06d15590d0cb7061bb79b839a791f90fdfef054e878748fad2123fbb481f7e1d9cfdab406f5e8093badb645fa2cb49203e1bf68f945ca21f5a03027dfe828e99ea4b6cf8ae2daae54bcf000000905510d0f861d5cd19326c399727f453486bdc7b85202ecd41f5fef58b5078e887ec5b91f4d39ddbe24e2233747a1e65e6737b58c0850e148f7e92cb21e947efb518882acf619244aca195b5dd44fe507cf4f7b1aa9386b7904b01769ffa8211b3ea6ab32f2c85a4d03c6266632b602c655f1dc01662d283f3fb700a734f14c580bfc7a5d2228ff1a4c7761708d9322f2e000001bc00000090c6d6caffce822bbedfa8b303833ce3bb9b0b3a79bfbfcbfd3b563f02298c592c4c7216a38ea06d6e9a1a75b8ce59730cc56c8488246b4d5261647058936277ea7ca9ec6df4bfaab432e580fb3ee6ad005ae36548d2fb1e7edc2f1228431bb1acc1e3210b4f8d5b68647dbee0bb7924fe2727a6669cfc46cb82fcdc1c77e3a0de61eb3f0a7da43811a067fcc07a5303300000009014237a82b5c531c5b22ebeb4f7af578d7998537fef0b53ee2fd725d07550da956a9ea3ffbdd09144a539b5fe593a138d39e93551ff290cc899b250940749ec14f745945d067438975a090af541be7ca68c7acbec35e623263cabd630ebd11d6caeefaa085a44d44810e70f8d6a631a8207ea4aff253f47613ca512bf04b63bad9dcc861f61d81ed0d7a88fe0747c6027000000908e8e062b17d6f040bf583520ad0d92e257880d51cd470ca10fd94d0e03815062d26f1169b1ebaaf9b5dde8a5638abb39043bd0e31d0939415ed88682e4b1d0e434f879f11542360439caf4db74632afce8378f2faf1316e528cf3a64d7e7e3a5fcf322938c266d48181fb71b956c6f66353469056cf26e8fd84c3ae60f72ffcf1f9deb3363b93f5ba1dda798c93f4ff5000001bc000000908cfb998afce6a15aa54c86f27370d5fa09e60944ffd9ba0cad5da227e2df3e678226f78094eac382cd0cfa9fa7dadf181c190002fde911048c253e2f05e8267af3129dd8be984d00e9ef152762ef161f93fc72ef1ac9bd0de640f6930a88f1fcfa9ad5bf5032505cb5c90ad5a7b22cd0b2c8d9af4f224955b28bed5900a852c9418d94f1a1e968afcae8d489895996a800000090579b53b18d0bd8e4db71db680804471f263423a4c57a5807696dae3a7d751e6dd8c1340ed4e0bb63e6e45b1fa36519d89f164f4ffaa41d391d4adeee0d02273595d6cfd41d0869677ddfe43cf8d4fc6e711d983bf9064485083edf3dfac78ceddd10474c1e07234f04ecbc50cb1bac7c30248d5bd9efae2bd72baad5d108f98de87b6ec6414d7581031cca18a7a1f88d000000903df50823b273945486cac84eae73e266121418fc5756bfc8ea6809d69410c76daee250d34b31a846e74ed1e9b87ad3dcfe92600d5bf24d620319554a8c67b0c2a76816d6bbd0ad08d83a89b121a4209e751b3e1d2ab0ad916fa673ab94ae1ce7c5367d77a7e5094a96e8c6d85575e34ebcf5ccddded1e82e329b0f5d0606f0010754789ee4e8be98adc2578c242d3eb2000001bc00000090fb7cd18168f47d0ddf433e52f0ea9f4f1d391b476226feae60b6258e7e9203983154c17120ef162fb83d858ed5d89acfb48b5b42ceeaf4cc45a3a2774814a2bc080b2a5d139aa7d33d54730e7c6b72b8c81475d99e430e914d609adba55d572d9fd9a2d0d3b55765aa106faac79fc50ade6e09d2fb18631a6e5028dd30a03fd78756608d3390e38358345734691e130400000090f354980488624491d43905213b4f502c0e0cf43c88bc840c0cbf1f103e74c47c3bd8bebf1453aee92c4ea82615fb9f4a50aad10dc69dabdb8ec7c8e518f55628f48a22867302d0aedbe01330ef940b87fcbe1522609073955a1f4e53b580d9fb5947abd430f3ada138bd38bfe014bf017d257cc3cdae7ad84837ad0aac1b8fc85d7f619247c58c4b84d96bb47d61447d000000909a34e935d1b48a64b74a4b7a130471c3197ca84342093096b7d7a5e57bf4aa9d89f286b4a27619861589c15f9ff4ac6277093e2bdb8f1418ce45c88b1b94d69c8fa5194ad9bbcf79de7ae6596d0f81fd1549667d7a97d3ad96e21fa687964b2d29ea50b7c0fff8bed8e3f5df7c0b7528130bc9443be97e2cd56bfae66b9f471572223673a7027b9df9c8275b7bf3cdcc000001bc0000009048deb9e0401c49c61deeea50914ae71c267a5056dcce4406b02478aead4616303a6d36685b3d23d995d2a3c31dfcd58a4925ae67251b98bc7a08521bbc80b850b7c268e8b796d8e4436e156fd1d9f906c508132999f3928da46a5829c3ef8636ce949c5ea263c6e0a23427bea71a8fe5cc35344d0e9d61b2891de94fd71fe97e23fdd6a1f28937cd6a4efa1e3282614900000090ef21002e4193e387593866f9568792747b9dc5353764bb3cfc9691068cd7ec63509277384c3e12130782690775bfd7598b30130d4797603c432bc9b5bea6a27f0c69b05374e731c220ff281450b2d4e126716e2bee5436d160b2f6731bf35c900639a6d7e65330b75439d3c7c6245f876e2950cc7fa970ad9ff16ebb6a0898525dbff3e00564cd209f260c2bc4f694910000009011f59e99b692f90fb8cb1a1724ea0cc8585330f95afbc3393e707c4d2a7703cd6ab9d975e56c7c1d10863b3b139958722f4af95cfda6159bca44175d9b5c6ac481caa2a86c6770abb6d6925a00213cea8455e87213b575da93ca24ee48e627145db559c962519911b1afb7a47af5ba0460a4a97ba00bd4bfe9f52f194c5e8ecbf6427cc4560227224f38c07b7e59a4ba000001bc00000090375f55f2a7cb6057626722e28363fabd45f30ea1babf12ffe3184303eb5788010d104812cc4db5d7d18114007d9f4314e64fd02acba6c5bbf83ccf2f35446b21a1e7955c55e6859fefe6f71f2e16ddf4ec1ed3c5178daf2c9e5613c3e9aae3201946fcdbeb0e8719b01a18a25905cca216f034c4f94ace0ee4bcfb8bf0b40ff0cdcd8f1238384e28df63c1ba65f91b540000009025e941529ddcb4ac5e93de566fac91cad1baa6dae9cda86477c95ce97c7fa81b6a3db36b657711ea0a1a7669a87ebb593bae554b66a058af1a21ecf1b2c5aecfa191f54733a32480d29a1ba026b6fc90b0ee4e718738ee68c2b34e774116f045f1138ed8c99ba88b98affe4806efa98b32435d368c6f34dde1fa09715624ac0611faf13adc4a8a6eef04646897ce61af00000090005b88cd11607a66bd9fdf06b8023ae16072df1d1a7d223a6d7d37049dbdd417043e11e1736c01af9098b6e30ae6e59e1882deae1521bd41b011c3f18fbb569d20e9af66508f743059537843cd1088ca526dc1f174a8018e467dc19af5cfb12d20d09664ecfafa7b1acf78c1396f0dd20f606f27813b004b81f347c313fcc77ceb5fc33758c4042e3bba26e6b4c9ac79000001bc0000009011e23f2328a3cdcb9652a6dc95eca90584fe46f92b70362a33f8374faf6c26f54650df91601eaf32e44ef840c5c3e0e5d02e51198bd57920a5c8b22aa96288c430ca5c462b8aab462c9222c36adb884bf5149978707ef563dad2ab59041332b569c79cf44e915c5aca22b75ae7218e996bc17d8409b0cfe5ea948fa2f95162b00069e3046acb65d5e245756709742b6f00000090193875fe2d757b5c35f529652a27b43f96d9866935e92806baa042413da52f6785a97ffa06741bf7f3a52031e8f67bc4ce40528f304d1e9ef6efa19575100fbe49f2147d7e0ec69f0f232c239fcce61a50addc45875278d5ac24e389521fca0c6a49eda5f3ca7f5cc7f1f9fad15332c9e6548f77cc0fbafb72413f6af7a44365b67dcef769105d6fb99e6acfcb8ec3d80000009060f4380337b2cf5647dc40b9d4d198ab5c8ce6317e4ca71b6b120612539ddc0de66f6b5a42257146ce190103849efa4dbc68903f1a32164258c81ce43caf8b53aa73519fc442f2f93cb9494fa19ba62817d116704233bce8a761a13221cfbead9bba235b6567045072eda0f4da79a5abdc640ca003cc218d3ad51fb6f5699ac03207e37e457d997288c90e043a4b49e1000001bc0000009027ec222ad55c14e1b629cba9e7b024ad8b045150f409c624f1b4b5772994e2f847ed4c6fc9ba0b887fdb370dfab6bc9a029a882d513e848d0a000e6a21d392081159e910e1824ca8336326c6fd32e62ee4fb91d3bcd1ea95316ccfd428235da330cf4e74853790219bc1d868b696ce9f289d416dd11908e410c00a7a2b0ae38ac6aee983af156f7ab445944bf3c78e8b00000090c7b511f4186d7293c83edbc937e81e2068ccb3253c10908e1dbb877098d3312ff806bf187b9521032fc91802a275c546310d3ede01710cadb7fef5c5ca3f188c900120b753a91fe69a4bd6ee2c39bed71c7ca4d6d5718ca20a3c83795545b169608e6248ef7b16e892c08bdfb2e261f85863b80f65540b1a68f1fd872fd2a9012f645a9177f656ab4bf297b5340983a500000090acba85789c0bd050a43cbd36f5b1c1e427f898fcee8c905e59e58b0218f7f652f7f947cfb947b52336439ec95ff4472481c871ca400dca0b90bd36ca63cc72e884736cae8a5ea449e383aab49c4cd6fab9c185f5b03b2bb9995436b1736674b1a1f8a9f4eb1102ad1fc406db1efa35e57d04cb2b69521ca599c548a3545805d44835b5dfde8b9039207128eba0be564d00000e00000001bc000000905bd444a8cba9ec75f404b87314bfd6020f57de5ccbe53d5fc09d4ab7d0523bad932cc48f4547c19d6fb6e5dfd506051992fcaf21fdfda48c0cbc1bac1a0db7bec9bebf7c40350a275594cdb6c0f5c94478f2d8ddb378ee5553051ba1014b4ef11c72588a4add965476d0da2f6d92e8c0745301d16b48600e1818114f9b02d82c8fe9ea5faf6a6033431267feb6788e3800000090c2cbadc76ca5c5af8dcf7288d4ef510b6114c120dfc23294df68240116291024a307f69ef01a033c11adac13172bbcbd83499538f279d4e6979184bdb3e9a71dce200df699cad843448318fc765621c6e762e8115488774101f7e3fab9e5c3119cea5b3c016fa19e2fd7686d7ab0bae4a036236ffb0cd9a1de8adeb1b624e150e917033d9a6aaaf2a93533d70007bdfc00000090328f9d32f22edfebdb68b5243666e71fe47a0739ad54826a2c9022076c8ca9f6e33deb528608d088e3e1d9a4222f1155caad9f3c4411bd779fe4e48a416cd6b30dd4dc5af43781989d1677d3c9422ee5687fef2d3f2de01d28800086c3cdddd4fab892dfc81ebdc8538f69c21137b4edb06e3b57ae6e75b684510c05225cfaf9e3ca6523fa821c3769d41a21fde5552e000001bc00000090fcbe73df4cbe4ce643bbee6919bf8ce36bb0083e91ddf443c4ee83374ceb33a79ff29e7155da16a7e1a4cc387b97981d6c38ca137a53c59b9e953d528df5e966da7e28dd7aa35b22cd75f86a920715f03dca7ef0f24bcb605e4be105a9b5d5f3fbe87f5d8bc8536011782da77732815fd863e08348fe2eb2c550f8bec4410d3850a79fd9cd2e37a1d244ba3184a99d2800000090859704b25ed494302d05adc7012684828a21a45b8aeb93df0a2d1ea91e312d66a2832a040bd2bcbbebaae7cb9dd3aa225d094a55977583142576a401ad449ed0593e7d9fd1cbc37ce036af276f565a038b63875d8090ccff076ac7495b4ff9631e86a6a0cdfa74e2f677750b1a1c280fb6ee6ff516163491aa744aad3a1c487cdab16dfdaec960b66ca812785ccf1f2a000000905726064d12c28f46856076461dd95fef270926eacd55074d64c998310a4798b699e8c864d863fa24c164036b379429ba81e7b9b52afda13d16cfcb231ff6e36812b16064122a163cd7bf935ca76ed6e275cd0e355aa41880a54c6f4fc9089e66837f477a5a0dda745ac9196f94fc8e1ec36eb8ea932eb6b4d737d6d005d0b8e3f299a2c02ac881de574900c89eea6339000001bc00000090bfee39eff3bae13492bf9ce976a56c09f166dbcd46ece93ab636914d02a7392596a2593c973fc5329d8dd03aed494ce37ba3a9a8d44108be1ff4238c414f2d8b9de63fc3adbe43edfc0bfcd0b2c85b9752eb49a51f36b995d20a3f7d80b35c30097ccc4fbe50cc4bf627e51771b5abcd43806c5d9dbce141c8c002bd56ea73d3cdfb523d1b6195ecdab57b427096227b000000900296ad69087cf87ef862839d9581a851861d600fa3e1e0dd4eea3cbebb18b868000356deed62fc7f1645f1a0b088aa169164b7f93b1ebd2e82485a677b57b68166d7896b4c65fb4808eceecca609f95546159f1d2b4ebf30862f18673f1d0248025bac6c928438e32c3b087abe01b8e827c811178866b40b4e3c14f8d1b6e89949ba757df7d18c21dd7a71fc5d4efe13000000900d33920df26da7d1d6b36377566e86e40a8015ecf91f88630ed533afafbf02a9aae149987f96ebb264eb582b1fb1aef2dbcaccc9efd52801c7d4d091b4c4a6e1378ddadfee155b09597a2ab3b1901780f0e606f6e1ffb02decffbc61f6ed141c282122b58b6ebd5807f3005d365eca15d2ce2c6ee04e53f0279af43b59017f3a5521ac893649bbf5e44cb9831879a7be000001bc00000090cc65151f7ad0a4bf1b0355424b24cc6eedba544cd71860bdd03a6855fc8242a77f21ccd3ee05d414c7cc8c8ac06108cb6102327bdb2a50dba83060c70b6cbcb31c817da3bade2a008761a0055374adbb54e0b549fe8ef201b83064196cd04bc0df1500b86ba47caf85b8bf64c01e93f27290ee8f0cfb6a5a53d9e6e2e092642df9d33d21139cceda22b76cfcdc0bbd3900000090378d2ba4c3e4b6d7f41c3e40cf644800141153017fb22ed45e0afc3f3f33f26da0a42071f04441b98a1af1bc41fc67f46ec17497f1ae5e10850c11452a284825a40d124958218ed6ab40f0babea0a827dba3a9e6efe5a9ebabbe59a1a3d64cad6ff4d706d2cad4c3f18964bc3afa143e8eff0b6469324ab2f417a4c1508b917a3e87c2f826a2ae81964f3a2c5af72d81000000906cbd3d7a20ae20388791281bbf4e67beaa96f258182d43044da9f1ebd6887b1b72da20bf46b67a23096b3f8509177b9c8dc77556cdbcc916b1ed02737ce1a8b34d3e74058494773916a1d1ab7f6658b09bf396ed9a2e70ec021178f9078dd57ca020c7a36b4e75548658ac642118f8c74062ad1169c47c2ff445433a50ff23623bae3a52b5a614fab34d12eaa314bb26000001bc000000906ea8321846cadbbbd83f29e437e2f68ed651e32a80b91c23fa9aff1116e3f7d084d238933ee634c640a369880b6eb7e1df8dd518e82546a53657a7aaf8f8e7ee8fdabb094a22378a14da612310e7dd6502aa80f268fd9bc57345c0d62c8b5b3dbd20c652445f67444074c186de015ef73221e6e865007e72082b14e9a6b03f76f5eeadfcbb705c1b03d6b983e8be0a28000000905219224f11bb74c2905c836b29a468148d41fe096400b1c4a5622c876d4fad2c161a13fbadb299cb0274f3ebb24f19f994a0fc82dff8523587cd1860b97bdf73a8a389a8b933a4711ab03bd77b28caabfdcfd2ab79cc27fe4e347d62b7acc92d385c206e4964e6252c4dffe60cc0bc6d9d0e265237941efe40116c02ed8dfa3805a63b6c998936e0a6e3d220bad3ee1300000090d07856ff8c6054302a935ee722eaf3cb1b9ec87e1c99ec4d5f05b82035d25abd2919636567dff299030db4df879a1e3da982747382e803240281fd86455d3e0ccec709c94a3226ad404ba79d6548a729a9c9ad21e1070e32154c4bb5665ea38ba1d7cf28598b3c115d50283af0a9f83da97a6571fabad795c7da119c7332ce25f686ad84f40b3ef6b08328bdb8e4733e000001bc00000090d3f985d89d0e61756a2139c09fd5502a712bf54663733ddf69cb1d3101d85c63924c625b12cd3bd36ada36864bc4443899d3c0735a5c2a29f86e8c8673952bd937cc39a6101ea05ea7e29d5ca473c8c05e3d3e37a9cb63fe19a38b2143155a2412b7feb1edd44b9686dc1179e04157e5965199f3d597190cc205e17333c995c32d5875f222e11759ccaca03613f713410000009094984b569bb94bad9099f29b90ef394dd454e2af7e3407a242f48bd08cd3fc111f49fbfc8093676a0a0f958a44b532e771e676fbcec59a5d965a98681e5460260ccd9ff9afa3638d92e4405d1f26776855ed9458d250c2854550f2e7bc3b2a7b1d2e49b3f08100ce724b420bd2f3de6a8078622e00fc4616bbf50da777426ddb2c47dc704cfcd6deb695156ca4a60e8000000090beee2b163d5d4a655689e8b0c30c8510d5c9e0fc68df0c94e9fa90d88a01d433523495024f2bf686d72323d34d8559aaacc1806e7bcb45b51cf697e3dce63ea0443807ae95619d8cbecc598e60b40ea544e93bb21b8d5862942774ebcf4ab1f56f42db3b75e3bcdc61e2c601b73286789f49ffd8b16788ce30dcd556aa35cbf32e1f628ef27cda313b1b779afa78372b000001bc00000090ca71834083c2c4a2c84e8192dec2d6f869bb192cbf4abd9a7f4fcd832d27875153abb7cc2da5eb8ccb6915b96a294cce6e99ba7632ef6757d7008b0bf0958d11e1bd49796e191a0c0c8417b4923da5c0779aaaed17ad3b4fad14065fd4203d73375e945b7792260c28893e89e3474970f80a2d5ea0f524f3efb5ffa8c2b895cbd32c5a77595c55d0b02133b97519f24600000090de3733625aa8d0451bbf8ceb0be90358fddd5863068f18505e05f9620da1bff7285b56740cf001d503bc05ff9e47c0769b45c5066c9f521cba91852d64db3748354ab1e9d12dac0284d0b63545918f00f4f1bc14c98760b9f02a666ae4721eb7b99254922bdc980ee12674075da138d68b385df945e3695c337af5ca590026d81bc5170366d9e1ee6e1a6b964782859a00000090b46b4bc458ff824b02d652b9e0e7d785589131d3359e69893c85b1606bf776de78b58044d0beb789dfaeb3104c8321ea76369c5db074097f126f8b0078dffd3ce005eb18a09cf43ac4f6f1f38dd58d1bdb1dd0dae627b5528d10adee3e1a822ca5c1aa8489c0f0e8ecdec41ad817ee12d534a241f7a6a13bb0ebe6a0e6d6349939669d5bdb654bb8f69d111a941af156000001bc0000009047099475fc1633753f715412724344352f1e4e82ce39b92b0d12b252413edde0e7c95f8b3b5ebbde7a57ba3da250bf51b2cc9c8c3f29e8b50d29ea0f31015879ca8bd47f6e092955c3c45f028b68350001831603834529b9e9625fee1b2a212e006b853c3ea4fc9124da15fd610a40aecc48728f1be8e8db55a32b26de66d1790e404c95710c76baeba3e5912a53768e00000090bcabda0ca6aea4f9d32bd42a74401684c5f46a968e48f394fb82b06ed1a36b0024f41ed47e948ddd2f96f0f9e2df0e7e61f67440a2b6e41c59059f2f563f27b21b4a7960c6f2238faf8d3bae1b31c1ed8974932b1a4ecec12e11772265bd9ded7b6751cdb0ace6d0db1055121a81f8f39b86d4e265c2bd82aa63fa52135b18c7089105d261e8a7147712b67a4f41cdcb00000090e02c17c4eacd5cab85df9268d835e0b3c1210fb114be217c839a764f1ac161bbdc2774a4fad9803a4c99315afc07b84c3796c7420f48c4a69ae5cbb3fd637a34ffb4ad7828fb81961d3bfcf6f52530d0b53f35adc9f88c96612123a23a011adb9c2b8e9acb53ee608ff642307de4ae094c859489acfe3c1d85119c4a786a1af5a3efafe2685aa4747cc63fdc84e9146500000e00000001bc00000090538a0441399b0eb4b37558ecf90d9bf9d67db754fda7d60fc3deb3c4e767bcc087f8c11ee7ee94353bb1a943dc8d148f97c3172f61121fab91a333f97129592b891c45de2c185d57c1548022605fed55bf47dbbe5470fbb7fdebc757800c35880c5ae70e372cc46272caceb0003fd6a46126a790e8d65baf954669f71bd817bc0e8c9b36e735963afcd3256ef4505b2400000090bcabc8093838df793a13c3cf44a1a70fff0569e2b1356a210fd55913b23068d1a98ea92dd3df55bd2755d97b09887edf8860b310a675eeec0ac1869aae6289c3e49560b8f4eb583bf40f6e21654a6b80e7af429fc7f038d95ecffba457ed949bbb7995158b2061f986643795c68b7967facb2cd028641daedf89779cf3fdfc90d12865fb851a5cf4eeabc7911d3d8f4a000000901f9dadab38f2ad1c8c0bf1b02c9bf4d584069a3b54a92ce07141c19e7bc975ea943719224e6f93fe69dfd882b6ecc94ec80a1da4189443cb04636e92f09f88adacea1ba91c31cfb9b7474ff1d58d63652f522adf727c82127393617c4b1530d8c961d41e378e3f5f266efc1bb0b7455d75148d6c79f98c01a5d5dafd3ba03f2639b4b45678ef60587bea187af77a11bb000001bc000000903442c44f4115857ef498fa03b90666e4b043398d13f0c2523a31c4ad92bebb6b6a3826f7f9158e1610939d54d9a3a041aa38d1192bf0dc797710a83799f48e470deeca42989c44b7622c4b99ad4922673f9ca98815da551a3d3e882643bdfb9cf0987abc462b859b433c1c7e1c9e96b4b4961302654f31326b8c6ab0b751d6f267c2adcad54b9058cc6fd5e9c8b70cd4000000906d69f738576233ec2328d6bd1ee76e6b40dab296dc3b214e02c6418e007ea20470acd84bd70c7ba5c24cb4360c8641f399a5b928077b3d11ceaaa73c11f7f37bd246208926b9c1b0e55abe71413511c4d0f04e811246a32542f7df6ac2a53254f1fcb9dd9716d85697cfe7afb069c65e9c03247da7195e9d39cc81f3dbc1a5b78e989c9e6d8956376e65a68b15be17340000009076c552a5d849a23c028a8df9458c56ef39d43d4e88b83cc86a7c5f93937b9c4db4f58496390d315c983284b9b68b5a546ec81ad4276d487ad1327ceb7b1f028887b1a7dd91fc6df07232e8371d78770a860f4890bef4d66018bc2dd5cf19c19da34b5efceb81804574f18011c9d52373d6d4996811bfa4ac2f947d90f5dcff96c9a8a4a407950c1de8c24bfff838971c000001bc0000009020c2f2ce0288f6e482241ead06ee7eb7b9f7d75f81c08b0da7b8d74fcf71c226add5b6db17fc64cdebd52bace97d20a655a05db3e73cfe16a0b88f11c049bb4a3b84ba4b50ccd39a9bde94edda541f5b44fda6a243468e74b9207fcd9d0385417891fe89f8c98a7ff77709e225c2039b6669e9879b5f595f52b194051ffa1a28f79973c4766e14da62a94b96483ac44200000090899898e94b501a777a9c12fb71a41e7697903ee2467966a5fe4ebb3024763e3d1ec29fee30c778929cb1a8a7265bd94d2dc67b1f6f6c8fea74ec2218ebcfaafb86f31426be18238178d23a165e671a30f3cb1b583f31555cb2be7e939aaa3a5b730c719fc73baccb83f69c07b26787d0107c7576dddc9dbd9d5fc7d0877f5150b27379c1d0b957180db2f528caadbc870000009057a22904be7a901c8cc3780b0277abfd02cc690199f208162df307f4168800bfbf2d997b9164cd2094a905d0d990cba8bebdfc6b4f30f740f811b44d203454d4364376c90912dc515f7752494649674edce66dc97a66dbb635ae57019ec8c46279e5373b6acf992a1a49edfdc3975f89d3185ad1b2de46ec88647230df94679cc356cb7abadd931aa6f294e34c3eed16000001bc0000009025609637221fe1306882993148602ceb784483a1151fed8e832fa18354016cdf71254410e38ac04184851ef76e6fcc5aba4e9a6c9e2638e41c7c5f8cee1b13cd3b0d17035b91ad04c63ee8a196ba537c26145c76a657e3d58ce9fed1d815a923033f7f3b4e866678d5060c1fbe338741b642162e9b7b8f9c47652521db9d99936c4d1ad38ee22f40bee9bc0f9ada6616000000901cdc562761ae6a5df3735ae6520eb47449dbd832f71ed2fc601aba142d20e1db7af47e209133de4a4874478df07071a4e0e373f4c2a61f0ef9036ac6b9f7dc2ca68a9b9d42d95caf623a8d1cb579b14e8b7d3fb8364f41bb945b63d933917fccec8de9746d5a295470a0c72ae94f47ed1a19445e70fdb586d9e6e7040bda1392fe9f3824c366512191767ddb708db86000000090f1a3c9017a4f4e312db8be2df5c2ffc914976a896d42ed510c47de5e437d6a4d7c61f893b78170690fad42b3f785fc77aec0a3cfc350fa0fb8c2d167b83f3d6fcb68e198633ab4538cd326e50c60d09f11cc14ddbf310e66c54021708c305bf57fa089950e565ae42169fbae159a661e68e641373df3cd38f455f3b8ab7d502d8187451fbe918b56a7c826e97ece64f4000001bc000000904576be0ee1fb3989c2b50c3c12eb035478869d0070c9522062b4d729485a9d6ca310cb28835f7611f4c44e8a92bbce8a7b52e229ce919a836b1942920d895205469b78da41f4862da83b05228c9728fcb1865b5b24002d2cbd16df45312f7dd1321943f1f7bb6aa432bdb84462069bcfc58650c1b4bdafd3992b5ba65657965656128fe027ce897b2051c9c697a1bcfd000000906898e921b3171d11bfa8902b63cfe050b43129c7395b6408415a18ad43c9543ed00cf3932f6023e999bc2ecb19853b3f20cf8cd5dbbe8514d9ea535dc4767cc9c9e88ff5bc664641e6fcf7d60b4cda224238e457073e702b2aa03c6d3dbb3ee797493a3afb2d079389e1548b761aa78929c4654c1dc1260d1db3cc989eab174cf2639838f844efcc4f648ed6b1c635f700000090fc9483293459d113eee0962ddc86156fd3cd45d05a0c16e07b4c0f3bfa660e3b069664717211a3cc3682945993548caa5b22df049a2f86238b3118ea877ecf9829afffab51135dfb66651aca3346892221585fe7b4c05b112fdfeee3134f6e8d3c7205e0de0a7d11fd4ba79ee612e840d6f859a4e3c746d122efd2e80755b46e4acf8c38d23f9271e101865e1ed823fb000001bc00000090c3cf4166479dca196f8f0246666941e3159f4e630223144a4e7a5a3f9f275c365e9191c212e2463a159e9de3155255f0f9c3b26c82f97c1d82601be3c51eb33752533cedfa1df5a434d37565da7aeb49f6fce23d4419aa3dc6c29478260e4254119cd7fbc9734d2ad321ab505d3b3c81eaa6e991c9a101e7250d71acadce5669281a3586b524e89064a42ebbcbf9f65400000090f32756a1d3fac1cfd947619de20dd66cb5a3bab4a4b1735d81e0b70deef25533bd6183cbe0b46ce35a4fa3ebc01b62302bb65d2a6db20233b500577296657e24768a1837c1eacd099834e69d3f878ce837dd31a7b8a8ed78e624a1810a7aba36f6ddb23c411b2ee5034a366c18bfaf3bf8e32e6d38361c9150f3c008825b8be8a3e5d177c80b2450c4feffbf29c8bce500000090c815b26c6e93de18db7c07eefdd72c77fc04eede275c87032768403812324fb8627805521f427e1fe5f881739df67d2f94fe358fddc4a971495b8ab18dfc8bcd83acc0117b65e15ece82916332c400424b9df1a8c6faf744d3d858cc63d5748ef8e927b7cb58c0129426a11afea0bb752eba612fb3f3bc43b1a2c627e7eeaf83e67f54683a0b4886990b67e07ce112b2000001bc0000009047403c11095d5b37db843ee4def2f8314b6f35746d30dbcf7095a8f5bb372ba1f385c21a8261210f8d0ac4c574f48bcff6f6f328bd938542b88fed261a7bde161f45913a788d2e418e9c8e432edfedd0147966d3bcaf0b98d0df08552403e92fffc01a0508721e1ad14df4306b4308dee4de010f603093bab5faed87c6cf60ba3171a00856f2ac3b06b699f7bfeb90f700000090af5b01631cce3055d7a9453decba284c3fdc06b0b71d98331cda285eea5206b3d2849aa349f8964e41cdeee6e5033639273d9a84fd20d695347a217822773890dced57219cc9acd1c866875d58939b7436db0eaaae1e44ed46ec19aa52c5f07139084a2ab1750e25c4ba379c4e683c08dbd954495bf6290e6edc61fdbe268142910e82c6aef3873100e3e7f40c4e856b00000090eb59cea068d5d6f4ee1d8115de3caa9ac0bc1ef647dab13a897080ee608c4ac251f4ef3fef30c12a7ac13eb02de4f2a37027b245dd9f2ea62465039a847c84c9ce2058930d1fa6d573866a018abf06350b09f9ad6e6fb0934122c64e7edc06690432f62faf63bf11f2881d3026ac9bd17d2143f7bd55cecd872e6fc98494f20c9f1d3c6436a4eff1baac096c0c5c882e000001bc000000907a519a60fe33f4b9382b5a67a538ebf6f53574dc1b2226f682bb87090ed48de9760c9b3e96ff6c87a8d2f2bcf4eabd7ae4d7f7859b10b3490561221bda35379a6196f07f7eec1be17be8abf819fa543655da0b0e224a2206197a464dfc7f0f812f194256ec8197aa776989f7f6b373a3b7a9fdbd40f85b203d63ea04bb972dbfcd15e5e7f1107e6270662260771da70e00000090bfa04272dd685cca97b73fe43df6f13aec32a46040e7a6495aed0c841aaeb495dc9428024abb90cb8309a9bc381a08428cbce5642ba0c18ba4cebf593102a05c62dffebddd38699b7d0f61d9f0114e3d7c713d65175a0aadbd4ad218a71bd8c9c9822dd7aeb4fc66994e2d31402cf81462f3ca7dc5df16a2dd15326f212096b22b30f2e8634327453802da76ac65615c00000090a479c98778c84ca2d9882cc42ef49d8441e855a2f54a43e045ded34978d82b0b1b0cd89ae968660d697b5873cb35dc91d8f463c2607d6f8848ce86a8c9eb3d3acb36d049915591056ab1b79aae00a5f568dcc3c48ae34c054ecdbfed0e96eae51e734386b262e62de543bc05d56251cad682b889103e58a536508821f847033a321142d8933ecc097dcefc5430fadb3a00000e00000001bc00000090b7968a955d2dfccf014999255b9ca6e954d7caf9a303bef2814245542a14bbfe846c946b03c54c945928d7c18b4a756d3636260d94f5d69ef6f93c523b2d80e2dfa6212f9fa3c82b083f3cc5d0a6a500837ecaff099978ac1229a823df5b11facb2eef513c1b277d704e51c28551814916d644e8818d8f971e1d80f2f735644be615e57885d8568b3efc13b4a9a1fb0a00000090a10b4b7824af15267906d782f4904863afba1c3d1ed581e99e32c6c493a7846e6f846c84286bf333ed45ae38e0510284cb164ccabd2fe49d5791a710b94c8df61b337fe569991dc692314e8eca72af12107c2d75080debacdbc1318c0a8c40b6cb600c366a733fecc7f76543c4dd73ca4b237ab3b176d98537532fe0382ffddf4e4426f5227b0a4ac756c9f6badb234e0000009085c8b49b001dd30b7018b2a4a90e8485c200113f9c3c7867cdf5a4cbfc8490f3b34a056c35be01b576f39d69a86e7f60c2f6f8f1ee445b96a4449114ea6ed1e8d03fbc50bfc658c43e8d71dde864b506380ad15dd48cf99dc7fd3c82f3f1e48bc4409ae2ace69c4350fb1235f7e445b1f41e96477784299439dd984b19d8bba4489aeb66862d543ff340073d046c80f9000001bc000000908e9cc39a7bdf0721646ba3b0233c7b8631903679258eb14f27966ecc188d74c92fb176aed4fb55e0022bc417a1976da6b1e9ef8a26a9ebacc234bd030c9f930e09fadb0e5989f964ac2db2e8c08fea5ce219ee1c757de3b3305d537c5acbdb7164e6c0c5bdea99ca6e05751c3d6c8ca4abfd29f3027cd21467dda03574adf18be31acfb55227f08291fc7ff94aafa82900000090d7ea79f2a79ac7b7199608412594e9c39d6d200c865056541c65d00218430bb6eecca91752dd462ed04bf2337c17763fc18326195672e7664138f28f44afe7bd8ee5e36e5237fe193ef4c82c8d0c608bc078dec1bf9a6e693113e6d91e261c579c66478ac5a1596ccb91ed884dcf88ff8b8ed010c46d26b560d54b96eddd6b4f435b2149aca948f24d9403096efc7d7000000090cf657fdb9a0dd2b397c3c6f86cabe903860f881fa3d787e00179173c8061a7a903389c4f0ff1bac518ddccf514eefc9814f49f54ab22f25cf0bafeb92589108ffcd6c35ead1950640949e8f7025f5e3e669dd8f298498655d4f22d4908c40f6a1c9d02ff790d397440b7d0e0e64b2eb03b52be821ee39dad03788d613b876fca3053ce1fbbf61588be94342740011cf6000001bc00000090db066dd99708e02662124ea437c46cad412577c6b6e94d535f1bc556be4d2215c19428926ffe706f811af6eb239dacdcfe6f2b00c14c70ccbf2548cd3eb3c59ee030c1a0b3f02e952e3e370f39a3407711a393569c9905fe0be6048cada151dd5fb1337d334b5dc1c2b018eaf892d3edf265f5c22e45dcf843b0647159f4dcde84bdf31133bbf8b7c692b7d24c1a063d000000907bd9616b869597f8c331a4112d51429c804370966e033be8135121beb7a4dfc21ecdc37facdc01ecc6d1db6e9435ecb4833f197b6577403d57d2c09f511e496da938ea4898bbbeefcf5c776112961888d2aab79a214ed7e45d34a7699ad5523e02ae32c96a2a49c0cc5da2581e81ccf55439f4f5d0e52f5542c86a65dc8c30aaa326972fc852c514e57877fc1632a10100000090db2a0f48ef0ee0a981673c0fc77b364c4d5b02498e71853c6806e66f215613b266da6f2c3295f6a61099d72f94ceef9a0ceff8464c2b9b106bf36bf6ccfd512f56e7d026e7f680ae933978974704a03b27a1ce316c14c50bd191380b7ae6e5eed923737aebcf01092047f81ecd47c9441536c5a4579dbb32a1fa3c2d5758014750efec3a27c52ea30b68f5d9f4850e2e000001bc0000009028a58a7daf03e720795deb55e471a44b048b694f524903dd1aadc6779f6b286caaafcfd0b95d213eff8ebdf24a227ee8a2503d9c02ee079bee47cc032af93c1f513da5c754599e5c14a53cce674e1e37980840e2cbfa446d7c8e00ac0797cc6973c723f3e7e1e4f05eeb27463c1cac066661b441c36d43d223effcbb1a7e16eb9a616c23efa8643703a519fce0e3dec900000090e12682942a9cb9d8d97e0d8542d4b3eb2f61e1c6b18d15dbe382472cb8eb601c2191b239f98b6de85ff2d96b53c5158e33dd6d195bf4837dc481d5c068136ec4d31923c522342c81ff3fac8721a1da2e83d81be1e3d657a9d6ea592a634ffd4385226199dadadd8af222616ddd36b8a58b6b014d8659e76e99a4447a1773869f57c4ff69075ccddfa46de2db7673102a0000009014acf34b96562f756f3a34419fc01eefef5123364d56c35c3226813f56b7868e300d8c299ef09be1b08b38a85f759bce2b14fffcf6892f37d18c54ba9516a85fe9ed9de7293d7e7dd0a8d79ec9b069faf44f250c4c5f748b396901228c7bafcd7c89059fc0b330b37a2b9be7c4805c50c8cdf439e0f6b8fb7e8706ed29940bf7098edde8b3f427405865d2a6dedbd040000001bc0000009076e1ab6c68777495c22513e219f4a9ef4ddff594c95ad42337177a1fb4842ee0494168c135904a0820e65e95ef99548b80dacc87fe0ad7a58c67076640d3075e9f9f1cfcecce95b7d1178fbf6ae8662ac3e09c6470fb6ee972e1af3833309657eb02185552813b4231fb0dfef0046567243efe8bf958502aa87c2b08463f71ca4194bff89dd4b29b7e039784145d5e430000009041331715e1cb585124b0dc39418125664fe058a973203758019fa2ef0ea59c7bd5699c0d072e61cfade043c16f98fe730b4c8b62c66aeca37cb5914337462d7a8865ea805c3a989f184a154b8cb49305d9b15d98703e9bc55b33d3fdf0ac4cf476ed841c65a6372744f4edd93b550e48b49c3acbeea01235449807c8bd5edc26433d94016700d07365769ecdce72bf4400000090c362e0f4934778f4585405e6402fb9de60210e5f1209f942cf428510da7f03774f0121a7259defeb3f1ff6895b5dabb8fa7dcf1c7e1c8f157c01f00f62968a872d0b1d5d072d37aa0bd644d63489d0fedb5eed785b537c852f81b1def1b4dc788eb6d8255e396854a06fbabe3cc4482301c38923ad0be4f9696227eb3f5d83e99f554f1dbd79d1b64a50341a85a73740000001bc00000090a6e13c2eb058853e0865e0d942ec7d63cbca97e6aace8d62edb8429a5a2cbd2a2ce68508e01326c60881c584e71f4eecce64d2d2ad804c62ca47c5a0d1958b6bc7983aae29d9430914e4c09247d53fc8a1ecaa20b93662f4020cf7331a55701ee9fa57b97c9044d7048dbe7d1a9a350c96e0e22b1d808e8d24f17e233e0c864fddfdc7b68a8877c73cc191eca7eb9f1000000090922b263725ba81ccd8d7422243bbb9806961a47e96da934a3a5fc4603e5d5e4e6bc7d38fd31c84aa1747287d9f729869ab9c0f32bde16677534a83148f9c489920d3b29f6cf68324c2e5d864932dfa60fc97cbcd4d9657281712b022e29f5f89992cca034a6342d635eba4c0ad2df5af89904e4276ab1da6a39432ee1c0f9a8bf0ee4eacfa26a54d1a22a3d63732744a00000090c673de086083e4f2deaa6a3f34a917e374d1a9c2577ab6a85ff9bb583bbe7fa923f3efcf68348028587ee4b7be6df0a97c6af81b93af58038760a59f2d91bdd3126fdb44c80b208862924a53122a75d0d0a70b5433714b1eb1203cbf165a934a6568c68a22d358490deecff0558ccdb30e006a98cf07610a55194893c9649b30398a3301e8ba5d721279caa106549b6f000001bc000000904a4029e9184666e191b436b44bfa3a8857c4335075eb18bf413257765e02e3e16fcc66d3c2c32e339c0ae1b4f99a66232adfaf33417d71e3fb35cfa8272ab18257d412ae7c56b7c65e1dc1c4ffd6ea5bbc3f16dd46d111c38999b5d4ad141910dd482765f3cdf7d6fda72159ecf246f4ec5e09abf857d3627a4d90553dde7ea3f5663a02b08ce0069b78cb5e4f49c0d8000000902178902bc93e04b3f3a6658a3ee3cd0aef2a16aaed6f0249aef5a026de6f516849832b547d9a4e026ced2da2ede5ab517adadd045cc698446827bd8bca4491e2521ad944320d7198e23ae65432a90c51c7d0c0c6dd2bb78ec5a47c241ab318810f37025a301961be34aa75889f13fb67f39c272222d68fdbdf47e0ff5b3673b290951c674a463c68ca3105bcfde34ea600000090688c993c3b2a470cc31c4bee959a98d1af8c12d21e520b50773fd7723d9d9d6cddb095a99236d054ce3c11c6f557cfdc79bca98c54964cd68944b28f65831eb3ec6086b226077d5512c782e030b57e3c3276da66d8eb3af1b7d2d76a2a382a1b6e7f71e1c4130bd24b864dba04727ced8abfff56ad35533c1fc7eab7ef08949d08c5208ae3e042e763322cbbb0c65776000001bc00000090d50be3ce4e58c66a007f2716226fd00515d21be6161efc71317f535c0ad3f1cb0497aa0c55e3bec7a34675504334497b6958783f1090b88ee174e107759ae3706ef200b69e4e9681a67239f9512c4e86b101df5bf73f08d3fd08acef16bc9857b722a6472a6dff98baacace6f3478fa363e9500406db02772c4fd328f7bc82b0448cea431a089f6f567410d44992c3d100000090a2f72607f0f9161f24cc9c00ba8914937e24cc3d20d3b14c751076ed5481930c339928038c366f5fa1db32c055782c94b44d7e6a73c72b8370740c9a91972eb71165516107307e18f0d58c0dd51fb0585f05e6b64a7903f7e427ba93bb69a705fc464095757f14c5b86bab8352b84a0066210a190d0ff68fb88794730e6d63cd8ef03f632f8a6d28e7deb8a9df7dc83c00000090b5abd77435f66a78e2de4cdc07f5326e6ed20a594ebb0b3dbecbebcddb6ea6fd756b4393b024cff5cc9a178ae19f5088f6130f37117b37bd1bb5847f352862590f5a21dd0b1cd4060af8dbbb7300557e12bbd00fcbf953b4111477c5add912c77cccfe78306b3f29a5186bf4f005d948b3eef381081e2a8693299484d28445e4843b48c6b52582d8a2b5d84c749ac950000033a000000ce40000012800000090229388b3a431be6b9653aff04b9359a8608767dc2de0419efb0b91f247a4269f45a4b1e2a8bc2e6dda32f707eecd34cb3366b36803954fdbb8f279d852b37b33decc47345388d527433dba1449c00d03a490e6b5f7f0e9ad28301d099ac3492489f8287165f5c231389123b86db7baae55731f7d2ca674378556f89548ab1f9f037b5c982c7b7ebaa74ae94e2dc4732b000000903aee5e522b5f56e536df8ef54bd19f1c5bb1d820658fffd764da995e584a6efaf04d744beeb6127f19410af6fb65edd2261dbce88a18cf55d47a07c5c550ebd1d6425136927d40bc78a13c45da9e88993ef764aee2a53ea05dca3ed57368eda2c5a6a13b08687360271d05d835b94b78efe6b60f2839355849495a363ded3507648476e19e3cc1d7903191e5bd8598a60000012800000090505af5b4991216986ea5634f906556df448f90ee8d7c400a6e96e2d2014d9ca502059dbc82a4eb40e6422cc17d2c59399035a13cf18494af6e79de74dc243f69a18355d4ce14c1121ec65ec9722c4667e31ade9bb4ab5c41db9ebac1f0e215dc5236dd747e0ba8685ccaa12760865546d52a9e2245d699c8e88d89cd183e04c0ef8b4b6547141d247937a6da6ae338e50000009094439dac22b0f4e1a1cf2747ff890355cdb876d1133463d0f3016734159d099540628b8a81562afd699b1bcbc2885ef8feeed751536d9bd8cf046a0bdf0398984146839da849ec6bd897350bda300f04276a1b7d9abf799776a3c64294b6e4c9c768e19f0ef758e0fa97a706e6315cdc7a2370f89e301ccfb5664a9cc5becdf9bb0fd015936b984c9b4800e62b2e1f6f0000012800000090e0698c6a57315526b74f6cb3617711e0c054b0488cd2b3d413e18674be991c4ce9d6796564eaebb8977b5ae75ba9a47259348b64e8330754cc5543c3b867da1709fdda0a509cf7a216c6c8693547cb4454d17181ad1e67c51da2446c1b922c87836775ec86ed5aba1e4e14bac831021dde12ebd15223efab74e73b47d7d42a64b255dbe1929a91438ee5d82ec2c2b60d0000009072b35250299df92ec033153bd0799eae0234158b942abf7c23df05e6c60809a5e0a344d7de0b739c3c478c00c4c020c9cade6a7f3c10031c47ad3248bc56b47ac7ec58f071aabb500370c990804be96157e63e41ef9476a965467cf588f77f2bb420477512ff881df4bc89628bf8be5b095170733398ffb463ad6347e4ec5d3345e35be599a28d5e744efb625ba90ef400000128000000903c56b6d74c83e54735baca8111b0c3e5496c7cc3737c1cbea76e13761c0c086366de8290722cada540d19e8d45235e49469bfeab2b09f84607d6bc069409fc29d6ff6986e715caf2b411343e1b4e66c0aaec16ff15335f3030803585f8769fdaff07f9bb95d5b3a1f25a3d5bdc8b8420d6ab8d8c8c3146e82e330abf83ad8bb8e8153ed842cb780af11f4a7104a628e000000090d88f4ce50221ca7385fb78a7db3e639413b03b803b6bb177f100c95007507af701f9b4982607615066f02f598ed06b6f98be07c33e8283eae9483624822dcf36400e8193dfc720d12e58d57bd1eb0fdaaa014be61644f62ad2401ff2460f91b9a852ecd0c761ed2fbf6c00e721cea4f4387bc825f1bb92d29dd01e7aa31f4aba59a2188d3c2590b52cfdd921d7e8e57c0000012800000090aab78c0b3962855a0dce967579343c0137331b1cd622dc347ba3b6e3d66ac75c602484fb7a24e771f9e1b3f9edf768b86614c5e12f5aab14023a1f35e7693c048468d51e1ad2f71bbe06deb0a6f25b348372c25388d1cd7e44fb2a01194786bd2661abf38e323be07ac7e7c869348b6a0fe03fe712c3c2ba944353e7c161715aa4f5a6988a0531bdb757a5b96bdba738000000903dcdb5cead4dbc2d6f7f4dd0093b1c14f44876543bf016543b15a05938d6fb66f17f02a0e5467532f8441e0699e20acd7060a2b6ebbeb04f65af86b416b9a081a5cee331691a934379450b2bb4ceb4b1cab8f5fc861ac3d2acbb6485e2e689c91e09052ff61f9a819bfbea097cda0c6474f8a788a00cca8d4c863738bed83bc8e16e0e9759f9ac190d2b28987ea4231200000128000000903cdefcfd45b1ba2d83be0a46ab7dd242f7e5e895e7672f50add523a0eb6358f94c04302bf690ba420aa42a69e82a4f373f1887e7698ae51d11e258901baed21b6c0d6c3d16de591910540b9abad5c89a96bdeab09b27a752e94dcb2e71ed8571c963df9afa3d8d736b0621d941429139aae3da4fafa8def367250ad17cfaddf758914fd43d6901a92473fbb27726668900000090985b0016d8588b238dfd905cd864cae91d3ef4474833887e1a0119f5b8e67441d409af7bf106a2a9a10b887bf8edaa4d240f2de9cd0d7a180819412f076d2502431195001c2cb2b624c249519933e40cf7918e9d8856a8bd927f761bab2a4d2bb1a8292f4d63107f806f7fb971d4e3dbfacf5798444c335bd737a5e00c78f148c754f8d761c3ff396af00e6808fd01f0000001280000009001ab2f2f96fcaf3ee139547dfcb20712ace6ae915f8d86d2aeb96a8efc356a2b0c9e40fec9b001f22ebc49c53056f781aa0145115822ed88c143f12a353d5f0470fbba36e85ef4491c85c310feaa6a20093eaa78eb1e49c815cca3fbcfa32a942f90dd82ff94fdb74d66a089fe8529fbbb6046b30533d144f6a537fe8fd734ce32bbcab3bc2019aef32f77692397b2e400000090ce9fbb834c6c927a11fac76cdfc44a00edcae62a5d8088092a2e7545a3b4a7d6d58566a30760b7b3f4e58fbfe571c4d5c72da8be7b7999a7c29c70a02b868ef5558b2b70b1cba583d27898bbd2d66c2923944c85d4fc77d36a5241780df91173f2bf13e9c814f68c1fe6b5d92d46f7c1b2bd1e69ed00017262f1d8b1fe795b498b920a9be2086eb2f00b8f652964039d00000128000000908860e1a69a9e2cbf88e05b93915ebc98e8b609f41781ac97fafe6c3e18e8c276e6faaa4b252c784a9b8c09e1caef1265e0f2c467d6272fdc889e539ef0aede3684937782e4825d9aecc975e09770420f04ba1333c84fee4dcc917d6ee0e567aa421f205839425a57597de409eecaa93d3a4fb262f9a99c14bfec03e1437b1108323ee30fae221f925397481c6dadcad200000090966fed22f972cdb59d1aa2e6c28c7643e2d1a2dcfd4636345c21e9d2c702dd6e9c97eea8fa2b4a5f2ce409f9706f1c4f7061ba0597dc1772c5252d3f5c0996e17fb44db31970424fa04c39e4f9dfe1df3a19ef6536cf3678704566cead85577908d2920d4b8bdc43c8154712f0e994deabb13034ec5db65ed7f1a0099cce611f0005bd6b2d2fb8168fb09b296d6d3de600000128000000901e24bf1b818df3b4f0c786e0f65346a46cbc6e32a4b3dd7354a3e49e45474fa4e90e150e00d9caf47ff6cf2ef7e5af39576ad7b7afd93a1271dd3e6cd08bafc90cfe66772ae41fcd3f6f184fc55fcb61ee464c44442f22a5d6ae4d8423fbb03d2ecc706b6043e1762d51df7c4f72e4bae329325f1b813714178ac415fac87060cea5fc7976804ea4d580b5a6a9f2bc320000009069200cddb6678b395690d22a92613469428b1d487c79be4450ceb95273f6b409c3dcfef361f1a0fa88209a31eb26b67cd96374df6bbe2b32dfcd867d00d8d5f4030e3091d200e4d95a1c0d511f8f37ba31378e1bae21b3125818a75f52fc89fadf49b10125af4c66631914efe6b68bb40d1d6701e52cf14587be5e697aba1f2427d67356e5a9c10f3c6454ed23af43f9000001280000009075bdd58d142542120664c3a621de692476f985546d6e644cc10fff950d99e39c3dc88d84dee487f947bbb0f3917c292f4276e9f87fa5724f0733daa0922f338c1cf4ad40224cf3ffa9e0ef29349903fceadf23ab67bdc42a6d97b73bb85352fb539252d59b6e7e86238327d630e0a4f6ec9d8931377580c4f6ba30f5187e4d59f60f1acd6fc96ecbbf94f13a92830790000000905ed953ddd64ef5fbfe5edb5fb182de41aa7a1fd5f9e85b6d5ea74cd8a7bdafaae31a434198d8841c3718a07ce17edceaa7e3fbfef7c0cc8aa893fc8115857754053d8c77e1b16cf1feb8e3d0860585641d188ea2c414831f3624ab59d835851f1bd033090662fcf445ba08f4876bf71590e5bc3c32ceb745088cb0f2ef46272da82ee42ff496bffc2ac37a20d2bacf4e00000128000000905a341b6ce0ede8f5f8f6e8d32e8022c11d0c68fcb7aced295e2ad1a83a9596187a46d257d062ab1c70721d5aa577dfa429081d6a355708cf37b903ca19764a3c0dab929758e5193aa8d12150c059339aec63bebd51c3092d43145cfb9d3c451dc39d6381650d37398521efabadbe3c1f182848defb521b96f8010d5ebb0d567cc1a35b1f92239a47976e2b32989ca7d30000009073ccdd690f4eafe2eead77e9e089ba7511cae490f3538e6c84934e714a4e9fe512908ad79cc5ba5e0fb79dbd9e583c32a9bf87ee48c96635a9a75be8c35194ea95499f3249d0a1bd568e081c6784f79a20467f0d81545aa21a7e38ecf6ef9d94dd9f5df93bf563720b644bda89f3c1e229db4cbe6eb0dfca5adcc805e1ab68da3cb812817251b02acb103aed40541a2b00000ce4000001280000009026bce16f9034980ede54249ed45fd623470304ac7d5c290037b743d785762c0178dde6a5b11b70f67ea2aaa4bdcad784ad51517c0aad8d0741ee9896cdfddf5efa8cb971bf13704a62ea56426c5b5b28dba5b9d7431f3b703d16ca928b14717ad847beff58bd00703d469b04ae8d5673c764459d7c70c487e2b8dc56921f3772fe890e19d46937246b6ecb53f4f50c5500000090f04587d4fab3a75048c04fa486941e4e874b19ad77ad780f6074d2384fefac7ce05c28ae2ad4bf50e0025bade67aae8770584ba9992b15db5533cf3b89fb64677adb54c862e350062e733f35edde61fc884a5293d24e20c4310964eafb3c5960d7d1def9a6f609e98b1022a692f0fb786d81df0d158fff49bd11a990c3122e2fb83684fe6b5106cfa2733c6fab9fb88b000001280000009035a7eeca40c8e2bba2ed2b757b8d6490f44e13e161354541e0075ce961822a4eb27b051457f9e88be8684213c8fcaa00ad2052fe2886e701cc24d8d6f7a4aa4b3597c7d85613edf04dfcada7d7c39da86b077d97620635b6dbd29824e0848357be256b504ff5652165c4822d4ad820ee2c79467b423f5d31adb633612b5e5b15777d6ccae55ec70d99a6c10c030cfe2a00000090aebaa1ebca372bd33e7852db4163446d886090bcd05d6e5355d11047e601463f4507859694c8e30d11c9d74acb02a5c7bd5eed8dac2d9f0e5d0281007233a02ea4c0ed665441aa57c0c7082b942d65b53e605ec7d3d89af83196c02996622bd3ebaa5d54b7d4da94727478e2987ccb4bfb81a153a99603930fd609be0e6be983e1fd59f539a91df3e9f1763142f9a6ce0000012800000090524c471a92b6d7165edf28ce0e54d66a6f61e270e338d4cf262c8cd180db7be85cec5365b6008feb5be52c99461328e1ebdf6893df6f9808a74e2cd5fc6c60919000a617cb9a4bcf84e01cd6404e7d5dac142e826e737dc8758b90c4dccaedab94f1cbfd7cf053d8fcae94bd309f201831e0edfc6ae8e30457e0c0371031220947c78fea955d4680fe39ae790b9e963e00000090d3bd94123ca96bff2dee2aa370efcd404e118f1180d79530dedaba3dc3154614e9915a8b0901b005c288f061f03c0c60566d357ef772387d8e61e8f4c2b8654c62c7cd23c3ac9c033d98892b1ea04ba5b4a9aca46eb7a128045a09269f9bd4fee8402b8be68dab85fd929afba6f29a7fe738be2ce0e94820e0f9c6518bee1b44679c9780f200b5c6261802b4a0be2b1c0000012800000090319c0d94159436bb81fcc81be0aaf9e3118a5955348108a8fca1f4a77806ec0462f1899c78170ff4176f5e97d5a8d2721e7bc03a8eb6dda0351850ba330a2b54cb7128286d9ad0d7b58c37d112b2536db4d6a86d66a3c8559d4cdc19caac191228d72367ed35f94d5d2dd7043ab074a7ae22ffb167347637c3ba2ad3a0c419d1181e67b061a1de2ac917f012999b1d0300000090065f2755859b1133d853b59bcc80bb73af1189664b3195d624861c07c9eb878cfa8687cfb82c4f851b0528473e27bb9af77059ae1c4e23a5f2372ff75857075a753a9c75875ae2129823424e66d5d78f84afd052d61b0a1b31a3dfe6cb1a806aa19a50d5b9ec157d2facb4f563abcb83cc3b6aac3dcc528c329b4919a355907b36cf2ee524d926ba87092509e3d808f70000012800000090fa2875f8be9eb0776642aa5d2bf2bc615e324ee515e2d4bdf81c09de95cb6ab3136288cc91a3e145bd70fc686df1754f7162baf30e724733a98258f91792da9bbc4264cca247c12d94e1fc2f2e45f9f931060c14c2462f6b0cfaa1a6286c03d3e30d81cf3c03f68af6d107fd42cca7438ece9749058fbc2328dd9bbe02f4f8d6d2309e6c3b0001af3cc932dc8bcc8ed200000090f50d7d32ab91cd8c3aff752e922844a0bfd5edef2f6bf8784360fd5b486e44288b07615b9d580f34a302222225ceb2f04d41339ec684e624163d4917bc8e42193fe14b0c1c88d68f88f9067ef677bcb76c752f326f2e536bf531c021e543fde42a5aa9e1c499bee05f6d78647b9d9d5ebbeafb53b8604767811f8e2ba029cb438e555810adec3f85ba2521675c2750440000012800000090d3e5f1f0b7463a85fb887c73b59cded50445fe4e890daeedf6a576380d2b3fa11c7518fb25af49490abbd6712cceb4305f3d43d61349be0c9b4c393a8a6bbf30f17dbc06c2103572b1b5cf22f86daf99eb76470d469fae219d26c1dbd533f47cbf1a3fdedbc55ae23dc2a789e51a8ab28eb2a0f292ed0c9f7253913199ccb2a910bb012a2ccf4630fefa169f661ad3650000009010599e417943025a7639267a1e18127c1cd439d05a1039a059f8ab49f9dcef63b890dabfa6096ec7fa0ddad844b29842ed3ec56bd6190c811da59fa70a07f9f5571dfa7217aa63717e7e6409ed81e37701851638904cc026911824d6b25c702fddc156b58f5f48ef411176330f9fae31236c67f30a1650158369ffef352e4ce3fc6a4d8cb5fa6ed9c5ad9ad3d119701a0000012800000090a389db0fd184113a4e4b46aa17388cbde640bfce3325cf61bd8ad7cdad47770eaa77abe2e690f52076a252505704b309cb8851cb69b24c95a87489136e6f73c0bfd49b94a4ef197d01d754d1ede85e4663e923dadbb4a4b806746f2d1ed9d992e06e2dd80f320f827db44059e1716ea92a1fb7c77e0d624d5adc773982b6c8d6687b699b3bdcd74edd00d78a69658c7c0000009028f5c952c4c3cae898a4269ac8ee0a0d4168e771a6f8d58561fed45c016c95c495c721923916f6d187b2523f7df94e7db8342aaa50f7a8c76823499ece6d3a53b1e095c4310c0225f60b20a91b86f1d2fa94c0ec508cc26b7b88b01a4b3b17e06698d586af6478253b877068f6a846f18fb0179240bb56e4e54770b3a4bc215c2be2b50673dbfe7bad40c07f63bbeff30000012800000090f2c814af6271db7c8e9d4e66cde9621bf22aef0134da41f47c35f71e471322fd66ebb39b40b974ca386bee6418469d5a1f3614758edb5ce1fa9636e03092329d8974e695dbf86e8da247feb4968a7b061c729f685b9da1d8b8635e04567bbd2b33eba0c833ee0f0bed056365873336e905c137ea0f17978259c2ea780c8c25ba328af85d9d98a0e3d938ae4107e42332000000906c52a4d740a9a815af7a7e95ba09c78226736edb78e8802d418b12022485c3b7ce79547cc3dee2c8001c0955d2601cf7aea7fcef6a09f1e36410a28a233be825bec542c9dbb53b6b2d203676d2c62b06d180b8fc42125ab058b9155a27244b61552af9f69f214acff4373f901e83c64a49116c2dc7b9b312b4fc93de2bd45a90864fbdf25a4ff286563a0ddcb50ecc770000012800000090bc8e92635d068e8f45cba5df8453691e130a9fafddea39c56f766fc987ee093e76ab21755ac24471f4bb049e3e71af69d9b12bacd520d6541f74909f903d3ad05830a6453d20c79fbcfde7ea423693eae7176bf537bbabdf309fb4e4178f40ac2eb048540dd302daf6deeb69aad9617361c56304a9037a66d39a94c487235c862b95d933caafaf0a964204eb00b2fcfe00000090f1d1f253bb1383ea73d63955d73b688b3daf0a019a1747ece001a07708988e629e5cd0d557e8f2f674db96e904a69762d1bc2eb02083b535e7767d14ad60fdebc1ef938d8422cbcbf9042ffc27a76523f81cf17bbb658d9cb951fe0bf9335520c00aed26cc37b7ac1eebd297ec02e90deb147a3aa5f2933973c37738cdaa040db84200c040225e7a4d412cee477998210000012800000090b864adaecd36d70266605faf87d3eec7205abd549042d44f60ffff66ba0fefe5f2426826b44c2779e144f28a162d06d24efe8cf29c337333c8ee42bdf40e0f5f836da60d7ae07495f821360f22afa06e85fe1ff0710fe0f12f2e1a053cccd9a89eb8d69b12d0604daf20a79e2b310d069746d271cfd788b448aa9c907b0be49faa548bfa0eda227aee965c8f4b0cfc1700000090cfc24b1d4dc86a7e0b31a4b03db181ed811ec14b156df7da4bf44ec6a19d7154ff5b7543d4a117176f0cb5a509706a19736b86ce8027dd3ba62ed0e1bf93bf2686201a6aa33bfeac26fe49c2a91dedd85a8d0323668373868b40e65e662edd3b079fda7b450524e89ff5987d8a5ede5117c005777c90a426862f76bfabd4ee3f254525478d37403866cc1b536b24519f00000128000000907340b3e06f362d0e25af7a0054eaceb640eadc92c26ce2adbd225e40075c48adeabba9a0286360795e5aaf7ea15560d1e9ccb9307b854729ef54170a63bc4584cc33744bac67b66475067b808c7b3612837efb49e00909b129456195dcce20256d5aa533a5ccf6c81644deb9226458b01fa3882da3ccb1cde0778a76e0ef1de5a397b1a74d1015da520af795974fb68300000090d2f4bebe950156f5a477fecae6f502f2e12d0a6df4029e8b4bae461d325db1d3b5812a5bb055406757f41621c76865b80d6be58a8bc5d9916c0627eee5928cbd9531e7977707dccc5c37a1a8a91f61395a77fa5fa5b7a70b8e677d311963474577abb368e9e3e571a3161f82c4603086ee0acf8c450ac2390b5e11e41c161ed9490c0605cef9916dd7ab4dfc8639aaba00000ce40000012800000090e549acf82a2d39497468fb5b925614c77bfaad29c7c2097eb12481b38da2cf526d83815bf1098dd63315c17a3cadc92ba6f513002cdf6a388f1de593f4b1075fcfb8ba1775f0b9796dcca84eac6eb940a7c45a9fa6c123681ca3d9e1879f61b842aea625a7de75502dc5af86d6b159b7cab7fdefa98b2db1345d07cf7da54dc5b1735ea31d2e75bfce4767273bce88cc000000905b57379b21c844b13cf8f3a037091cb3d0badbf3bde4c962d6b9c3c859e71295b1854091dd1c6668566ad727f9020ade69e19d34adcda46d2c93260a54929ee78d0f54cd90deeb0fc3d5860b7cf373b1012cd224e4bf27172a5741012cc83dd2ce8afbb70c32e3728fe900fe16284ae8b91f09055fc133f32923b06fa3f594635d85f964e8592be2175673eba3b07833000001280000009068833df188633bdd6038b3056a6f3c496a25391b1931b2f7cad08ee450a9a2a319f9781f9219511d9e739d99a6339a386822f561ffffd4d03d7fded85c2aa60202b8b67c104a85455a269fa8ffe4aa104e510b61731cea00eef07a943ea86867635706b6dbc509ee7e710247f254ce37315c9430368fe5e21cb5868b0f8c15d0494baa5aeb5c6b9a3b2985b3791b9a6e000000907676fe247936a75a03de9df952f34f0e82cdb40a1b057f932f6b913d30f708119d8857a1048511ea14e1710db2b90dabdc1351d9521f5f3064367a1d2db14fdb33bdd44e155cc39f61795f024ef460b307624c7a5e004dbea07c89cd271f921a21d225bc1cd87db49e398e1e8aedd923c9032f07b7e29cb1ceb462a59a6b2f9aae7cfee6064ac65578fe46c69cac75ca0000012800000090811ed27dc7ad47725b36f2c99ddb7e4cb66d6ddbaabe12556ab48b82678be51ba35a2c8401214e1c52e839a8a6903345b56c482977ab438bb64ecaeb5b6dc871e3a2876cf72333935d688ba754f397f3b96c795a3b292eee1f0def244ff2d3055cff950f727aef6d10ee069202325a8e154d526e08bd9dca4115276a99642612af60bb882d18903d261879dcb83c388a00000090e215b3deaf1f80a0450ca99498b82978e61011cfecd2b62ac1302b54f5abf8353658654997d2d66aef07ee1cb22bc33ac492274e548657b9d72c33e15883ce164fb56df05ab50d4cabc5ec4b3e328e98d595e36b1b778577cd9f07aa530d8049b4e39be4470cb7ae5afda18939496c85969fc1d3859992dbaf71a57ab515f4ce475bfbb014d1a3b005d698240f3569680000012800000090393392d7b7dc83078bd03116d5331cac8598a7d3dbfc13828d4a755de00f03b2ca88481407fbe04314601bb9001255aa51f43898cd2eaf0a1c3e11987b40fb4ce9d81f838de5c7d1ecbb79addcf3e27662abe805244c5b3d6fe5bd6e542eb329f48584e30d09d103679f52268d63abcaa6d02a0e9596b1c5f4d54c4fe11d8afb084494242cef2761e6be2b26c69cf28200000090082406fba8c9ae1b7c48b88bfcd627113f0d3f8c845665439fff90506e6d10257cdd5039c84c2b726a793c46fd7e30553bb33e2b4508d626e3d1deb2742683b26bd96abc118606f6fef1e0254203743f7ba5e122cc28a61e7c25550ee83cf7f363fd0ff7ba950447f08f868332b7369af8dea778aa4f2bdaf19a6ea422f16b9b4336b90d597c150712c3b083fb5dcb860000012800000090566d5d24fbeae58464b0615822f5dc1a5a03e6387afc0f89143738c3a7a82202b4d56c2bfc68175482f4cc3fdee16e023931a4dd760b719f0e31325a7198dacd88e32019efcadbb2a52b9701d23476fcfaff2b0f621845c3e246118f5c45e2a6790536c3984ae9a5984b938c3297920d7119a80e9e65dedb85f624888ee140d33fc9acd649e269a3ddb1f6bd31663220000000905b94546562731f1304d142db43c5462d32c17a7571b9a3fe2fd8b6c594b07a1bbbe4307e8b5c8c79213dde97f4a0ebaed453c4e798137e16b7d97c5882bf505ab2febbfd0a9bc802ea653874f11d6428cbee3a13a18eb54aa068cf2493512935163c59abc5d41900687c0222c084e85b476cbe9e2c1b367589a987f8c85c6b31257a22cec6af243663028f6d04b83955000001280000009047f97e0eac0aec21000ef407ba1cee999045431c0b8dd55027275e04502ab79ce4d0b6e5e86e8267a4e0234e029b335fe0a5a425638b5c07cdf37819afcd4b1f89246b02dbcd453bd7c2b0b25334f835468e6898a5c6066e62b8d869892dd294e05c83441841902532b4b5614c537bcfe557e329721078343e340bccf1abd74caf709ba0764352531308a7f5abbdf36000000090538969d6d762b76699c38f562873016b04d775021b4e9d2968430a2b3037c9cab3ae7814fd6dc7540e1a776bc4b75ebcab68a5fbc3eef095bbd0897517073639167327c8ce14e0e383c48475123e958c0c547ec4a2304df37901c05672f909770f02994c6f952eb5f21be1782e8f9b58df9967dbbf40306aa622ae9b4f8ef918105bfa6490e6311df30d9caed97e65180000012800000090ecf13baa64eae5d4ae2a2171abf58b0316e596ffb4e45d8b04fc6b3ef7baa3b6f144c69d47e57f4ce71725c1d23d904eab72f1e9558b38a2ec2e03490753746866158f8b5a1c1676b6c104795c2c72b46c02a0a24b09b0a167cf793e6d3a8fc4966487e6b9badec4505406c897064d16397c8f9c19e3be5bf2b6d836598a05aac481b44c2279db99967c7af13f9b754300000090ec3107180cd218bea3427fb271d8ee8dad175dcff2c80f1d9546beb9e3888f3da8632ce4672f5a4d826d219dee2704ac726a25cf699bc587432d1e76c5370cc090646ae5eccbdd2fd291b96c28f012c846308c58341f691de11365856500c6ac11ff5a20b28b39590fa03cb51730afcbb5651820568c5287dc99816279536f9016d8d770bfea03cc7dab39d4727b62910000012800000090b10f42fe05e1e1db07bac42949c8ba753f1c1185e27e061e5c73b8cf47eed8f356f38a8253891f322bca6bdd7d83933291953bfe0f225edeca42a4903bbdc73484d2b13347bb5b6ed7f48bb2215cb7b7cf968b29972e7ee078af4c634100613d21fd151fbe189aa19b395ee32bd671fd7bc3d1f9b8add290760f8cae20afbf91262267fb012b19527b11f94a35b5d8e20000009027517a0b48a659823f506f85de46054b9e586a0b9ef8de12a8d5f126d849333211c3e95f572cd162217fb7512eac7a87e0cb71a81c004a8d33d97e85832c1b7d33d615aa220cddc2ae5389bb239b8e29652b02e322d20c5e193bb3cad2efca03afb2d04c44815e56e2ac9caa2b68d32dd291ce3da9c7debb6646c0de58f4e321df762a3cc55cfc30425221a2f2cb26d10000012800000090471e0b99b2d33a1c6c46137b51404859c121b605ec6ba2d051cb05000ea2af1038fd2f55e333b12143126d8430e576a3102a4cd9b7d8b28bda0fd68c80f9f4907d273e8db07d35367eff9fc93d715a1e1e20c80b76593addecdab503c944603e1ace2d612f482eec9d23e9655552ad9b5d6805379b4ccc26195ad730f4a192cb4f85589fb9f4f0556480a78593348a5000000090b56978aa1d94ff2e2593864144defcc9491429a862274141a65225b58597d15b8eb13ef060cd75c33246df88241964c87eb08f2639f24048a0dd94bbca3b0fb4a6fb82916f2b6fbe1d05504f02fd6b4a67b58c58085864dbb6a26f7359a1e256e7fda12e9f4714dbab35fa1ff05081380bd351516c68b542f7068f2ecad24139b59055599b1cecae902973dd934007a400000128000000901ff8c6da2a57ce3580ed242c3571d9ec27f35ef436367a80bb500e65a97d49e48840fd757984eeee7ed4d7b675e2fa761378d270ceb582a96f4abbb7b90062747ab25a1e6fe505e7c3f2187f38c8996d773676380161053f7eb3f8c97387aa9c6aaaa30b97a546478668ac11ac2447f8845f1139820d679387fda7ae38627b95d2e1bc4a1ec6c50c02b6001ad67dd621000000901a0f38d26a55c352cacce5719aef19a35195aaa7a0660322ecef21d17cdcd4beb2e9fdf909522e68ead4974dbbc61ec727b7c192d649ba9402ef11bab69a4820c4ac8466678684a4561b79c607787a99d0ad4c9bcea79c0f6141417e2b2c08927e61c1412c6116fd383ce2b39f5284887477b1af8a5d4287b6e93cd9f6cc2b20bee631b52586254fca5b4eceadf0fc3b0000012800000090d454eb3e205fb713c0e1f57ac87f7486e283bf5373ab8dd7d6814b51e647c906668e53fdecf34d62c2577741f0326aa2770dbe8ddfa38feb113f296e8154da0bfb8744ffdc53fd9952fc2886e3c9ff4d9bec7fc40bf3b419f7cd8f9fdd94e5a80d858c55d3d8d6a78c4f38aafa2e57d344f3fa33066c02fcef95584f53fd18d77746707d7baf40f3d132e0762ff530da00000090447038e5cb74279855f930e8f7b7766db0fb5d9659e29f100a5edee666e93509b6304c0e244f64f622b85fe2edd61b7fea4129ee9877221583820e8624e32d92ab91f7f912589879ebe09ec84d6188f1afd24505c8d53576e2f4ceb6ec542df20ff8b21341611074c545fbb75dd8e4b9ace680bf1c22d34acd865dbe1ce75aa488b8c373d2601600ffdedd741f163ed500000ce4000001280000009045436ce2e6da0bbfec32c2a11b7de39d7dd557b2c44a87a827375716d3a0bfbf23e4e3027a036a17fe39610b53226ca60bc1a401c108e7a175a79639423d25e87c5bee44843faf52e06dfe9c5889e44696d84e60b00c808fc658cc1ba3a0380981f00a9b7e08844bbd7a30005ba8721b1933fb86fd11c4d51834fffcc1ab349f99bcda485368666b15f1e3668cc181f200000090bd229cf6d6f7d21631b59a23f3dcab0a9e2fd1bc8559a231695b6a5c26615528cf204d00046fb6fb2e67656576cbb6d72d194763c42e03a99b90950193d0d71c906007f18e3e1e3a7dc32ff538e16de9f4fb1ff8469289acb071318c67b9e99de9220af87f0936e67dc7dd73f06476d2c387fffde703d4375bc237c735801c71af114a06051621aead6dd13729d131990000012800000090b1095ccf7c01d057426cbf1f0b64a04461f96293107906aa032cecce60a80895415eaac9d968cf92b9bc23be2e4c28ad899b286877d856e516c45346416a54c7b851d3ee2310822c48ae58b6aa98d77214590692e544beffb4cd7db0b178bd4c73352d26295117d7fb3035e24c5a46375b0351068f8d13314c72c4791ae3ee6327bf1a69223068ebfbf3ee1162b05b3d00000090f9c41e0deba7b51b30183beee0fa118da199df57e7b64f7edabe514b9b054f84a8ac4a874b180c1173b428aede80f9065673f90cb90b50a75d45190411bca2802ec52d39a94964dc713f22e7a84e2b3951dc0147667b61153d4a7f05acc134188a20f930dbecaa1a6bf25d32efa1522651b47f92bd69e4c23a636a55111254efd05580201b50b964a1f32dc9025107a200000128000000903e89093271e6a69b711d07022e4e5e9c150a25620bd439d17551add63a0d8d884e45a3c44128ead9c2d3d8d2c3d4f92a39c8f93cb7578f1163966a8fbfc0e9c525c5d7f722a08d5c7352cb9a75b416603403f181652a7b06f8ca9600e23b4a965cdbd77ea9839d8e7e4d497c383e5e37682638f763ab3cead19ed526720b89d95366d5ff51b3f9c5ae658633f3e2c993000000906a4e1ed85756cd8c10680d71a1836879fac29cebf1d66a65cafca1ddb5b9ccf0c7eff289bdcce8b3dd23a1f904bb453359354d48579cc3fb3fbbf992a3f736154b6c8e1cb2e51c5e2c172cff4d5008dad02365cea9da1d63e00c042a9ba57e413c4a06d155fe9b9f86e262e97463597a82d7ef555baa2341426e0b7158829d50f9e4ecbe06444b6eeec16f96faf4550500000128000000903dc7fdc3162430d001f7977c0763f2ff678dcdf07c2f6a2485deeaf993ec94a2198d9ef36d7cd7f35081345641df105b6bd11a3491769f78c0d903ff1431a9e5dbe4018ab44cf0b9821ecb5ed32eb34ca80dffa898289893d917d9b1fefe265d6a7f8399c9daa180b1febcbc1c558d4746e5704d3405512a4fa1379925e58f33fa44731f43927a950a6c8babbf79a14700000090c596b4a820d0e7a8836b13d5e7f50bc9755865b70d1346e590ca091025a25e0add8c50137f8192b347f75bccce887e3f831d57d21252cab4b69dad4f17e1e0d280d147c23ab8bc57080c4812514ef05f63506743e267f89012fceb91c0688d6f5c434d4c5ff2ae87387e1a186b536e5bf6e98ed3291e5342ce9fa44c90cc5ba90387a4717d6dcb6e059145c1ce8764fa0000012800000090283d76ab2e5af53de1d18916e20f8b86bc6a20176941530f8619cc9cbc9fecc6a93b724f7fcee354a4fd6f195841ab11a75c89d33aeece8eec50e5fd4e546caabd8c04c6b1961a9fc37bc167fc31f3ebc1eb5d6dd77a1d04c733862b604dbfae14f6f9e69fb510ebf18bb64db753b0555b44b49f6fb37e41833c2cc1943c57394e0bd0dc3ce650c720e383a2de6f08fc000000900be60fd6de9a29388caf4f72b62772b80a503fd1449f8de61c72274e30ec13804f576b64345d7aedeff7af7d4b7ca95f03409036f473f35d5007585a2ae57ab94e234c195c07e0b5396f64211659a785e9a3ae4a697f5dca6a0a3ee2800208a107b12f40e5ec28cef8cd611add402aa2b64bf8938bcd1c2e4faebb54fa98cfae7b56b4a7797d5773a3b13808ebf2d3640000012800000090e1a2d111767837b0a5bd9ab4aa040837f01dc81fd1f3b4c94c577bc4334057561d356f081587fe288df0698fd3ca2d1be1fd4533a3d985a514d3b47a8f0e25c6e71b77a0f2a845a9292d016e16dea8c48597750ed24ec27955b749b8c647b1dad52191d4619762d90b395cd161201b5801587c46c623c9e9c85461a0998f13f32f3dabac687c6b37f0452793ec12029300000090339f31d769c14a357e7c98d6f5844e7c8a97ff122b25e0138d144d983c8219f971a67c20aebe049899c7ec09a3c7673ba857a507af1f5df87b53ce538385894b27c2e51f69ca75cb36656b09eaeccbffbea93c8af1dae1a5e8ab4c7c576c1f8521f27aae4d35c5bfb2868134d8dec61c60ebdb108b6f710c7e5ad7cf07026b0ab30df451dafb7d129075b4e2e29e87da0000012800000090446064bffca204655f9bcd32448d5281fc2ff2719cd87b3af607980fca826d2475cbb26176a5581312a871e1f3437f8b56e3e3424c050b0431daa7232ff0628d3c079dd7968229f7f4052650e2535473e346836f424308e4617e69233e04cdaeeb36f1952d6b42c278ae462f8c494d767a736ea0ca5eb4c7213413aa20a50b425b53e56c525fb4e4c9a4446ac4eddbb4000000908c5392f39dde50a945b2a726a59b76e677db424b16a2c17a7ae63c5b8a54db1a3ed78c150a97792402f186fbb8a6e093293ee00ff8b56cba7e772d89c79b87d48dcd17d436d11128b1f84ba989025fe5e25f731ab1fd99185783c13e2b180a344419a78577c541e4fda696c8463bff0b69cc80a23b3278f1149614cac7a019f43e484791680e168ea97e21cd5ec8bcc20000012800000090345b551d49681f065d63636d7c6e71cc73992b3b301f9591c577572b36b22e0fef0ac09ba7d7cfdd0f49a13739ef4314eb78de142191a75976123da2a49640249ccbc2af096e3900b4ca9bd4f09f52600c95f374ba110d6af27c2e1e4bc776af4577cf8cb55af20f521be2a0b9840a9e24c76aecbc0452ba6e07ff5762fd337ad72f9bebd508596940230d3a3648f54900000090ed47ff927b3a0d86080173815ca57523eb6dd5e261e587c375bd495e8bb376c15c14fe2f7086941bcee511a2845b43dce73c03193cb7f4069a18a228f310c87c2ea4c7023a863ebf36b3dd8f205b4cdf8bccfb99add2b6bb9b47057840ae0aad4147bc702c940e977f5be5fc96dbed0f578bd3c8fb05e73a83eca17aab10ff63f7781d4f42164a7ade252a819c7d8c0e0000012800000090a2acbcc47d3d3b5de0fd05c6e9a434a45f8df67d84caf7cc08438cc747261ad6f7d5182e8b4ff771f889ecff987fc81ab3fce9803f1f66ee6042e70026eca90cd8ee628a14cb2819b80062b9583aadcfb87a4b07b4758b162c4836d7e3c65d1406e4023e50cc17103ad1f23a9913eeb466c9626c3753860cbc973345674a43a3a9c3752420a8d4d0968d1dc8c051e0d000000090bec08567dd021f5e9de396dea483bef26c0fce90d2a9810cc0fc5cf979273566c8bcc1a5b7348f8c134c6836db56f06e1ec9bf2f22772212bbd346121021a3e06630212745414ca8ed09a68bcecae7ae5d657a5d0aeeb0787c601fd7ac9164c8dc78b475ab03c24fcd0d069e26386e24a339e387c4aa4aaee8a982836b9fc4f7da4043a4d98acc25a6d734034ffbad800000012800000090529e399a8cd2758e15cd6288caae8a4caf0825dc10342864bb3420a5599c42935ef54ca3c0755585de1d591be4d0a077bef0d0c7bf6a960ce038af375b4a2353866fcffc2e2ed3c9c126a996472b64259ba5bb465be59a2d08d91696dbc24909500d5840aae4a2af179bc4eb0a409b4b8472380e2f327252ed83255cfd2cfdbf6ffd43caea70a475fc62ef5f0f88aa5e00000090d57807dc2c257bb03cc5721539ee708345108fcf0cd13c91142f134800d242e8435773da485f21220c059830b664ed61fb5fbfd7a4815b7e33ab387b4c5a6b2cd5ab5bb7e22608bfdd5b53f95d58276dd44019bf08893e0b527c19c3a537cdf76bf68fee369d43c622e64a8567ef2cb84edd9ca30480d88489f1e31117c08c45e575ed09a075964611b419728712620c00000128000000905c9800416b095f77831bc877a355db545151d4ff58a8d9347dc9a982366aa6da5f9043e7b3320854635dd53d55cd2f283188eb27020f98ab4a2735b23d1f91df763e3272f4fbeb459ea74d93d007ca1dd1162e57b48161b27a2f02b35a7ef5998d4bc0e60b7acb4d31f781a1544d992688d47fa439a6e7e4ce9a8224e4e1c36ef85dd306d8fbdfe2246ef96c98ebd7cf000000904e9a6442af0ec3b24f0e4e472afb25a70dfa8159e23a861e53cd3756e54a9dc02e5a0e2112c1e00c8881ea179393700d41ce4009e93b8c5abcf4244cb2705507bac7d6bf6fbcc6c7e0023b0518765b6bebe0f278ba18c4f1e62102b4affefd24d94713ce05cc156a4a9a0908fe9632892c639af5c86c471a02aa3dae340f061a23b94ca42551f6b15919096dd2d80e87"; function setUp() public virtual { helper = new DecoderHelper(); @@ -68,17 +68,17 @@ contract DecoderTest is Test { assertEq(l2BlockNumber, 1, "Invalid block number"); assertEq( startStateHash, - 0xebfc0357e496d29717c182bae70315305a4bc802119c8705d521f3888d8ea687, + 0xffad71573f9ba1b8549c21040e8ca81c850b5c8616890c0b811525122993a909, "Invalid start state hash" ); assertEq( endStateHash, - 0x173011f69ad87076762a588bdaf7cccc9e5dccf2aed60b70b62773db03b64348, + 0x9b57972a8777a8a6ab8ec21766efe06d28d913326a5a64b138d041cc22e405ed, "Invalid end state hash" ); assertEq( publicInputsHash, - 0x067f07bdc550f37aec7514170b244cb7e0175bcc2fa988d46b69caba88a5d1e7, + 0x171bd65e55f7519128d5ebfb47e2d264b9abd3ba0a12b155da67cfbdc500bbc1, "Invalid public input hash" ); @@ -106,7 +106,7 @@ contract DecoderTest is Test { assertEq(l2BlockNumber, 1, "Invalid block number"); assertEq( diffRoot, - 0x807911d2bd073477866ec1b0f496db10464729d37023a8d97079c9c353a87dd5, + 0x72b5b74580b90c42a8089a222c9a450f69d35bf6cbefb5a0fe8f7403eeba8a07, "Invalid diff root/calldata hash" ); assertEq( @@ -116,17 +116,17 @@ contract DecoderTest is Test { ); assertEq( startStateHash, - 0xebfc0357e496d29717c182bae70315305a4bc802119c8705d521f3888d8ea687, + 0xffad71573f9ba1b8549c21040e8ca81c850b5c8616890c0b811525122993a909, "Invalid start state hash" ); assertEq( endStateHash, - 0x9e6828e46844a2977404d55da94e0c5529d011fcc33268d299be92c1c0a39b07, + 0x9a5cb854559b8847af8706564acfa34f73a963b6e889ad98ea0363258b916b89, "Invalid end state hash" ); assertEq( publicInputsHash, - 0x02641bcc168bf5a5d9a14cd74535aeba31f6cf8bfc93af8d0db0d2a0d5eab7f0, + 0x28bf184e40f1b56225120f46d0c05f49c58453e5a9851caa2414f95ab2f1af63, "Invalid public input hash" ); From 2167ae9e5c21ea765ec429908689059e4c894370 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:44:26 +0000 Subject: [PATCH 27/58] fix: lint --- .../archiver/src/archiver/archiver.ts | 2 +- .../aztec-node/src/aztec-node/server.ts | 7 +-- .../src/aztec_rpc_server/aztec_rpc_server.ts | 48 ++++++++-------- yarn-project/circuits.js/src/abis/abis.ts | 24 ++++---- .../structs/kernel/combined_constant_data.ts | 6 +- .../circuits.js/src/tests/factories.ts | 2 +- .../block_builder/solo_block_builder.test.ts | 1 - .../src/block_builder/solo_block_builder.ts | 33 +++++------ .../src/sequencer/public_processor.ts | 5 +- .../src/sequencer/sequencer.ts | 4 +- .../sequencer-client/src/sequencer/utils.ts | 20 +++++-- .../merkle_tree_operations_facade.ts | 2 +- .../world-state/src/world-state-db/index.ts | 5 +- .../src/world-state-db/merkle_trees.ts | 56 +++++++++++-------- 14 files changed, 122 insertions(+), 93 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index fe4cba1e615..f9d42b65a51 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -275,7 +275,7 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource public async getL2Block(number: number): Promise { // TODO CLEAN UP if (number < 0) { - number = this.store.getBlocksLength(); + number = this.store.getBlocksLength(); if (number === 0) { return Promise.resolve(undefined); } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 8a1651a7c13..3e5d5266071 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -121,7 +121,7 @@ export class AztecNodeService implements AztecNode { * @param number - The block number being requested. * @returns The blocks requested. */ - public async getBlock(number: number): Promise{ + public async getBlock(number: number): Promise { return await this.blockSource.getL2Block(number); } @@ -196,14 +196,13 @@ export class AztecNodeService implements AztecNode { * @param tx - The transaction to be submitted. */ public async sendTx(tx: Tx) { - // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value - CAN WE remove this i think the + // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value - CAN WE remove this i think the // kernel already supplies it if (tx.data.constants.historicTreeRoots.isEmpty()) { - // TODO: make this more robust - base case is for the first rollup const blockNumber = await this.blockSource.getBlockHeight(); const prevBlock = await this.getBlock(blockNumber); - const globals = prevBlock ? prevBlock.globalVariables: GlobalVariables.empty(); + const globals = prevBlock ? prevBlock.globalVariables : GlobalVariables.empty(); tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest(), globals); } this.log.info(`Received tx ${await tx.getTxHash()}`); diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 8ee70d15c31..63fffe970a9 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -14,6 +14,7 @@ import { PrivateKey, PublicKey, } from '@aztec/circuits.js'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { encodeArguments } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; @@ -48,7 +49,6 @@ import { KernelOracle } from '../kernel_oracle/index.js'; import { KernelProver } from '../kernel_prover/kernel_prover.js'; import { getAcirSimulator } from '../simulator/index.js'; import { Synchroniser } from '../synchroniser/index.js'; -import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A remote Aztec RPC Client implementation. @@ -161,9 +161,9 @@ export class AztecRPCServer implements AztecRPC { public async getBlock(blockNumber: number): Promise { // If a negative block number is provided the current block height is fetched. - if (blockNumber < 0){ + if (blockNumber < 0) { blockNumber = await this.node.getBlockHeight(); - + // TODO: FIX HACK if (blockNumber == 0) return undefined; } @@ -188,7 +188,7 @@ export class AztecRPCServer implements AztecRPC { const newContract = deployedContractAddress ? await this.db.getContract(deployedContractAddress) : undefined; const tx = await this.#simulateAndProve(txRequest, newContract); - console.log(tx); + console.log(tx); await this.db.addTx( TxDao.from({ @@ -345,13 +345,17 @@ export class AztecRPCServer implements AztecRPC { }; } - async #simulate(txRequest: TxExecutionRequest, prevBlockData: CombinedHistoricTreeRoots, contractDataOracle?: ContractDataOracle, ) { + async #simulate( + txRequest: TxExecutionRequest, + prevBlockData: CombinedHistoricTreeRoots, + contractDataOracle?: ContractDataOracle, + ) { // TODO - Pause syncing while simulating. if (!contractDataOracle) { contractDataOracle = new ContractDataOracle(this.db, this.node); } - const { contractAddress, functionAbi, portalContract} = await this.#getSimulationParameters( + const { contractAddress, functionAbi, portalContract } = await this.#getSimulationParameters( txRequest, contractDataOracle, ); @@ -360,7 +364,13 @@ export class AztecRPCServer implements AztecRPC { try { this.log('Executing simulator...'); - const result = await simulator.run(txRequest, functionAbi, contractAddress, portalContract, prevBlockData.privateHistoricTreeRoots); + const result = await simulator.run( + txRequest, + functionAbi, + contractAddress, + portalContract, + prevBlockData.privateHistoricTreeRoots, + ); this.log('Simulation completed!'); return result; @@ -375,10 +385,15 @@ export class AztecRPCServer implements AztecRPC { * Returns the simulation result containing the outputs of the unconstrained function. * * @param execRequest - The transaction request object containing the target contract and function data. + * @param prevBlockData - All data required to reconstruct the previous block hash. // TODO: Maybe just pass in one value for this instead of recomputing everywhere? Cache at the beginning? * @param contractDataOracle - Optional instance of ContractDataOracle for fetching and caching contract information. * @returns The simulation result containing the outputs of the unconstrained function. */ - async #simulateUnconstrained(execRequest: ExecutionRequest, prevBlockData: CombinedHistoricTreeRoots = CombinedHistoricTreeRoots.empty(), contractDataOracle?: ContractDataOracle) { + async #simulateUnconstrained( + execRequest: ExecutionRequest, + prevBlockData: CombinedHistoricTreeRoots = CombinedHistoricTreeRoots.empty(), + contractDataOracle?: ContractDataOracle, + ) { if (!contractDataOracle) { contractDataOracle = new ContractDataOracle(this.db, this.node); } @@ -420,15 +435,9 @@ export class AztecRPCServer implements AztecRPC { //TODO(MADDIAA) MAYBE WE SHOULD GET THE LATEST BLOCK TREE ROOTS HERE AND PASS THEM DOWN EVERYWHERE? - - - - - - // Add values that allow us to reconstruct the block hash const wasm = await CircuitsWasm.get(); - const latestBlock = await this.getBlock(-1) + const latestBlock = await this.getBlock(-1); const latestGlobals = latestBlock?.globalVariables ?? GlobalVariables.empty(); const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); const treeRoots = this.db.getTreeRoots(); @@ -443,28 +452,23 @@ export class AztecRPCServer implements AztecRPC { Fr.ZERO, ), treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], - prevBlockGlobalVariablesHash + prevBlockGlobalVariablesHash, ); - const contractDataOracle = new ContractDataOracle(this.db, this.node); // TODO: maybe could put above in this kernel oracle const kernelOracle = new KernelOracle(contractDataOracle, this.node); - const executionResult = await this.#simulate(txExecutionRequest, historicTreeRoots, contractDataOracle); + const executionResult = await this.#simulate(txExecutionRequest, historicTreeRoots, contractDataOracle); const kernelProver = new KernelProver(kernelOracle); this.log(`Executing kernel prover...`); const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult); this.log('Proof completed!'); - // TODO: FIX HACK< OVERWRITING THE ROOTS HERE publicInputs.constants.historicTreeRoots = historicTreeRoots; - - - const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; const encryptedLogs = new TxL2Logs(collectEncryptedLogs(executionResult)); diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index b65dd66c021..5fbf47ed8cf 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -334,8 +334,18 @@ export function computeBlockHash( ); } - -export function computeBlockHashWithGloabalsHash( +/** + * Computes the block hash given the blocks globals and roots. + * @param wasm - A module providing low-level wasm access. + * @param globalsHash - The global variables hash to put into the block hash. + * @param privateDataTree - The root of the private data tree. + * @param nullifierTreeRoot - The root of the nullifier tree. + * @param contractTreeRoot - The root of the contract tree. + * @param l1ToL2DataTreeRoot - The root of the l1 to l2 data tree. + * @param publicDataTreeRoot - The root of the public data tree. + * @returns The block hash. + */ +export function computeBlockHashWithGlobalsHash( wasm: IWasmModule, globalsHash: Fr, privateDataTreeRoot: Fr, @@ -362,15 +372,9 @@ export function computeBlockHashWithGloabalsHash( * @param globals - The global variables to put into the block hash. * @returns The globals hash. */ -export function computeGlobalsHash( - wasm: IWasmModule, - globals: GlobalVariables, -): Fr { +export function computeGlobalsHash(wasm: IWasmModule, globals: GlobalVariables): Fr { wasm.call('pedersen__init'); - return abisComputeGlobalsHash( - wasm, - globals, - ); + return abisComputeGlobalsHash(wasm, globals); } const ARGS_HASH_CHUNK_SIZE = 32; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 8643f88ee0d..074eccec344 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -129,7 +129,11 @@ export class CombinedHistoricTreeRoots { } isEmpty() { - return this.privateHistoricTreeRoots.isEmpty() && this.publicDataTreeRoot.isZero() && this.prevGlobalVariablesHash.isZero(); + return ( + this.privateHistoricTreeRoots.isEmpty() && + this.publicDataTreeRoot.isZero() && + this.prevGlobalVariablesHash.isZero() + ); } static empty() { diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index ecfea7406fb..6e17c4bc22d 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -122,7 +122,7 @@ export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeR * @returns A combined historic tree roots object. */ export function makeCombinedHistoricTreeRoots(seed: number, globalsHash?: Fr): CombinedHistoricTreeRoots { - return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), globalsHash ?? fr(seed + 5) , fr(seed + 6)); + return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), globalsHash ?? fr(seed + 5), fr(seed + 6)); } /** diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 174e5bf9d00..f554ff1dc2a 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -339,7 +339,6 @@ describe('sequencer/solo_block_builder', () => { processedTx.data.end.encryptedLogsHash = to2Fields(L2Block.computeKernelLogsHash(processedTx.encryptedLogs)); processedTx.data.end.unencryptedLogsHash = to2Fields(L2Block.computeKernelLogsHash(processedTx.unencryptedLogs)); - return processedTx; }; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index deb8ed827c0..0c1aad8b4e6 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -26,7 +26,7 @@ import { VerificationKey, makeTuple, } from '@aztec/circuits.js'; -import { computeBlockHash, computeBlockHashWithGloabalsHash, computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeBlockHashWithGlobalsHash, computeContractLeaf } from '@aztec/circuits.js/abis'; import { toFriendlyJSON } from '@aztec/circuits.js/utils'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -107,7 +107,6 @@ export class SoloBlockBuilder implements BlockBuilder { ].map(tree => this.getTreeSnapshot(tree)), ); - // Check txs are good for processing this.validateTxs(txs); @@ -543,17 +542,21 @@ export class SoloBlockBuilder implements BlockBuilder { return new MembershipWitness(height, index, assertLength(path.toFieldArray(), height)); } - protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { const historicTreeRoots = tx.data.constants.historicTreeRoots; - const {privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot} = historicTreeRoots.privateHistoricTreeRoots; + const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = + historicTreeRoots.privateHistoricTreeRoots; const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHashWithGloabalsHash(wasm, historicTreeRoots.prevGlobalVariablesHash, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot, historicTreeRoots.publicDataTreeRoot); - return this.getMembershipWitnessFor( - blockHash, - MerkleTreeId.BLOCKS_TREE, - HISTORIC_BLOCKS_TREE_HEIGHT, + const blockHash = computeBlockHashWithGlobalsHash( + wasm, + historicTreeRoots.prevGlobalVariablesHash, + privateDataTreeRoot, + nullifierTreeRoot, + contractTreeRoot, + l1ToL2MessagesTreeRoot, + historicTreeRoots.publicDataTreeRoot, ); + return this.getMembershipWitnessFor(blockHash, MerkleTreeId.BLOCKS_TREE, HISTORIC_BLOCKS_TREE_HEIGHT); } protected async getConstantBaseRollupData(globalVariables: GlobalVariables): Promise { @@ -726,18 +729,12 @@ export class SoloBlockBuilder implements BlockBuilder { ), lowNullifierMembershipWitness: lowNullifierMembershipWitnesses, kernelData: [this.getKernelDataFor(left), this.getKernelDataFor(right)], - historicContractsTreeRootMembershipWitnesses: [ - mockContractMembershipWitnesses, - mockContractMembershipWitnesses - ], + historicContractsTreeRootMembershipWitnesses: [mockContractMembershipWitnesses, mockContractMembershipWitnesses], historicPrivateDataTreeRootMembershipWitnesses: [ mockPrivateDataMembershipWitnesses, - mockPrivateDataMembershipWitnesses - ], - historicL1ToL2MsgTreeRootMembershipWitnesses: [ - mockL1ToL2MembershipWitnesses, - mockL1ToL2MembershipWitnesses + mockPrivateDataMembershipWitnesses, ], + historicL1ToL2MsgTreeRootMembershipWitnesses: [mockL1ToL2MembershipWitnesses, mockL1ToL2MembershipWitnesses], historicBlocksTreeRootMembershipWitnesses: [ await this.getHistoricTreesMembershipWitnessFor(left), await this.getHistoricTreesMembershipWitnessFor(right), diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 41f41d10cbe..5c654c15fcf 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -108,7 +108,10 @@ export class PublicProcessor { * @param currentGlobalVariables - The global variables for this block. * @returns A processed tx with empty data. */ - public async makeEmptyProcessedTx(prevGlobals: GlobalVariables, currentGlobalVariables: GlobalVariables): Promise { + public async makeEmptyProcessedTx( + prevGlobals: GlobalVariables, + currentGlobalVariables: GlobalVariables, + ): Promise { const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db, prevGlobals); return makeEmptyProcessedTx(historicTreeRoots, currentGlobalVariables.chainId, currentGlobalVariables.version); } diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 1684161b199..fba06da579b 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -164,12 +164,12 @@ export class Sequencer { // Build the new block by running the rollup circuits this.log(`Assembling block with txs ${processedTxs.map(tx => tx.hash).join(', ')}`); - + // Get the prev globals from the block source // TODO CLEANUP const prevBlock = await this.l2BlockSource.getL2Block(-1); - const prevGlobals = prevBlock ? prevBlock.globalVariables: GlobalVariables.empty(); + const prevGlobals = prevBlock ? prevBlock.globalVariables : GlobalVariables.empty(); const emptyTx = await processor.makeEmptyProcessedTx(prevGlobals, globalVariables); const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, globalVariables); diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 81a6d983f07..d7e066d7c26 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -1,16 +1,24 @@ -import { CircuitsWasm, CombinedHistoricTreeRoots, Fr, GlobalVariables, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { + CircuitsWasm, + CombinedHistoricTreeRoots, + Fr, + GlobalVariables, + PrivateHistoricTreeRoots, +} from '@aztec/circuits.js'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations } from '@aztec/world-state'; -import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty()) { +export async function getCombinedHistoricTreeRoots( + db: MerkleTreeOperations, + prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty(), +) { const wasm = await CircuitsWasm.get(); const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); - return new CombinedHistoricTreeRoots( new PrivateHistoricTreeRoots( Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PRIVATE_DATA_TREE)).root), @@ -20,7 +28,7 @@ export async function getCombinedHistoricTreeRoots(db: MerkleTreeOperations, pre Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.BLOCKS_TREE)).root), Fr.ZERO, ), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE)).root), - prevGlobalsHash, + Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE)).root), + prevGlobalsHash, ); } diff --git a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts index 610a2f86d43..c9621bd7598 100644 --- a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts +++ b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts @@ -1,8 +1,8 @@ +import { GlobalVariables } from '@aztec/circuits.js'; import { LowLeafWitnessData } from '@aztec/merkle-tree'; import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types'; import { CurrentCommitmentTreeRoots, LeafData, MerkleTreeDb, MerkleTreeOperations, TreeInfo } from '../index.js'; -import { GlobalVariables } from '@aztec/circuits.js'; /** * Wraps a MerkleTreeDbOperations to call all functions with a preset includeUncommitted flag. diff --git a/yarn-project/world-state/src/world-state-db/index.ts b/yarn-project/world-state/src/world-state-db/index.ts index 4c6f8a50f91..6c6370311f2 100644 --- a/yarn-project/world-state/src/world-state-db/index.ts +++ b/yarn-project/world-state/src/world-state-db/index.ts @@ -171,8 +171,9 @@ export interface MerkleTreeOperations { getLeafValue(treeId: MerkleTreeId, index: bigint): Promise; /** - * Inserts into the roots trees (CONTRACT_TREE_ROOTS_TREE, PRIVATE_DATA_TREE_ROOTS_TREE, L1_TO_L2_MESSAGES_TREE_ROOTS_TREE) - * the current roots of the corresponding trees (CONTRACT_TREE, PRIVATE_DATA_TREE, L1_TO_L2_MESSAGES_TREE). + * Inserts the new block hash into the new block hashes tree. + * This includes all of the current roots of all of the data trees and the current blocks global vars. + * @param globalVariables - The global variables to insert into the block hash. */ // TODO: i currently dont love that the global variabels are leaked in this abstraction updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise; diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index f059597c857..c7206b872f4 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -13,6 +13,7 @@ import { PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; +import { computeBlockHash } from '@aztec/circuits.js/abis'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IWasmModule } from '@aztec/foundation/wasm'; @@ -42,7 +43,6 @@ import { PublicTreeId, TreeInfo, } from './index.js'; -import { computeBlockHash, computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A convenience class for managing multiple merkle trees. @@ -193,19 +193,18 @@ export class MerkleTrees implements MerkleTreeDb { const wasm = await CircuitsWasm.get(); // TODO maybe use the same pattern as function below - const treePromises = ([ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - ] as const).map(tree => this.getTreeInfo(tree, includeUncommitted)) - const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); - - const blockHash = computeBlockHash(wasm, globals, trees[0], trees[1], trees[2],trees[3], trees[4]); - console.log(globals); + const treePromises = ( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + ] as const + ).map(tree => this.getTreeInfo(tree, includeUncommitted)); + const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); - console.log("ADDING block hash: ", blockHash.toString()); + const blockHash = computeBlockHash(wasm, globals, trees[0], trees[1], trees[2], trees[3], trees[4]); await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } @@ -556,19 +555,30 @@ export class MerkleTrees implements MerkleTreeDb { } // Sync the blocks tree. - const treeRoots = (await Promise.all([ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - ].map( tree => this.trees[tree].getRoot(true)))).map( root => Fr.fromBuffer(root)); + const treeRoots = ( + await Promise.all( + [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, + ].map(tree => this.trees[tree].getRoot(true)), + ) + ).map(root => Fr.fromBuffer(root)); const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHash(wasm, l2Block.globalVariables, treeRoots[0], treeRoots[1], treeRoots[2], treeRoots[3], treeRoots[4]); + const blockHash = computeBlockHash( + wasm, + l2Block.globalVariables, + treeRoots[0], + treeRoots[1], + treeRoots[2], + treeRoots[3], + treeRoots[4], + ); // Add the block to the historic blocks tree - await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]) - + await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); await this._commit(); } From 9ee98d5f8c38b6f956929d8cd4dd7a7880ae5007 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 19:53:57 +0000 Subject: [PATCH 28/58] feat: I have become death, destroyer of worlds --- .../abis/rollup/base/base_rollup_inputs.hpp | 45 +-- .../abis/rollup/constant_rollup_data.hpp | 16 +- .../abis/rollup/root/root_rollup_inputs.hpp | 22 -- .../base/native_base_rollup_circuit.cpp | 4 - .../src/aztec3/circuits/rollup/root/.test.cpp | 277 ++++++++---------- .../root/native_root_rollup_circuit.cpp | 42 --- .../circuits/rollup/test_utils/utils.cpp | 83 +----- .../src/aztec-node/http-node.test.ts | 3 - .../aztec-node/src/aztec-node/http-node.ts | 3 - .../aztec-node/src/aztec-node/server.ts | 3 - .../src/synchroniser/synchroniser.test.ts | 3 - .../src/synchroniser/synchroniser.ts | 3 - .../src/rollup/rollup_wasm_wrapper.test.ts | 3 - .../src/structs/rollup/base_rollup.ts | 44 --- .../src/structs/rollup/root_rollup.ts | 26 -- .../circuits.js/src/tests/factories.ts | 49 +--- .../block_builder/solo_block_builder.test.ts | 16 - .../src/block_builder/solo_block_builder.ts | 49 ---- yarn-project/types/src/l2_block.ts | 66 ----- yarn-project/types/src/merkle_tree_id.ts | 13 +- .../server_world_state_synchroniser.test.ts | 6 - .../src/world-state-db/merkle_trees.ts | 27 -- 22 files changed, 159 insertions(+), 644 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp index 3ffcda6a4aa..2e2aa1abcc6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp @@ -14,37 +14,31 @@ namespace aztec3::circuits::abis { template struct BaseRollupInputs { using fr = typename NCT::fr; - std::array, 2> kernel_data; + std::array, 2> kernel_data{}; - AppendOnlyTreeSnapshot start_private_data_tree_snapshot; - AppendOnlyTreeSnapshot start_nullifier_tree_snapshot; - AppendOnlyTreeSnapshot start_contract_tree_snapshot; - fr start_public_data_tree_root; - AppendOnlyTreeSnapshot start_historic_blocks_tree_snapshot; + AppendOnlyTreeSnapshot start_private_data_tree_snapshot{}; + AppendOnlyTreeSnapshot start_nullifier_tree_snapshot{}; + AppendOnlyTreeSnapshot start_contract_tree_snapshot{}; + fr start_public_data_tree_root{}; + AppendOnlyTreeSnapshot start_historic_blocks_tree_snapshot{}; - std::array, 2 * MAX_NEW_NULLIFIERS_PER_TX> low_nullifier_leaf_preimages; + std::array, 2 * MAX_NEW_NULLIFIERS_PER_TX> low_nullifier_leaf_preimages{}; std::array, 2 * MAX_NEW_NULLIFIERS_PER_TX> - low_nullifier_membership_witness; + low_nullifier_membership_witness{}; // For inserting the new subtrees into their respective trees: // Note: the insertion leaf index can be derived from the above snapshots' `next_available_leaf_index` values. - std::array new_commitments_subtree_sibling_path; - std::array new_nullifiers_subtree_sibling_path; - std::array new_contracts_subtree_sibling_path; + std::array new_commitments_subtree_sibling_path{}; + std::array new_nullifiers_subtree_sibling_path{}; + std::array new_contracts_subtree_sibling_path{}; std::array, 2 * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX> - new_public_data_update_requests_sibling_paths; + new_public_data_update_requests_sibling_paths{}; std::array, 2 * MAX_PUBLIC_DATA_READS_PER_TX> - new_public_data_reads_sibling_paths; + new_public_data_reads_sibling_paths{}; - std::array, 2> - historic_private_data_tree_root_membership_witnesses; - std::array, 2> - historic_contract_tree_root_membership_witnesses; - std::array, 2> - historic_l1_to_l2_msg_tree_root_membership_witnesses; - std::array, 2> historic_blocks_tree_root_membership_witnesses; + std::array, 2> historic_blocks_tree_root_membership_witnesses{}; - ConstantRollupData constants; + ConstantRollupData constants{}; // for serialization, update with new fields MSGPACK_FIELDS(kernel_data, @@ -60,9 +54,6 @@ template struct BaseRollupInputs { new_contracts_subtree_sibling_path, new_public_data_update_requests_sibling_paths, new_public_data_reads_sibling_paths, - historic_private_data_tree_root_membership_witnesses, - historic_contract_tree_root_membership_witnesses, - historic_l1_to_l2_msg_tree_root_membership_witnesses, historic_blocks_tree_root_membership_witnesses, constants); bool operator==(BaseRollupInputs const&) const = default; @@ -96,12 +87,6 @@ template std::ostream& operator<<(std::ostream& os, BaseRollupInp << obj.new_public_data_update_requests_sibling_paths << "\n" << "new_state_reads_sibling_paths:\n" << obj.new_public_data_reads_sibling_paths << "\n" - << "historic_private_data_tree_root_membership_witnesses:\n" - << obj.historic_private_data_tree_root_membership_witnesses << "\n" - << "historic_contract_tree_root_membership_witnesses:\n" - << obj.historic_contract_tree_root_membership_witnesses << "\n" - << "historic_l1_to_l2_msg_tree_root_membership_witnesses:\n" - << obj.historic_l1_to_l2_msg_tree_root_membership_witnesses << "\n" << "historic_blocks_tree_root_membership_witnesses:\n" << obj.historic_blocks_tree_root_membership_witnesses << "\n" << "constants:\n" diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp index 93f3eab4a5b..2a4cc844699 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/constant_rollup_data.hpp @@ -11,9 +11,6 @@ template struct ConstantRollupData { using fr = typename NCT::fr; // The very latest roots as at the very beginning of the entire rollup: - AppendOnlyTreeSnapshot start_tree_of_historic_private_data_tree_roots_snapshot{}; - AppendOnlyTreeSnapshot start_tree_of_historic_contract_tree_roots_snapshot{}; - AppendOnlyTreeSnapshot start_tree_of_historic_l1_to_l2_msg_tree_roots_snapshot{}; AppendOnlyTreeSnapshot start_historic_blocks_tree_roots_snapshot{}; // Some members of this struct tbd: @@ -24,10 +21,7 @@ template struct ConstantRollupData { GlobalVariables global_variables{}; - MSGPACK_FIELDS(start_tree_of_historic_private_data_tree_roots_snapshot, - start_tree_of_historic_contract_tree_roots_snapshot, - start_tree_of_historic_l1_to_l2_msg_tree_roots_snapshot, - start_historic_blocks_tree_roots_snapshot, + MSGPACK_FIELDS(start_historic_blocks_tree_roots_snapshot, private_kernel_vk_tree_root, public_kernel_vk_tree_root, base_rollup_vk_hash, @@ -39,13 +33,7 @@ template struct ConstantRollupData { template std::ostream& operator<<(std::ostream& os, ConstantRollupData const& obj) { - return os << "start_tree_of_historic_private_data_tree_roots_snapshot:\n " - << obj.start_tree_of_historic_private_data_tree_roots_snapshot << "\n" - << "start_tree_of_historic_contract_tree_roots_snapshot:\n" - << obj.start_tree_of_historic_contract_tree_roots_snapshot << "\n" - << "tree_of_historic_l1_to_l2_msg_tree_roots_snapshot:\n" - << obj.start_tree_of_historic_l1_to_l2_msg_tree_roots_snapshot << "\n" - << "start_historic_blocks_tree_roots_snapshot:\n" + return os << "start_historic_blocks_tree_roots_snapshot:\n" << obj.start_historic_blocks_tree_roots_snapshot << "\n" << "private_kernel_vk_tree_root: " << obj.private_kernel_vk_tree_root << "\n" << "public_kernel_vk_tree_root: " << obj.public_kernel_vk_tree_root << "\n" diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp index 8a48deb5002..33ab4134ef8 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp @@ -18,16 +18,11 @@ template struct RootRollupInputs { // All below are shared between the base and merge rollups std::array, 2> previous_rollup_data{}; - std::array new_historic_private_data_tree_root_sibling_path{}; - std::array new_historic_contract_tree_root_sibling_path{}; - // inputs required to process l1 to l2 messages std::array l1_to_l2_messages{}; std::array new_l1_to_l2_message_tree_root_sibling_path{}; - std::array new_historic_l1_to_l2_message_roots_tree_sibling_path{}; AppendOnlyTreeSnapshot start_l1_to_l2_message_tree_snapshot{}; - AppendOnlyTreeSnapshot start_historic_tree_l1_to_l2_message_tree_roots_snapshot{}; // inputs required to add the block hash AppendOnlyTreeSnapshot start_historic_blocks_tree_snapshot{}; @@ -41,13 +36,9 @@ template void read(uint8_t const*& it, RootRollupInputs& obj using serialize::read; read(it, obj.previous_rollup_data); - read(it, obj.new_historic_private_data_tree_root_sibling_path); - read(it, obj.new_historic_contract_tree_root_sibling_path); read(it, obj.l1_to_l2_messages); read(it, obj.new_l1_to_l2_message_tree_root_sibling_path); - read(it, obj.new_historic_l1_to_l2_message_roots_tree_sibling_path); read(it, obj.start_l1_to_l2_message_tree_snapshot); - read(it, obj.start_historic_tree_l1_to_l2_message_tree_roots_snapshot); read(it, obj.start_historic_blocks_tree_snapshot); read(it, obj.new_historic_blocks_tree_sibling_path); }; @@ -57,13 +48,9 @@ template void write(std::vector& buf, RootRollupInputs void write(std::vector& buf, RootRollupInputs std::ostream& operator<<(std::ostream& os, RootRollupInputs const& obj) { return os << "previous_rollup_data: " << obj.previous_rollup_data << "\n" - << "new_historic_private_data_tree_roots: " << obj.new_historic_private_data_tree_root_sibling_path - << "\n" - << "new_historic_contract_tree_roots: " << obj.new_historic_contract_tree_root_sibling_path << "\n" << "new_l1_to_l2_messages: " << obj.l1_to_l2_messages << "\n" - << "new_l1_to_l2_message_tree_root_sibling_path: " << obj.new_l1_to_l2_message_tree_root_sibling_path - << "\n" - << "new_historic_l1_to_l2_message_roots_tree_sibling_path: " - << obj.new_historic_l1_to_l2_message_roots_tree_sibling_path << "\n" << "start_l1_to_l2_message_tree_snapshot: " << obj.start_l1_to_l2_message_tree_snapshot << "\n" - << "start_historic_tree_l1_to_l2_message_tree_roots_snapshot: " - << obj.start_historic_tree_l1_to_l2_message_tree_roots_snapshot << "\n" << "start_historic_blocks_tree_snapshot: " << obj.start_historic_blocks_tree_snapshot << "\n" << "new_historic_blocks_tree_sibling_path: " << obj.new_historic_blocks_tree_sibling_path << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 120a22f8809..ab43014992c 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -137,8 +137,6 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas // against the historical root provided in the rollup constants auto historic_root = baseRollupInputs.constants.start_historic_blocks_tree_roots_snapshot.root; - info("expected root: ", historic_root); - for (size_t i = 0; i < 2; i++) { // Rebuild the block hash auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.historic_tree_roots; @@ -160,8 +158,6 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas abis::MembershipWitness const historic_root_witness = baseRollupInputs.historic_blocks_tree_root_membership_witnesses[i]; - info("historic root witness: ", historic_root_witness.leaf_index, " ", historic_root_witness.sibling_path); - check_membership( builder, previous_block_hash, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp index f1dbb5f5b08..2c2bd576927 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp @@ -160,164 +160,123 @@ TEST_F(root_rollup_tests, native_check_block_hashes_empty_blocks) run_cbind(inputs, outputs, true); } -TEST_F(root_rollup_tests, native_root_missing_nullifier_logic) -{ - utils::DummyCircuitBuilder builder = - utils::DummyCircuitBuilder("root_rollup_tests__native_root_missing_nullifier_logic"); - - MemoryStore private_data_tree_store; - MerkleTree private_data_tree = MerkleTree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); - - MemoryStore contract_tree_store; - MerkleTree contract_tree = MerkleTree(contract_tree_store, CONTRACT_TREE_HEIGHT); - - MemoryStore historic_private_data_tree_store; - MerkleTree historic_private_data_tree = - MerkleTree(historic_private_data_tree_store, PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore historic_contract_tree_store; - MerkleTree historic_contract_tree = MerkleTree(historic_contract_tree_store, CONTRACT_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore l1_to_l2_messages_tree_store; - MerkleTree l1_to_l2_messages_tree = MerkleTree(l1_to_l2_messages_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); - - MemoryStore historic_l1_to_l2_messages_tree_store; - MerkleTree historic_l1_to_l2_tree = - MerkleTree(historic_l1_to_l2_messages_tree_store, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); - - // Historic trees are initialised with an empty root at position 0. - historic_private_data_tree.update_element(0, private_data_tree.root()); - historic_contract_tree.update_element(0, contract_tree.root()); - historic_l1_to_l2_tree.update_element(0, l1_to_l2_messages_tree.root()); - - std::array kernels = { - get_empty_kernel(), get_empty_kernel(), get_empty_kernel(), get_empty_kernel() - }; - std::array l1_to_l2_messages = get_empty_l1_to_l2_messages(); - - // Create commitments - for (uint8_t kernel_j = 0; kernel_j < 4; kernel_j++) { - std::array new_commitments; - for (uint8_t commitment_k = 0; commitment_k < MAX_NEW_COMMITMENTS_PER_TX; commitment_k++) { - auto val = fr(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k + 1); - new_commitments[commitment_k] = val; - private_data_tree.update_element(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k, val); - } - kernels[kernel_j].public_inputs.end.new_commitments = new_commitments; - - std::array new_l2_to_l1_messages; - for (uint8_t i = 0; i < MAX_NEW_L2_TO_L1_MSGS_PER_TX; i++) { - auto val = fr(kernel_j * MAX_NEW_L2_TO_L1_MSGS_PER_TX + i + 1); - new_l2_to_l1_messages[i] = val; - } - kernels[kernel_j].public_inputs.end.new_l2_to_l1_msgs = new_l2_to_l1_messages; - } - - // @todo @LHerskind: Add nullifiers - // @todo @LHerskind: Add public data writes - - // Contract tree - NewContractData const new_contract = { - .contract_address = fr(1), - .portal_contract_address = fr(3), - .function_tree_root = fr(2), - }; - // Update contract tree - contract_tree.update_element(2, new_contract.hash()); - kernels[2].public_inputs.end.new_contracts[0] = new_contract; - - // l1 to l2 messages snapshot - AppendOnlyTreeSnapshot const start_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), - .next_available_leaf_index = 0 }; - - // The start historic data snapshots - AppendOnlyTreeSnapshot const start_historic_data_tree_snapshot = { .root = historic_private_data_tree.root(), - .next_available_leaf_index = 1 }; - AppendOnlyTreeSnapshot const start_historic_contract_tree_snapshot = { .root = historic_contract_tree.root(), - .next_available_leaf_index = 1 }; - AppendOnlyTreeSnapshot const start_historic_l1_to_l2_tree_snapshot = { .root = historic_l1_to_l2_tree.root(), - .next_available_leaf_index = 1 }; - - // Create 16 empty l1 to l2 messages, and update the l1_to_l2 messages tree - for (size_t i = 0; i < l1_to_l2_messages.size(); i++) { - l1_to_l2_messages_tree.update_element(i, l1_to_l2_messages[i]); - } - - // Insert the newest data root into the historic tree - historic_private_data_tree.update_element(1, private_data_tree.root()); - historic_contract_tree.update_element(1, contract_tree.root()); - historic_l1_to_l2_tree.update_element(1, l1_to_l2_messages_tree.root()); - - // Compute the end snapshot - AppendOnlyTreeSnapshot const end_historic_data_tree_snapshot = { .root = historic_private_data_tree.root(), - .next_available_leaf_index = 2 }; - AppendOnlyTreeSnapshot const end_historic_contract_tree_snapshot = { .root = historic_contract_tree.root(), - .next_available_leaf_index = 2 }; - AppendOnlyTreeSnapshot const end_historic_l1_to_l2_tree_snapshot = { .root = historic_l1_to_l2_tree.root(), - .next_available_leaf_index = 2 }; - AppendOnlyTreeSnapshot const end_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), - .next_available_leaf_index = - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP }; - - RootRollupInputs rootRollupInputs = get_root_rollup_inputs(builder, kernels, l1_to_l2_messages); - RootRollupPublicInputs outputs = - aztec3::circuits::rollup::native_root_rollup::root_rollup_circuit(builder, rootRollupInputs); - - // Check private data trees - ASSERT_EQ( - outputs.start_private_data_tree_snapshot, - rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_private_data_tree_snapshot); - ASSERT_EQ( - outputs.end_private_data_tree_snapshot, - rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_private_data_tree_snapshot); - AppendOnlyTreeSnapshot const expected_private_data_tree_snapshot = { .root = private_data_tree.root(), - .next_available_leaf_index = - 4 * MAX_NEW_COMMITMENTS_PER_TX }; - ASSERT_EQ(outputs.end_private_data_tree_snapshot, expected_private_data_tree_snapshot); - - // Check public data trees - ASSERT_EQ(outputs.start_public_data_tree_root, - rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_public_data_tree_root); - ASSERT_EQ(outputs.end_public_data_tree_root, - rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_public_data_tree_root); - - // check contract trees - ASSERT_EQ(outputs.start_contract_tree_snapshot, - rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_contract_tree_snapshot); - ASSERT_EQ(outputs.end_contract_tree_snapshot, - rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_contract_tree_snapshot); - AppendOnlyTreeSnapshot const expected_contract_tree_snapshot{ .root = contract_tree.root(), - .next_available_leaf_index = 4 }; - ASSERT_EQ(outputs.end_contract_tree_snapshot, expected_contract_tree_snapshot); - - // @todo @LHerskind: Check nullifier trees - - // Check historic data trees - ASSERT_EQ(outputs.start_tree_of_historic_private_data_tree_roots_snapshot, start_historic_data_tree_snapshot); - ASSERT_EQ(outputs.end_tree_of_historic_private_data_tree_roots_snapshot, end_historic_data_tree_snapshot); - - // Check historic contract trees - ASSERT_EQ(outputs.start_tree_of_historic_contract_tree_roots_snapshot, start_historic_contract_tree_snapshot); - ASSERT_EQ(outputs.end_tree_of_historic_contract_tree_roots_snapshot, end_historic_contract_tree_snapshot); - - // Check historic l1 to l2 messages trees - ASSERT_EQ(outputs.start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot, - start_historic_l1_to_l2_tree_snapshot); - ASSERT_EQ(outputs.end_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot, end_historic_l1_to_l2_tree_snapshot); - - // Check l1 to l2 messages trees - ASSERT_EQ(outputs.start_l1_to_l2_messages_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); - ASSERT_EQ(outputs.end_l1_to_l2_messages_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); - - // Compute the expected calldata hash for the root rollup (including the l2 -> l1 messages) - auto left = components::compute_kernels_calldata_hash({ kernels[0], kernels[1] }); - auto right = components::compute_kernels_calldata_hash({ kernels[2], kernels[3] }); - auto root = accumulate_sha256({ left[0], left[1], right[0], right[1] }); - ASSERT_EQ(outputs.calldata_hash, root); - - EXPECT_FALSE(builder.failed()); - - run_cbind(rootRollupInputs, outputs, true); -} +// TODO turn back on +// TEST_F(root_rollup_tests, native_root_missing_nullifier_logic) +// { +// utils::DummyCircuitBuilder builder = +// utils::DummyCircuitBuilder("root_rollup_tests__native_root_missing_nullifier_logic"); + +// MemoryStore private_data_tree_store; +// MerkleTree private_data_tree = MerkleTree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); + +// MemoryStore contract_tree_store; +// MerkleTree contract_tree = MerkleTree(contract_tree_store, CONTRACT_TREE_HEIGHT); + +// MemoryStore l1_to_l2_messages_tree_store; +// MerkleTree l1_to_l2_messages_tree = MerkleTree(l1_to_l2_messages_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); + +// std::array kernels = { +// get_empty_kernel(), get_empty_kernel(), get_empty_kernel(), get_empty_kernel() +// }; +// std::array l1_to_l2_messages = get_empty_l1_to_l2_messages(); + +// // Create commitments +// for (uint8_t kernel_j = 0; kernel_j < 4; kernel_j++) { +// std::array new_commitments; +// for (uint8_t commitment_k = 0; commitment_k < MAX_NEW_COMMITMENTS_PER_TX; commitment_k++) { +// auto val = fr(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k + 1); +// new_commitments[commitment_k] = val; +// private_data_tree.update_element(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k, val); +// } +// kernels[kernel_j].public_inputs.end.new_commitments = new_commitments; + +// std::array new_l2_to_l1_messages; +// for (uint8_t i = 0; i < MAX_NEW_L2_TO_L1_MSGS_PER_TX; i++) { +// auto val = fr(kernel_j * MAX_NEW_L2_TO_L1_MSGS_PER_TX + i + 1); +// new_l2_to_l1_messages[i] = val; +// } +// kernels[kernel_j].public_inputs.end.new_l2_to_l1_msgs = new_l2_to_l1_messages; +// } + +// // @todo @LHerskind: Add nullifiers +// // @todo @LHerskind: Add public data writes + +// // Contract tree +// NewContractData const new_contract = { +// .contract_address = fr(1), +// .portal_contract_address = fr(3), +// .function_tree_root = fr(2), +// }; +// // Update contract tree +// contract_tree.update_element(2, new_contract.hash()); +// kernels[2].public_inputs.end.new_contracts[0] = new_contract; + +// // l1 to l2 messages snapshot +// AppendOnlyTreeSnapshot const start_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), +// .next_available_leaf_index = 0 }; + +// // Create 16 empty l1 to l2 messages, and update the l1_to_l2 messages tree +// for (size_t i = 0; i < l1_to_l2_messages.size(); i++) { +// l1_to_l2_messages_tree.update_element(i, l1_to_l2_messages[i]); +// } + + +// // Compute the end snapshot +// AppendOnlyTreeSnapshot const end_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), +// .next_available_leaf_index = +// NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP +// }; + +// RootRollupInputs rootRollupInputs = get_root_rollup_inputs(builder, kernels, l1_to_l2_messages); +// RootRollupPublicInputs outputs = +// aztec3::circuits::rollup::native_root_rollup::root_rollup_circuit(builder, rootRollupInputs); + +// // Check private data trees +// ASSERT_EQ( +// outputs.start_private_data_tree_snapshot, +// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_private_data_tree_snapshot); +// ASSERT_EQ( +// outputs.end_private_data_tree_snapshot, +// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_private_data_tree_snapshot); +// AppendOnlyTreeSnapshot const expected_private_data_tree_snapshot = { .root = private_data_tree.root(), +// .next_available_leaf_index = +// 4 * MAX_NEW_COMMITMENTS_PER_TX }; +// ASSERT_EQ(outputs.end_private_data_tree_snapshot, expected_private_data_tree_snapshot); + +// // Check public data trees +// ASSERT_EQ(outputs.start_public_data_tree_root, +// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_public_data_tree_root); +// ASSERT_EQ(outputs.end_public_data_tree_root, +// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_public_data_tree_root); + +// // check contract trees +// ASSERT_EQ(outputs.start_contract_tree_snapshot, +// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_contract_tree_snapshot); +// ASSERT_EQ(outputs.end_contract_tree_snapshot, +// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_contract_tree_snapshot); +// AppendOnlyTreeSnapshot const expected_contract_tree_snapshot{ .root = contract_tree.root(), +// .next_available_leaf_index = 4 }; +// ASSERT_EQ(outputs.end_contract_tree_snapshot, expected_contract_tree_snapshot); + +// // @todo @LHerskind: Check nullifier trees + +// // Check l1 to l2 messages trees +// ASSERT_EQ(outputs.start_l1_to_l2_messages_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); +// ASSERT_EQ(outputs.end_l1_to_l2_messages_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); + +// // TODO(MADDIAA) Check historic block hashes tree +// // ASSERT_EQ(outputs.start_historic_blocks_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); +// // ASSERT_EQ(outputs.end_historic_blocks_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); + +// // Compute the expected calldata hash for the root rollup (including the l2 -> l1 messages) +// auto left = components::compute_kernels_calldata_hash({ kernels[0], kernels[1] }); +// auto right = components::compute_kernels_calldata_hash({ kernels[2], kernels[3] }); +// auto root = accumulate_sha256({ left[0], left[1], right[0], right[1] }); +// ASSERT_EQ(outputs.calldata_hash, root); + +// EXPECT_FALSE(builder.failed()); + +// run_cbind(rootRollupInputs, outputs, true); +// } } // namespace aztec3::circuits::rollup::root::native_root_rollup_circuit \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index d41c1410fb0..16621a33319 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -90,28 +90,6 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu components::assert_equal_constants(builder, left, right); components::assert_prev_rollups_follow_on_from_each_other(builder, left, right); - // Update the historic private data tree - auto end_tree_of_historic_private_data_tree_roots_snapshot = components::insert_subtree_to_snapshot_tree( - builder, - left.constants.start_tree_of_historic_private_data_tree_roots_snapshot, - rootRollupInputs.new_historic_private_data_tree_root_sibling_path, - fr::zero(), - right.end_private_data_tree_snapshot.root, - 0, - format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historic private data tree roots not empty at location where subtree would be inserted")); - - // Update the historic private data tree - auto end_tree_of_historic_contract_tree_roots_snapshot = components::insert_subtree_to_snapshot_tree( - builder, - left.constants.start_tree_of_historic_contract_tree_roots_snapshot, - rootRollupInputs.new_historic_contract_tree_root_sibling_path, - fr::zero(), - right.end_contract_tree_snapshot.root, - 0, - format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historic contract tree roots not empty at location where subtree would be inserted")); - // Check correct l1 to l2 tree given // Compute subtree inserting l1 to l2 messages auto l1_to_l2_subtree_root = calculate_subtree(rootRollupInputs.l1_to_l2_messages); @@ -128,17 +106,6 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, "l1 to l2 message tree not empty at location where subtree would be inserted")); - // Update the historic l1 to l2 data tree - auto end_l1_to_l2_data_roots_tree_snapshot = components::insert_subtree_to_snapshot_tree( - builder, - rootRollupInputs.start_historic_tree_l1_to_l2_message_tree_roots_snapshot, - rootRollupInputs.new_historic_l1_to_l2_message_roots_tree_sibling_path, - fr::zero(), - new_l1_to_l2_messages_tree_snapshot.root, - 0, - format(ROOT_CIRCUIT_ERROR_MESSAGE_BEGINNING, - "historic l1 to l2 message tree roots not empty at location where subtree would be inserted")); - // Build the block hash for this iteration from the tree roots and global variables // Then insert the block into the historic blocks tree auto block_hash = compute_block_hash_with_globals(left.constants.global_variables, @@ -171,17 +138,8 @@ RootRollupPublicInputs root_rollup_circuit(DummyBuilder& builder, RootRollupInpu .end_contract_tree_snapshot = right.end_contract_tree_snapshot, .start_public_data_tree_root = left.start_public_data_tree_root, .end_public_data_tree_root = right.end_public_data_tree_root, - .start_tree_of_historic_private_data_tree_roots_snapshot = - left.constants.start_tree_of_historic_private_data_tree_roots_snapshot, - .end_tree_of_historic_private_data_tree_roots_snapshot = end_tree_of_historic_private_data_tree_roots_snapshot, - .start_tree_of_historic_contract_tree_roots_snapshot = - left.constants.start_tree_of_historic_contract_tree_roots_snapshot, - .end_tree_of_historic_contract_tree_roots_snapshot = end_tree_of_historic_contract_tree_roots_snapshot, .start_l1_to_l2_messages_tree_snapshot = rootRollupInputs.start_l1_to_l2_message_tree_snapshot, .end_l1_to_l2_messages_tree_snapshot = new_l1_to_l2_messages_tree_snapshot, - .start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot = - rootRollupInputs.start_historic_tree_l1_to_l2_message_tree_roots_snapshot, - .end_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot = end_l1_to_l2_data_roots_tree_snapshot, .start_historic_blocks_tree_snapshot = rootRollupInputs.start_historic_blocks_tree_snapshot, .end_historic_blocks_tree_snapshot = end_historic_blocks_tree_snapshot, .calldata_hash = components::compute_calldata_hash(rootRollupInputs.previous_rollup_data), diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 79504d230b0..dce8cf7f88f 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -85,41 +85,9 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne { // @todo Look at the starting points for all of these. // By supporting as inputs we can make very generic tests, where it is trivial to try new setups. - MemoryStore historic_data_tree_store; - MerkleTree historic_private_data_tree = MerkleTree(historic_data_tree_store, PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore historic_contract_tree_store; - MerkleTree historic_contract_tree = MerkleTree(historic_contract_tree_store, CONTRACT_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore historic_l1_to_l2_msg_tree_store; - MerkleTree historic_l1_to_l2_msg_tree = - MerkleTree(historic_l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); - MemoryStore historic_blocks_tree_store; MerkleTree historic_blocks_tree = MerkleTree(historic_blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); - // Historic trees are initialised with an empty root at position 0. - historic_private_data_tree.update_element(0, private_data_tree.root()); - historic_contract_tree.update_element(0, contract_tree.root()); - MemoryStore tmp_store; - historic_l1_to_l2_msg_tree.update_element(0, MerkleTree(tmp_store, L1_TO_L2_MSG_TREE_HEIGHT).root()); - - - ConstantRollupData const constantRollupData = { - .start_tree_of_historic_private_data_tree_roots_snapshot = { - .root = historic_private_data_tree.root(), - .next_available_leaf_index = 1, - }, - .start_tree_of_historic_contract_tree_roots_snapshot = { - .root = historic_contract_tree.root(), - .next_available_leaf_index = 1, - }, - .start_tree_of_historic_l1_to_l2_msg_tree_roots_snapshot = { - .root = historic_l1_to_l2_msg_tree.root(), - .next_available_leaf_index = 1, - }, - }; - BaseRollupInputs baseRollupInputs = { .kernel_data = kernel_data, .start_private_data_tree_snapshot = { @@ -129,8 +97,9 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne .start_contract_tree_snapshot = { .root = contract_tree.root(), .next_available_leaf_index = 0, - }, - .constants = constantRollupData }; + } + }; + std::vector initial_values(2 * MAX_NEW_NULLIFIERS_PER_TX - 1); @@ -192,10 +161,12 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne l1_to_l2_msg_tree.root(), public_data_tree.root()); historic_blocks_tree.update_element(0, block_hash); - baseRollupInputs.constants.start_historic_blocks_tree_roots_snapshot = { - .root = historic_blocks_tree.root(), - .next_available_leaf_index = 1, - }; + + ConstantRollupData const constantRollupData = { .start_historic_blocks_tree_roots_snapshot = { + .root = historic_blocks_tree.root(), + .next_available_leaf_index = 1, + } }; + baseRollupInputs.constants = constantRollupData; // Set historic tree roots data in the public inputs. for (size_t i = 0; i < 2; i++) { @@ -244,25 +215,6 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne } // Get historic_root sibling paths - baseRollupInputs.historic_private_data_tree_root_membership_witnesses[0] = { - .leaf_index = 0, - .sibling_path = get_sibling_path(historic_private_data_tree, 0, 0), - }; - baseRollupInputs.historic_private_data_tree_root_membership_witnesses[1] = - baseRollupInputs.historic_private_data_tree_root_membership_witnesses[0]; - - baseRollupInputs.historic_contract_tree_root_membership_witnesses[0] = { - .leaf_index = 0, - .sibling_path = get_sibling_path(historic_contract_tree, 0, 0), - }; - baseRollupInputs.historic_contract_tree_root_membership_witnesses[1] = - baseRollupInputs.historic_contract_tree_root_membership_witnesses[0]; - baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[0] = { - .leaf_index = 0, - .sibling_path = get_sibling_path(historic_l1_to_l2_msg_tree, 0, 0), - }; - baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[1] = - baseRollupInputs.historic_l1_to_l2_msg_tree_root_membership_witnesses[0]; baseRollupInputs.historic_blocks_tree_root_membership_witnesses[0] = { .leaf_index = 0, .sibling_path = get_sibling_path(historic_blocks_tree, 0, 0), @@ -444,14 +396,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, historic_contract_tree.update_element(0, contract_tree.root()); historic_l1_to_l2_msg_tree.update_element(0, l1_to_l2_msg_tree.root()); - // Historic trees sibling paths - auto historic_data_sibling_path = - get_sibling_path(historic_private_data_tree, 1, 0); - auto historic_contract_sibling_path = - get_sibling_path(historic_contract_tree, 1, 0); - auto historic_l1_to_l2_msg_sibling_path = - get_sibling_path(historic_l1_to_l2_msg_tree, 1, 0); - // l1 to l2 tree auto l1_to_l2_tree_sibling_path = get_sibling_path(l1_to_l2_msg_tree, 0, L1_TO_L2_MSG_SUBTREE_HEIGHT); @@ -461,10 +405,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, .root = l1_to_l2_msg_tree.root(), .next_available_leaf_index = 0, }; - AppendOnlyTreeSnapshot const start_historic_tree_l1_to_l2_message_tree_roots_snapshot = { - .root = historic_l1_to_l2_msg_tree.root(), - .next_available_leaf_index = 1, - }; // Blocks tree auto blocks_tree_sibling_path = get_sibling_path(historic_blocks_tree, 0, 0); @@ -477,14 +417,9 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, RootRollupInputs rootRollupInputs = { .previous_rollup_data = get_previous_rollup_data(builder, std::move(kernel_data)), - .new_historic_private_data_tree_root_sibling_path = historic_data_sibling_path, - .new_historic_contract_tree_root_sibling_path = historic_contract_sibling_path, .l1_to_l2_messages = l1_to_l2_messages, .new_l1_to_l2_message_tree_root_sibling_path = l1_to_l2_tree_sibling_path, - .new_historic_l1_to_l2_message_roots_tree_sibling_path = historic_l1_to_l2_msg_sibling_path, .start_l1_to_l2_message_tree_snapshot = start_l1_to_l2_msg_tree_snapshot, - .start_historic_tree_l1_to_l2_message_tree_roots_snapshot = - start_historic_tree_l1_to_l2_message_tree_roots_snapshot, .start_historic_blocks_tree_snapshot = start_historic_blocks_tree_snapshot, .new_historic_blocks_tree_sibling_path = blocks_tree_sibling_path, }; diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts index 91a73868176..a818bd31efa 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts @@ -411,9 +411,6 @@ describe('HttpNode', () => { [MerkleTreeId.NULLIFIER_TREE]: Fr.random(), [MerkleTreeId.PUBLIC_DATA_TREE]: Fr.random(), [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: Fr.random(), - [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: Fr.random(), - [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: Fr.random(), - [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: Fr.random(), [MerkleTreeId.BLOCKS_TREE]: Fr.random(), }; diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.ts b/yarn-project/aztec-node/src/aztec-node/http-node.ts index bf27835d828..321476dde72 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.ts @@ -326,9 +326,6 @@ export class HttpNode implements AztecNode { [MerkleTreeId.NULLIFIER_TREE]: extractRoot(MerkleTreeId.NULLIFIER_TREE), [MerkleTreeId.PUBLIC_DATA_TREE]: extractRoot(MerkleTreeId.PUBLIC_DATA_TREE), [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: extractRoot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE), - [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: extractRoot(MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE), - [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: extractRoot(MerkleTreeId.CONTRACT_TREE_ROOTS_TREE), - [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: extractRoot(MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE), [MerkleTreeId.BLOCKS_TREE]: extractRoot(MerkleTreeId.BLOCKS_TREE), }; } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 3e5d5266071..61b2031fa94 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -326,9 +326,6 @@ export class AztecNodeService implements AztecNode { [MerkleTreeId.NULLIFIER_TREE]: await getTreeRoot(MerkleTreeId.NULLIFIER_TREE), [MerkleTreeId.PUBLIC_DATA_TREE]: await getTreeRoot(MerkleTreeId.PUBLIC_DATA_TREE), [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: await getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE), - [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE), - [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.CONTRACT_TREE_ROOTS_TREE), - [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: await getTreeRoot(MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE), [MerkleTreeId.BLOCKS_TREE]: await getTreeRoot(MerkleTreeId.BLOCKS_TREE), }; } diff --git a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.test.ts b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.test.ts index eab46862b80..b86b0df4038 100644 --- a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.test.ts +++ b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.test.ts @@ -20,9 +20,6 @@ describe('Synchroniser', () => { [MerkleTreeId.NULLIFIER_TREE]: Fr.random(), [MerkleTreeId.PUBLIC_DATA_TREE]: Fr.random(), [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: Fr.random(), - [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: Fr.random(), - [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: Fr.random(), - [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: Fr.random(), [MerkleTreeId.BLOCKS_TREE]: Fr.random(), }; diff --git a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts index 25ed2005219..53d569dd94e 100644 --- a/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts +++ b/yarn-project/aztec-rpc/src/synchroniser/synchroniser.ts @@ -136,9 +136,6 @@ export class Synchroniser { [MerkleTreeId.NULLIFIER_TREE]: block.endNullifierTreeSnapshot.root, [MerkleTreeId.PUBLIC_DATA_TREE]: block.endPublicDataTreeRoot, [MerkleTreeId.L1_TO_L2_MESSAGES_TREE]: block.endL1ToL2MessageTreeSnapshot.root, - [MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]: block.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot.root, - [MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]: block.endTreeOfHistoricContractTreeRootsSnapshot.root, - [MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]: block.endTreeOfHistoricPrivateDataTreeRootsSnapshot.root, [MerkleTreeId.BLOCKS_TREE]: block.endHistoricBlocksTreeSnapshot.root, }; await this.db.setTreeRoots(roots); diff --git a/yarn-project/circuits.js/src/rollup/rollup_wasm_wrapper.test.ts b/yarn-project/circuits.js/src/rollup/rollup_wasm_wrapper.test.ts index b62186d9f27..2ff9d86770f 100644 --- a/yarn-project/circuits.js/src/rollup/rollup_wasm_wrapper.test.ts +++ b/yarn-project/circuits.js/src/rollup/rollup_wasm_wrapper.test.ts @@ -69,9 +69,6 @@ describe('rollup/rollup_wasm_wrapper', () => { expect(output.endPrivateDataTreeSnapshot).toEqual( input.previousRollupData[1].publicInputs.endPrivateDataTreeSnapshot, ); - expect(output.constants.startTreeOfHistoricContractTreeRootsSnapshot).toEqual( - input.previousRollupData[0].publicInputs.constants.startTreeOfHistoricContractTreeRootsSnapshot, - ); }); it('calling merge_rollup__sim with different constants should fail', () => { diff --git a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts index fc7d63c5390..717a3cb0101 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts @@ -58,18 +58,6 @@ export class NullifierLeafPreimage { */ export class ConstantBaseRollupData { constructor( - /** - * Snapshot of the private data tree roots tree at the start of the rollup. - */ - public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot, - /** - * Snapshot of the contract tree roots tree at the start of the rollup. - */ - public startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, - /** - * Snapshot of the L1-to-L2 message tree roots tree at the start of the rollup. - */ - public startTreeOfHistoricL1ToL2MsgTreeRootsSnapshot: AppendOnlyTreeSnapshot, /** * Snapshot of the historic blocks roots tree at the start of the rollup. */ @@ -104,9 +92,6 @@ export class ConstantBaseRollupData { static fromBuffer(buffer: Buffer | BufferReader): ConstantBaseRollupData { const reader = BufferReader.asReader(buffer); return new ConstantBaseRollupData( - reader.readObject(AppendOnlyTreeSnapshot), - reader.readObject(AppendOnlyTreeSnapshot), - reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), reader.readFr(), reader.readFr(), @@ -118,9 +103,6 @@ export class ConstantBaseRollupData { static getFields(fields: FieldsOf) { return [ - fields.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - fields.startTreeOfHistoricContractTreeRootsSnapshot, - fields.startTreeOfHistoricL1ToL2MsgTreeRootsSnapshot, fields.startHistoricBlocksTreeRootsSnapshot, fields.privateKernelVkTreeRoot, fields.publicKernelVkTreeRoot, @@ -213,29 +195,6 @@ export class BaseRollupInputs { * Each item in the array is the sibling path that corresponds to a read request. */ public newPublicDataReadsSiblingPaths: Fr[][], - - /** - * Membership witnesses of private data tree roots referred by each of the 2 kernels. - * Can be used to prove that the root is actually in the roots tree. - */ - public historicPrivateDataTreeRootMembershipWitnesses: [ - MembershipWitness, - MembershipWitness, - ], - /** - * Membership witnesses of contract tree roots referred by each of the 2 kernels. - */ - public historicContractsTreeRootMembershipWitnesses: [ - MembershipWitness, - MembershipWitness, - ], - /** - * Membership witnesses of L1-to-L2 message tree roots referred by each of the 2 kernels. - */ - public historicL1ToL2MsgTreeRootMembershipWitnesses: [ - MembershipWitness, - MembershipWitness, - ], /** * Membership witnesses of historic blocks referred by each of the 2 kernels. */ @@ -291,9 +250,6 @@ export class BaseRollupInputs { fields.newContractsSubtreeSiblingPath, fields.newPublicDataUpdateRequestsSiblingPaths, fields.newPublicDataReadsSiblingPaths, - fields.historicPrivateDataTreeRootMembershipWitnesses, - fields.historicContractsTreeRootMembershipWitnesses, - fields.historicL1ToL2MsgTreeRootMembershipWitnesses, fields.historicBlocksTreeRootMembershipWitnesses, fields.constants, ] as const; diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 4f393b61a5e..740087e6d81 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -2,12 +2,9 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import { - CONTRACT_TREE_ROOTS_TREE_HEIGHT, HISTORIC_BLOCKS_TREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, } from '../../cbind/constants.gen.js'; import { FieldsOf, assertMemberLength } from '../../utils/jsUtils.js'; import { serializeToBuffer } from '../../utils/serialize.js'; @@ -27,14 +24,6 @@ export class RootRollupInputs { * from 2 merge or base rollup circuits. */ public previousRollupData: [PreviousRollupData, PreviousRollupData], - /** - * Sibling path of the new historic private data tree root. - */ - public newHistoricPrivateDataTreeRootSiblingPath: Fr[], - /** - * Sibling path of the new historic contract data tree root. - */ - public newHistoricContractDataTreeRootSiblingPath: Fr[], /** * New L1 to L2 messages. */ @@ -43,18 +32,10 @@ export class RootRollupInputs { * Sibling path of the new L1 to L2 message tree root. */ public newL1ToL2MessageTreeRootSiblingPath: Fr[], - /** - * Sibling path of the new historic L1 to L2 message tree root. - */ - public newHistoricL1ToL2MessageTreeRootSiblingPath: Fr[], /** * Snapshot of the L1 to L2 message tree at the start of the rollup. */ public startL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, - /** - * Snapshot of the historic L1 to L2 message tree roots at the start of the rollup. - */ - public startHistoricTreeL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, /** * Snapshot of the historic block roots tree at the start of the rollup. */ @@ -64,10 +45,7 @@ export class RootRollupInputs { */ public newHistoricBlocksTreeSiblingPath: Fr[], ) { - assertMemberLength(this, 'newHistoricPrivateDataTreeRootSiblingPath', PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); - assertMemberLength(this, 'newHistoricContractDataTreeRootSiblingPath', CONTRACT_TREE_ROOTS_TREE_HEIGHT); assertMemberLength(this, 'newL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH); - assertMemberLength(this, 'newHistoricL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); assertMemberLength(this, 'newHistoricBlocksTreeSiblingPath', HISTORIC_BLOCKS_TREE_HEIGHT); assertMemberLength(this, 'newL1ToL2Messages', NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); } @@ -83,13 +61,9 @@ export class RootRollupInputs { static getFields(fields: FieldsOf) { return [ fields.previousRollupData, - fields.newHistoricPrivateDataTreeRootSiblingPath, - fields.newHistoricContractDataTreeRootSiblingPath, fields.newL1ToL2Messages, fields.newL1ToL2MessageTreeRootSiblingPath, - fields.newHistoricL1ToL2MessageTreeRootSiblingPath, fields.startL1ToL2MessageTreeSnapshot, - fields.startHistoricTreeL1ToL2MessageTreeRootsSnapshot, fields.startHistoricBlocksTreeSnapshot, fields.newHistoricBlocksTreeSiblingPath, ] as const; diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 6e17c4bc22d..11c4c4cdef3 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -29,7 +29,7 @@ import { G1AffineElement, HISTORIC_BLOCKS_TREE_HEIGHT, KernelCircuitPublicInputs, - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, + L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, @@ -121,8 +121,8 @@ export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeR * @param seed - The seed to use for generating the combined historic tree roots. * @returns A combined historic tree roots object. */ -export function makeCombinedHistoricTreeRoots(seed: number, globalsHash?: Fr): CombinedHistoricTreeRoots { - return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), globalsHash ?? fr(seed + 5), fr(seed + 6)); +export function makeCombinedHistoricTreeRoots(seed: number): CombinedHistoricTreeRoots { + return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), fr(seed + 6), fr(seed + 7)); } /** @@ -701,9 +701,6 @@ export function makeConstantBaseRollupData( globalVariables: GlobalVariables | undefined = undefined, ): ConstantBaseRollupData { return ConstantBaseRollupData.from({ - startTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(seed), - startTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(seed + 0x100), - startTreeOfHistoricL1ToL2MsgTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(seed + 0x200), startHistoricBlocksTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(seed + 0x300), privateKernelVkTreeRoot: fr(seed + 0x401), publicKernelVkTreeRoot: fr(seed + 0x402), @@ -792,10 +789,7 @@ export function makeBaseOrMergeRollupPublicInputs( * @param globalVariables - The global variables to use when generating the previous rollup data. * @returns A previous rollup data. */ -export function makePreviousRollupData( - seed = 0, - globalVariables: GlobalVariables | undefined = undefined, -): PreviousRollupData { +export function makePreviousRollupData(seed = 0, globalVariables: GlobalVariables | undefined = undefined): PreviousRollupData { return new PreviousRollupData( makeBaseOrMergeRollupPublicInputs(seed, globalVariables), makeDynamicSizeBuffer(16, seed + 0x50), @@ -814,15 +808,11 @@ export function makePreviousRollupData( export function makeRootRollupInputs(seed = 0, globalVariables?: GlobalVariables): RootRollupInputs { return new RootRollupInputs( [makePreviousRollupData(seed, globalVariables), makePreviousRollupData(seed + 0x1000, globalVariables)], - makeTuple(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, fr, 0x2000), - makeTuple(CONTRACT_TREE_ROOTS_TREE_HEIGHT, fr, 0x2100), makeTuple(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, fr, 0x2100), - makeTuple(L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, fr, 0x2100), - makeTuple(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, fr, 0x2100), + makeTuple(L1_TO_L2_MSG_TREE_HEIGHT, fr, 0x2100), + makeAppendOnlyTreeSnapshot(seed + 0x2200), makeAppendOnlyTreeSnapshot(seed + 0x2200), - makeAppendOnlyTreeSnapshot(seed + 0x2300), - makeAppendOnlyTreeSnapshot(seed + 0x2400), - makeTuple(HISTORIC_BLOCKS_TREE_HEIGHT, fr, 0x2500), + makeTuple(HISTORIC_BLOCKS_TREE_HEIGHT, fr, 0x2400), ); } @@ -920,25 +910,9 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { range(PUBLIC_DATA_TREE_HEIGHT, x).map(fr), ); - const historicPrivateDataTreeRootMembershipWitnesses: BaseRollupInputs['historicPrivateDataTreeRootMembershipWitnesses'] = - [ - makeMembershipWitness(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, seed + 0x6000), - makeMembershipWitness(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, seed + 0x7000), - ]; - - const historicContractsTreeRootMembershipWitnesses: BaseRollupInputs['historicContractsTreeRootMembershipWitnesses'] = - [ - makeMembershipWitness(CONTRACT_TREE_ROOTS_TREE_HEIGHT, seed + 0x8000), - makeMembershipWitness(CONTRACT_TREE_ROOTS_TREE_HEIGHT, seed + 0x9000), - ]; - const historicL1ToL2MsgTreeRootMembershipWitnesses: BaseRollupInputs['historicL1ToL2MsgTreeRootMembershipWitnesses'] = - [ - makeMembershipWitness(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, seed + 0xa000), - makeMembershipWitness(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, seed + 0xb000), - ]; - const historicBlocksTreeRootMembershipWitnesses: BaseRollupInputs['historicL1ToL2MsgTreeRootMembershipWitnesses'] = [ - makeMembershipWitness(HISTORIC_BLOCKS_TREE_HEIGHT, seed + 0xc000), - makeMembershipWitness(HISTORIC_BLOCKS_TREE_HEIGHT, seed + 0xd000), + const historicBlocksTreeRootMembershipWitnesses: BaseRollupInputs['historicBlocksTreeRootMembershipWitnesses'] = [ + makeMembershipWitness(HISTORIC_BLOCKS_TREE_HEIGHT, seed + 0x7000), + makeMembershipWitness(HISTORIC_BLOCKS_TREE_HEIGHT, seed + 0x8000), ]; const constants = makeConstantBaseRollupData(0x100); @@ -957,9 +931,6 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { newContractsSubtreeSiblingPath, newPublicDataUpdateRequestsSiblingPaths, newPublicDataReadsSiblingPaths, - historicPrivateDataTreeRootMembershipWitnesses, - historicContractsTreeRootMembershipWitnesses, - historicL1ToL2MsgTreeRootMembershipWitnesses, historicBlocksTreeRootMembershipWitnesses, constants, }); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index f554ff1dc2a..f47d5d40839 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -208,16 +208,7 @@ describe('sequencer/solo_block_builder', () => { rootRollupOutput.endPrivateDataTreeSnapshot = await getTreeSnapshot(MerkleTreeId.PRIVATE_DATA_TREE); rootRollupOutput.endPublicDataTreeRoot = (await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE)).root; - rootRollupOutput.endTreeOfHistoricContractTreeRootsSnapshot = await getTreeSnapshot( - MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, - ); - rootRollupOutput.endTreeOfHistoricPrivateDataTreeRootsSnapshot = await getTreeSnapshot( - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - ); rootRollupOutput.endL1ToL2MessageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE); - rootRollupOutput.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot = await getTreeSnapshot( - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - ); // Calculate block hash rootRollupOutput.globalVariables = globalVariables; @@ -250,15 +241,8 @@ describe('sequencer/solo_block_builder', () => { endContractTreeSnapshot: rootRollupOutput.endContractTreeSnapshot, startPublicDataTreeRoot: rootRollupOutput.startPublicDataTreeRoot, endPublicDataTreeRoot: rootRollupOutput.endPublicDataTreeRoot, - startTreeOfHistoricPrivateDataTreeRootsSnapshot: rootRollupOutput.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - endTreeOfHistoricPrivateDataTreeRootsSnapshot: rootRollupOutput.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - startTreeOfHistoricContractTreeRootsSnapshot: rootRollupOutput.startTreeOfHistoricContractTreeRootsSnapshot, - endTreeOfHistoricContractTreeRootsSnapshot: rootRollupOutput.endTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot: rootRollupOutput.startL1ToL2MessageTreeSnapshot, endL1ToL2MessageTreeSnapshot: rootRollupOutput.endL1ToL2MessageTreeSnapshot, - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: - rootRollupOutput.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: rootRollupOutput.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot: rootRollupOutput.startHistoricBlocksTreeSnapshot, endHistoricBlocksTreeSnapshot: rootRollupOutput.endHistoricBlocksTreeSnapshot, newCommitments, diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 0c1aad8b4e6..5a27782cf38 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -88,10 +88,7 @@ export class SoloBlockBuilder implements BlockBuilder { startNullifierTreeSnapshot, startContractTreeSnapshot, startPublicDataTreeSnapshot, - startTreeOfHistoricPrivateDataTreeRootsSnapshot, - startTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot, - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, ] = await Promise.all( [ @@ -99,10 +96,7 @@ export class SoloBlockBuilder implements BlockBuilder { MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.CONTRACT_TREE, MerkleTreeId.PUBLIC_DATA_TREE, - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, MerkleTreeId.BLOCKS_TREE, ].map(tree => this.getTreeSnapshot(tree)), ); @@ -118,10 +112,7 @@ export class SoloBlockBuilder implements BlockBuilder { endNullifierTreeSnapshot, endContractTreeSnapshot, endPublicDataTreeRoot, - endTreeOfHistoricPrivateDataTreeRootsSnapshot, - endTreeOfHistoricContractTreeRootsSnapshot, endL1ToL2MessageTreeSnapshot, - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, endHistoricBlocksTreeSnapshot, } = circuitsOutput; @@ -161,14 +152,8 @@ export class SoloBlockBuilder implements BlockBuilder { endContractTreeSnapshot, startPublicDataTreeRoot: startPublicDataTreeSnapshot.root, endPublicDataTreeRoot, - startTreeOfHistoricPrivateDataTreeRootsSnapshot, - endTreeOfHistoricPrivateDataTreeRootsSnapshot, - startTreeOfHistoricContractTreeRootsSnapshot, - endTreeOfHistoricContractTreeRootsSnapshot, startL1ToL2MessageTreeSnapshot, endL1ToL2MessageTreeSnapshot, - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, endHistoricBlocksTreeSnapshot, newCommitments, @@ -453,15 +438,6 @@ export class SoloBlockBuilder implements BlockBuilder { return path.toFieldArray(); }; - const newHistoricContractDataTreeRootSiblingPath = await getRootTreeSiblingPath( - MerkleTreeId.CONTRACT_TREE_ROOTS_TREE, - ); - const newHistoricPrivateDataTreeRootSiblingPath = await getRootTreeSiblingPath( - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - ); - const newHistoricL1ToL2MessageTreeRootSiblingPath = await getRootTreeSiblingPath( - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - ); const newL1ToL2MessageTreeRootSiblingPath = await this.getSubtreeSiblingPath( MerkleTreeId.L1_TO_L2_MESSAGES_TREE, L1_TO_L2_MSG_SUBTREE_HEIGHT, @@ -469,9 +445,6 @@ export class SoloBlockBuilder implements BlockBuilder { // Get tree snapshots const startL1ToL2MessageTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGES_TREE); - const startHistoricTreeL1ToL2MessageTreeRootsSnapshot = await this.getTreeSnapshot( - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - ); // Get historic block tree roots const startHistoricBlocksTreeSnapshot = await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE); @@ -479,13 +452,9 @@ export class SoloBlockBuilder implements BlockBuilder { return RootRollupInputs.from({ previousRollupData, - newHistoricContractDataTreeRootSiblingPath, - newHistoricPrivateDataTreeRootSiblingPath, newL1ToL2Messages, - newHistoricL1ToL2MessageTreeRootSiblingPath, newL1ToL2MessageTreeRootSiblingPath, startL1ToL2MessageTreeSnapshot, - startHistoricTreeL1ToL2MessageTreeRootsSnapshot, startHistoricBlocksTreeSnapshot, newHistoricBlocksTreeSiblingPath, }); @@ -565,13 +534,6 @@ export class SoloBlockBuilder implements BlockBuilder { mergeRollupVkHash: DELETE_FR, privateKernelVkTreeRoot: FUTURE_FR, publicKernelVkTreeRoot: FUTURE_FR, - startTreeOfHistoricContractTreeRootsSnapshot: await this.getTreeSnapshot(MerkleTreeId.CONTRACT_TREE_ROOTS_TREE), - startTreeOfHistoricPrivateDataTreeRootsSnapshot: await this.getTreeSnapshot( - MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE, - ), - startTreeOfHistoricL1ToL2MsgTreeRootsSnapshot: await this.getTreeSnapshot( - MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE, - ), startHistoricBlocksTreeRootsSnapshot: await this.getTreeSnapshot(MerkleTreeId.BLOCKS_TREE), globalVariables, }); @@ -706,11 +668,6 @@ export class SoloBlockBuilder implements BlockBuilder { MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), ); - // Note these are no longer needed, but are included to decrease change set - const mockContractMembershipWitnesses = MembershipWitness.empty(CONTRACT_TREE_ROOTS_TREE_HEIGHT, 0n); - const mockPrivateDataMembershipWitnesses = MembershipWitness.empty(PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, 0n); - const mockL1ToL2MembershipWitnesses = MembershipWitness.empty(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, 0n); - return BaseRollupInputs.from({ constants, startNullifierTreeSnapshot, @@ -729,12 +686,6 @@ export class SoloBlockBuilder implements BlockBuilder { ), lowNullifierMembershipWitness: lowNullifierMembershipWitnesses, kernelData: [this.getKernelDataFor(left), this.getKernelDataFor(right)], - historicContractsTreeRootMembershipWitnesses: [mockContractMembershipWitnesses, mockContractMembershipWitnesses], - historicPrivateDataTreeRootMembershipWitnesses: [ - mockPrivateDataMembershipWitnesses, - mockPrivateDataMembershipWitnesses, - ], - historicL1ToL2MsgTreeRootMembershipWitnesses: [mockL1ToL2MembershipWitnesses, mockL1ToL2MembershipWitnesses], historicBlocksTreeRootMembershipWitnesses: [ await this.getHistoricTreesMembershipWitnessFor(left), await this.getHistoricTreesMembershipWitnessFor(right), diff --git a/yarn-project/types/src/l2_block.ts b/yarn-project/types/src/l2_block.ts index f53a501dd69..10340854b2e 100644 --- a/yarn-project/types/src/l2_block.ts +++ b/yarn-project/types/src/l2_block.ts @@ -66,14 +66,6 @@ export class L2Block { * The tree snapshot of the contract tree at the start of the rollup. */ public startContractTreeSnapshot: AppendOnlyTreeSnapshot, - /** - * The tree snapshot of the historic private data tree roots at the start of the rollup. - */ - public startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), - /** - * The tree snapshot of the historic contract tree roots at the start of the rollup. - */ - public startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot, /** * The tree root of the public data tree at the start of the rollup. */ @@ -82,10 +74,6 @@ export class L2Block { * The tree snapshot of the L2 message tree at the start of the rollup. */ public startL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, - /** - * The tree snapshot of the historic L2 message tree roots at the start of the rollup. - */ - public startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic blocks tree at the start of the rollup. */ @@ -102,14 +90,6 @@ export class L2Block { * The tree snapshot of the contract tree at the end of the rollup. */ public endContractTreeSnapshot: AppendOnlyTreeSnapshot, - /** - * The tree snapshot of the historic private data tree roots at the end of the rollup. - */ - public endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), - /** - * The tree snapshot of the historic contract tree roots at the end of the rollup. - */ - public endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree root of the public data tree at the end of the rollup. */ @@ -118,10 +98,6 @@ export class L2Block { * The tree snapshot of the L2 message tree at the end of the rollup. */ public endL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, - /** - * The tree snapshot of the historic L2 message tree roots at the end of the rollup. - */ - public endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot = AppendOnlyTreeSnapshot.empty(), /** * The tree snapshot of the historic blocks tree at the end of the rollup. */ @@ -205,18 +181,12 @@ export class L2Block { startContractTreeSnapshot: makeAppendOnlyTreeSnapshot(0), startPublicDataTreeRoot: Fr.random(), startL1ToL2MessageTreeSnapshot: makeAppendOnlyTreeSnapshot(0), - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), - startTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), - startTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(0), startHistoricBlocksTreeSnapshot: makeAppendOnlyTreeSnapshot(0), endPrivateDataTreeSnapshot: makeAppendOnlyTreeSnapshot(newCommitments.length), endNullifierTreeSnapshot: makeAppendOnlyTreeSnapshot(newNullifiers.length), endContractTreeSnapshot: makeAppendOnlyTreeSnapshot(newContracts.length), endPublicDataTreeRoot: Fr.random(), endL1ToL2MessageTreeSnapshot: makeAppendOnlyTreeSnapshot(1), - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), - endTreeOfHistoricPrivateDataTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), - endTreeOfHistoricContractTreeRootsSnapshot: makeAppendOnlyTreeSnapshot(1), endHistoricBlocksTreeSnapshot: makeAppendOnlyTreeSnapshot(1), newCommitments, newNullifiers, @@ -256,14 +226,6 @@ export class L2Block { * The tree snapshot of the contract tree at the start of the rollup. */ startContractTreeSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic private data tree roots at the start of the rollup. - */ - startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic contract tree roots at the start of the rollup. - */ - startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot; /** * The tree root of the public data tree at the start of the rollup. */ @@ -272,10 +234,6 @@ export class L2Block { * The tree snapshot of the L2 message tree at the start of the rollup. */ startL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic L2 message tree roots at the start of the rollup. - */ - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot; /** * The tree snapshot of the historic blocks tree at the start of the rollup. */ @@ -292,14 +250,6 @@ export class L2Block { * The tree snapshot of the contract tree at the end of the rollup. */ endContractTreeSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic private data tree roots at the end of the rollup. - */ - endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic contract tree roots at the end of the rollup. - */ - endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot; /** * The tree root of the public data tree at the end of the rollup. */ @@ -308,10 +258,6 @@ export class L2Block { * The tree snapshot of the L2 message tree at the end of the rollup. */ endL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot; - /** - * The tree snapshot of the historic L2 message tree roots at the end of the rollup. - */ - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot; /** * The tree snapshot of the historic blocks tree at the end of the rollup. */ @@ -359,20 +305,14 @@ export class L2Block { fields.startPrivateDataTreeSnapshot, fields.startNullifierTreeSnapshot, fields.startContractTreeSnapshot, - fields.startTreeOfHistoricPrivateDataTreeRootsSnapshot, - fields.startTreeOfHistoricContractTreeRootsSnapshot, fields.startPublicDataTreeRoot, fields.startL1ToL2MessageTreeSnapshot, - fields.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, fields.startHistoricBlocksTreeSnapshot, fields.endPrivateDataTreeSnapshot, fields.endNullifierTreeSnapshot, fields.endContractTreeSnapshot, - fields.endTreeOfHistoricPrivateDataTreeRootsSnapshot, - fields.endTreeOfHistoricContractTreeRootsSnapshot, fields.endPublicDataTreeRoot, fields.endL1ToL2MessageTreeSnapshot, - fields.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, fields.endHistoricBlocksTreeSnapshot, fields.newCommitments, fields.newNullifiers, @@ -473,20 +413,14 @@ export class L2Block { startPrivateDataTreeSnapshot, startNullifierTreeSnapshot, startContractTreeSnapshot, - startTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), - startTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), startPublicDataTreeRoot, startL1ToL2MessageTreeSnapshot, - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), startHistoricBlocksTreeSnapshot, endPrivateDataTreeSnapshot, endNullifierTreeSnapshot, endContractTreeSnapshot, - endTreeOfHistoricPrivateDataTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), - endTreeOfHistoricContractTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), endPublicDataTreeRoot, endL1ToL2MessageTreeSnapshot, - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot.empty(), endHistoricBlocksTreeSnapshot, newCommitments, newNullifiers, diff --git a/yarn-project/types/src/merkle_tree_id.ts b/yarn-project/types/src/merkle_tree_id.ts index 9b607f9bc31..38d94d74684 100644 --- a/yarn-project/types/src/merkle_tree_id.ts +++ b/yarn-project/types/src/merkle_tree_id.ts @@ -3,14 +3,11 @@ */ export enum MerkleTreeId { CONTRACT_TREE = 0, - CONTRACT_TREE_ROOTS_TREE = 1, - NULLIFIER_TREE = 2, - PRIVATE_DATA_TREE = 3, - PRIVATE_DATA_TREE_ROOTS_TREE = 4, - PUBLIC_DATA_TREE = 5, - L1_TO_L2_MESSAGES_TREE = 6, - L1_TO_L2_MESSAGES_ROOTS_TREE = 7, - BLOCKS_TREE = 8, + NULLIFIER_TREE = 1, + PRIVATE_DATA_TREE = 2, + PUBLIC_DATA_TREE = 3, + L1_TO_L2_MESSAGES_TREE = 4, + BLOCKS_TREE = 5, } export const merkleTreeIds = () => { diff --git a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts index 610d5919b72..0270e194c58 100644 --- a/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts +++ b/yarn-project/world-state/src/synchroniser/server_world_state_synchroniser.test.ts @@ -75,20 +75,14 @@ const getMockBlock = (blockNumber: number, newContractsCommitments?: Buffer[]) = startPrivateDataTreeSnapshot: getMockTreeSnapshot(), startNullifierTreeSnapshot: getMockTreeSnapshot(), startContractTreeSnapshot: getMockTreeSnapshot(), - startTreeOfHistoricPrivateDataTreeRootsSnapshot: getMockTreeSnapshot(), - startTreeOfHistoricContractTreeRootsSnapshot: getMockTreeSnapshot(), startPublicDataTreeRoot: Fr.random(), startL1ToL2MessageTreeSnapshot: getMockTreeSnapshot(), - startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: getMockTreeSnapshot(), startHistoricBlocksTreeSnapshot: getMockTreeSnapshot(), endPrivateDataTreeSnapshot: getMockTreeSnapshot(), endNullifierTreeSnapshot: getMockTreeSnapshot(), endContractTreeSnapshot: getMockTreeSnapshot(), - endTreeOfHistoricPrivateDataTreeRootsSnapshot: getMockTreeSnapshot(), - endTreeOfHistoricContractTreeRootsSnapshot: getMockTreeSnapshot(), endPublicDataTreeRoot: Fr.random(), endL1ToL2MessageTreeSnapshot: getMockTreeSnapshot(), - endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: getMockTreeSnapshot(), endHistoricBlocksTreeSnapshot: getMockTreeSnapshot(), newCommitments: times(MAX_NEW_COMMITMENTS_PER_TX, Fr.random), newNullifiers: times(MAX_NEW_NULLIFIERS_PER_TX, Fr.random), diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index c7206b872f4..1a618f9fa68 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -1,16 +1,13 @@ import { BaseRollupInputs, CONTRACT_TREE_HEIGHT, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, CircuitsWasm, Fr, GlobalVariables, HISTORIC_BLOCKS_TREE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, PRIVATE_DATA_TREE_HEIGHT, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; import { computeBlockHash } from '@aztec/circuits.js/abis'; @@ -68,13 +65,6 @@ export class MerkleTrees implements MerkleTreeDb { `${MerkleTreeId[MerkleTreeId.CONTRACT_TREE]}`, CONTRACT_TREE_HEIGHT, ); - const contractTreeRootsTree: AppendOnlyTree = await newTree( - StandardTree, - this.db, - hasher, - `${MerkleTreeId[MerkleTreeId.CONTRACT_TREE_ROOTS_TREE]}`, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, - ); const nullifierTree = await newTree( StandardIndexedTree, this.db, @@ -90,13 +80,6 @@ export class MerkleTrees implements MerkleTreeDb { `${MerkleTreeId[MerkleTreeId.PRIVATE_DATA_TREE]}`, PRIVATE_DATA_TREE_HEIGHT, ); - const privateDataTreeRootsTree: AppendOnlyTree = await newTree( - StandardTree, - this.db, - hasher, - `${MerkleTreeId[MerkleTreeId.PRIVATE_DATA_TREE_ROOTS_TREE]}`, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, - ); const publicDataTree: UpdateOnlyTree = await newTree( SparseTree, this.db, @@ -111,13 +94,6 @@ export class MerkleTrees implements MerkleTreeDb { `${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGES_TREE]}`, L1_TO_L2_MSG_TREE_HEIGHT, ); - const l1Tol2MessagesRootsTree: AppendOnlyTree = await newTree( - StandardTree, - this.db, - hasher, - `${MerkleTreeId[MerkleTreeId.L1_TO_L2_MESSAGES_ROOTS_TREE]}`, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, - ); const historicBlocksTree: AppendOnlyTree = await newTree( StandardTree, this.db, @@ -127,13 +103,10 @@ export class MerkleTrees implements MerkleTreeDb { ); this.trees = [ contractTree, - contractTreeRootsTree, nullifierTree, privateDataTree, - privateDataTreeRootsTree, publicDataTree, l1Tol2MessagesTree, - l1Tol2MessagesRootsTree, historicBlocksTree, ]; From 2885d55697bdaeb0edcc1a40e41d3aaedaa7e8d9 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 20:18:34 +0000 Subject: [PATCH 29/58] i have become lint, hater of self --- .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 1 - .../circuits.js/src/structs/rollup/base_rollup.ts | 3 --- yarn-project/circuits.js/src/tests/factories.ts | 5 ++++- .../src/block_builder/solo_block_builder.ts | 3 --- .../world-state/src/world-state-db/merkle_trees.ts | 9 +-------- 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 63fffe970a9..cce6126cd14 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -188,7 +188,6 @@ export class AztecRPCServer implements AztecRPC { const newContract = deployedContractAddress ? await this.db.getContract(deployedContractAddress) : undefined; const tx = await this.#simulateAndProve(txRequest, newContract); - console.log(tx); await this.db.addTx( TxDao.from({ diff --git a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts index 717a3cb0101..467cf463ef2 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts @@ -3,9 +3,7 @@ import { BufferReader } from '@aztec/foundation/serialize'; import { CONTRACT_TREE_HEIGHT, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, HISTORIC_BLOCKS_TREE_HEIGHT, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, @@ -13,7 +11,6 @@ import { MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, PRIVATE_DATA_TREE_HEIGHT, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '../../cbind/constants.gen.js'; import { FieldsOf, assertItemsLength, assertMemberLength } from '../../utils/jsUtils.js'; diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 11c4c4cdef3..5b9ef7aceab 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -789,7 +789,10 @@ export function makeBaseOrMergeRollupPublicInputs( * @param globalVariables - The global variables to use when generating the previous rollup data. * @returns A previous rollup data. */ -export function makePreviousRollupData(seed = 0, globalVariables: GlobalVariables | undefined = undefined): PreviousRollupData { +export function makePreviousRollupData( + seed = 0, + globalVariables: GlobalVariables | undefined = undefined, +): PreviousRollupData { return new PreviousRollupData( makeBaseOrMergeRollupPublicInputs(seed, globalVariables), makeDynamicSizeBuffer(16, seed + 0x50), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 5a27782cf38..1e5830fb43f 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -2,19 +2,16 @@ import { AppendOnlyTreeSnapshot, BaseOrMergeRollupPublicInputs, BaseRollupInputs, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, CircuitsWasm, ConstantBaseRollupData, GlobalVariables, HISTORIC_BLOCKS_TREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_HEIGHT, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, MembershipWitness, MergeRollupInputs, NULLIFIER_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NullifierLeafPreimage, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, PreviousKernelData, PreviousRollupData, Proof, diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 1a618f9fa68..45c4e3477ef 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -101,14 +101,7 @@ export class MerkleTrees implements MerkleTreeDb { `${MerkleTreeId[MerkleTreeId.BLOCKS_TREE]}`, HISTORIC_BLOCKS_TREE_HEIGHT, ); - this.trees = [ - contractTree, - nullifierTree, - privateDataTree, - publicDataTree, - l1Tol2MessagesTree, - historicBlocksTree, - ]; + this.trees = [contractTree, nullifierTree, privateDataTree, publicDataTree, l1Tol2MessagesTree, historicBlocksTree]; this.jobQueue.start(); From ce67250df6d69466315637c8d5c868b76dd55706 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 20:20:41 +0000 Subject: [PATCH 30/58] ive only gone n done it again --- yarn-project/circuits.js/src/tests/factories.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 5b9ef7aceab..2cea29208b1 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -11,7 +11,6 @@ import { BaseOrMergeRollupPublicInputs, BaseRollupInputs, CONTRACT_TREE_HEIGHT, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, CallContext, CircuitType, CircuitsWasm, @@ -30,7 +29,6 @@ import { HISTORIC_BLOCKS_TREE_HEIGHT, KernelCircuitPublicInputs, L1_TO_L2_MSG_TREE_HEIGHT, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, @@ -58,7 +56,6 @@ import { NullifierLeafPreimage, OptionallyRevealedData, PRIVATE_DATA_TREE_HEIGHT, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, Point, PreviousKernelData, From 0195792113eefba18496b08eb22220144900881b Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 2 Aug 2023 20:39:26 +0000 Subject: [PATCH 31/58] fix: update snappyshootys --- .../kernel/__snapshots__/index.test.ts.snap | 16 +++--- .../__snapshots__/base_rollup.test.ts.snap | 56 +++---------------- .../__snapshots__/root_rollup.test.ts.snap | 37 +----------- .../circuits.js/src/tests/factories.ts | 5 +- 4 files changed, 21 insertions(+), 93 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index 7a139cd4717..a3d6af9dfe8 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -419,8 +419,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 -public_data_tree_root: 0x106 -prev_global_variables_hash: 0x107 +public_data_tree_root: 0x107 +prev_global_variables_hash: 0x108 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -958,8 +958,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 -public_data_tree_root: 0x106 -prev_global_variables_hash: 0x107 +public_data_tree_root: 0x107 +prev_global_variables_hash: 0x108 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -1469,8 +1469,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 -public_data_tree_root: 0x106 -prev_global_variables_hash: 0x107 +public_data_tree_root: 0x107 +prev_global_variables_hash: 0x108 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -1705,8 +1705,8 @@ l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 -public_data_tree_root: 0x106 -prev_global_variables_hash: 0x107 +public_data_tree_root: 0x107 +prev_global_variables_hash: 0x108 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap index 27e808f5c28..599e68b59cf 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap @@ -213,8 +213,8 @@ l1_to_l2_messages_tree_root: 0x203 blocks_tree_root: 0x204 private_kernel_vk_tree_root: 0x205 -public_data_tree_root: 0x205 -prev_global_variables_hash: 0x206 +public_data_tree_root: 0x206 +prev_global_variables_hash: 0x207 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -458,8 +458,8 @@ l1_to_l2_messages_tree_root: 0x303 blocks_tree_root: 0x304 private_kernel_vk_tree_root: 0x305 -public_data_tree_root: 0x305 -prev_global_variables_hash: 0x306 +public_data_tree_root: 0x306 +prev_global_variables_hash: 0x307 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 @@ -685,43 +685,13 @@ new_public_data_update_requests_sibling_paths: [ [ 0x6000 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd ] [ 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe ] [ 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff ] [ 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 ] [ 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 ] [ 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 ] [ 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 ] [ 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 ] [ 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 ] [ 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 ] [ 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 ] [ 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 ] [ 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 ] [ 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a ] [ 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a 0x610b ] [ 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a 0x610b 0x610c ] ] new_state_reads_sibling_paths: [ [ 0x6000 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd ] [ 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe ] [ 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff ] [ 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 ] [ 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 ] [ 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 ] [ 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 ] [ 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 ] [ 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 ] [ 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 ] [ 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 ] [ 0x600b 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 ] [ 0x600c 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 ] [ 0x600d 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a ] [ 0x600e 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a 0x610b ] [ 0x600f 0x6010 0x6011 0x6012 0x6013 0x6014 0x6015 0x6016 0x6017 0x6018 0x6019 0x601a 0x601b 0x601c 0x601d 0x601e 0x601f 0x6020 0x6021 0x6022 0x6023 0x6024 0x6025 0x6026 0x6027 0x6028 0x6029 0x602a 0x602b 0x602c 0x602d 0x602e 0x602f 0x6030 0x6031 0x6032 0x6033 0x6034 0x6035 0x6036 0x6037 0x6038 0x6039 0x603a 0x603b 0x603c 0x603d 0x603e 0x603f 0x6040 0x6041 0x6042 0x6043 0x6044 0x6045 0x6046 0x6047 0x6048 0x6049 0x604a 0x604b 0x604c 0x604d 0x604e 0x604f 0x6050 0x6051 0x6052 0x6053 0x6054 0x6055 0x6056 0x6057 0x6058 0x6059 0x605a 0x605b 0x605c 0x605d 0x605e 0x605f 0x6060 0x6061 0x6062 0x6063 0x6064 0x6065 0x6066 0x6067 0x6068 0x6069 0x606a 0x606b 0x606c 0x606d 0x606e 0x606f 0x6070 0x6071 0x6072 0x6073 0x6074 0x6075 0x6076 0x6077 0x6078 0x6079 0x607a 0x607b 0x607c 0x607d 0x607e 0x607f 0x6080 0x6081 0x6082 0x6083 0x6084 0x6085 0x6086 0x6087 0x6088 0x6089 0x608a 0x608b 0x608c 0x608d 0x608e 0x608f 0x6090 0x6091 0x6092 0x6093 0x6094 0x6095 0x6096 0x6097 0x6098 0x6099 0x609a 0x609b 0x609c 0x609d 0x609e 0x609f 0x60a0 0x60a1 0x60a2 0x60a3 0x60a4 0x60a5 0x60a6 0x60a7 0x60a8 0x60a9 0x60aa 0x60ab 0x60ac 0x60ad 0x60ae 0x60af 0x60b0 0x60b1 0x60b2 0x60b3 0x60b4 0x60b5 0x60b6 0x60b7 0x60b8 0x60b9 0x60ba 0x60bb 0x60bc 0x60bd 0x60be 0x60bf 0x60c0 0x60c1 0x60c2 0x60c3 0x60c4 0x60c5 0x60c6 0x60c7 0x60c8 0x60c9 0x60ca 0x60cb 0x60cc 0x60cd 0x60ce 0x60cf 0x60d0 0x60d1 0x60d2 0x60d3 0x60d4 0x60d5 0x60d6 0x60d7 0x60d8 0x60d9 0x60da 0x60db 0x60dc 0x60dd 0x60de 0x60df 0x60e0 0x60e1 0x60e2 0x60e3 0x60e4 0x60e5 0x60e6 0x60e7 0x60e8 0x60e9 0x60ea 0x60eb 0x60ec 0x60ed 0x60ee 0x60ef 0x60f0 0x60f1 0x60f2 0x60f3 0x60f4 0x60f5 0x60f6 0x60f7 0x60f8 0x60f9 0x60fa 0x60fb 0x60fc 0x60fd 0x60fe 0x60ff 0x6100 0x6101 0x6102 0x6103 0x6104 0x6105 0x6106 0x6107 0x6108 0x6109 0x610a 0x610b 0x610c ] ] -historic_private_data_tree_root_membership_witnesses: -[ leaf_index: 0x6000 -sibling_path: [ 0x6000 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 0x6008 0x6009 0x600a 0x600b 0x600c 0x600d 0x600e 0x600f ] - leaf_index: 0x7000 +historic_blocks_tree_root_membership_witnesses: +[ leaf_index: 0x7000 sibling_path: [ 0x7000 0x7001 0x7002 0x7003 0x7004 0x7005 0x7006 0x7007 0x7008 0x7009 0x700a 0x700b 0x700c 0x700d 0x700e 0x700f ] - ] -historic_contract_tree_root_membership_witnesses: -[ leaf_index: 0x8000 + leaf_index: 0x8000 sibling_path: [ 0x8000 0x8001 0x8002 0x8003 0x8004 0x8005 0x8006 0x8007 0x8008 0x8009 0x800a 0x800b 0x800c 0x800d 0x800e 0x800f ] - leaf_index: 0x9000 -sibling_path: [ 0x9000 0x9001 0x9002 0x9003 0x9004 0x9005 0x9006 0x9007 0x9008 0x9009 0x900a 0x900b 0x900c 0x900d 0x900e 0x900f ] - ] -historic_l1_to_l2_msg_tree_root_membership_witnesses: -[ leaf_index: 0xa000 -sibling_path: [ 0xa000 0xa001 0xa002 0xa003 0xa004 0xa005 0xa006 0xa007 0xa008 0xa009 0xa00a 0xa00b 0xa00c 0xa00d 0xa00e 0xa00f ] - leaf_index: 0xb000 -sibling_path: [ 0xb000 0xb001 0xb002 0xb003 0xb004 0xb005 0xb006 0xb007 0xb008 0xb009 0xb00a 0xb00b 0xb00c 0xb00d 0xb00e 0xb00f ] - ] -historic_blocks_tree_root_membership_witnesses: -[ leaf_index: 0xc000 -sibling_path: [ 0xc000 0xc001 0xc002 0xc003 0xc004 0xc005 0xc006 0xc007 0xc008 0xc009 0xc00a 0xc00b 0xc00c 0xc00d 0xc00e 0xc00f ] - leaf_index: 0xd000 -sibling_path: [ 0xd000 0xd001 0xd002 0xd003 0xd004 0xd005 0xd006 0xd007 0xd008 0xd009 0xd00a 0xd00b 0xd00c 0xd00d 0xd00e 0xd00f ] ] constants: -start_tree_of_historic_private_data_tree_roots_snapshot: - root: 0x100 -next_available_leaf_index: 256 - -start_tree_of_historic_contract_tree_roots_snapshot: -root: 0x200 -next_available_leaf_index: 512 - -tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: -root: 0x300 -next_available_leaf_index: 768 - start_historic_blocks_tree_roots_snapshot: root: 0x400 next_available_leaf_index: 1024 @@ -757,18 +727,6 @@ proof_witness_indices: [ 262 263 264 265 266 267 ] has_data: 0 constants: -start_tree_of_historic_private_data_tree_roots_snapshot: - root: 0x200 -next_available_leaf_index: 512 - -start_tree_of_historic_contract_tree_roots_snapshot: -root: 0x300 -next_available_leaf_index: 768 - -tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: -root: 0x400 -next_available_leaf_index: 1024 - start_historic_blocks_tree_roots_snapshot: root: 0x500 next_available_leaf_index: 1280 diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap index c9677e7502b..c1cb63620e8 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/root_rollup.test.ts.snap @@ -18,18 +18,6 @@ proof_witness_indices: [ 106 107 108 109 10a 10b ] has_data: 0 constants: -start_tree_of_historic_private_data_tree_roots_snapshot: - root: 0x200 -next_available_leaf_index: 200 - -start_tree_of_historic_contract_tree_roots_snapshot: -root: 0x300 -next_available_leaf_index: 300 - -tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: -root: 0x400 -next_available_leaf_index: 400 - start_historic_blocks_tree_roots_snapshot: root: 0x500 next_available_leaf_index: 500 @@ -105,18 +93,6 @@ proof_witness_indices: [ 1106 1107 1108 1109 110a 110b ] has_data: 0 constants: -start_tree_of_historic_private_data_tree_roots_snapshot: - root: 0x1200 -next_available_leaf_index: 1200 - -start_tree_of_historic_contract_tree_roots_snapshot: -root: 0x1300 -next_available_leaf_index: 1300 - -tree_of_historic_l1_to_l2_msg_tree_roots_snapshot: -root: 0x1400 -next_available_leaf_index: 1400 - start_historic_blocks_tree_roots_snapshot: root: 0x1500 next_available_leaf_index: 1500 @@ -176,21 +152,14 @@ vk_sibling_path: leaf_index: 0x1120 sibling_path: [ 0x1120 0x1121 0x1122 0x1123 0x1124 0x1125 0x1126 0x1127 ] ] -new_historic_private_data_tree_roots: [ 0x2000 0x2001 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d 0x200e 0x200f ] -new_historic_contract_tree_roots: [ 0x2100 0x2101 0x2102 0x2103 0x2104 0x2105 0x2106 0x2107 0x2108 0x2109 0x210a 0x210b 0x210c 0x210d 0x210e 0x210f ] new_l1_to_l2_messages: [ 0x2100 0x2101 0x2102 0x2103 0x2104 0x2105 0x2106 0x2107 0x2108 0x2109 0x210a 0x210b 0x210c 0x210d 0x210e 0x210f ] -new_l1_to_l2_message_tree_root_sibling_path: [ 0x2100 0x2101 0x2102 0x2103 0x2104 0x2105 0x2106 0x2107 0x2108 0x2109 0x210a 0x210b ] -new_historic_l1_to_l2_message_roots_tree_sibling_path: [ 0x2100 0x2101 0x2102 0x2103 0x2104 0x2105 0x2106 0x2107 0x2108 0x2109 0x210a 0x210b 0x210c 0x210d 0x210e 0x210f ] start_l1_to_l2_message_tree_snapshot: root: 0x2200 next_available_leaf_index: 8704 -start_historic_tree_l1_to_l2_message_tree_roots_snapshot: root: 0x2300 -next_available_leaf_index: 8960 - -start_historic_blocks_tree_snapshot: root: 0x2400 -next_available_leaf_index: 9216 +start_historic_blocks_tree_snapshot: root: 0x2200 +next_available_leaf_index: 8704 -new_historic_blocks_tree_sibling_path: [ 0x2500 0x2501 0x2502 0x2503 0x2504 0x2505 0x2506 0x2507 0x2508 0x2509 0x250a 0x250b 0x250c 0x250d 0x250e 0x250f ] +new_historic_blocks_tree_sibling_path: [ 0x2400 0x2401 0x2402 0x2403 0x2404 0x2405 0x2406 0x2407 0x2408 0x2409 0x240a 0x240b 0x240c 0x240d 0x240e 0x240f ] " `; diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 2cea29208b1..a182e28721b 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -28,7 +28,8 @@ import { G1AffineElement, HISTORIC_BLOCKS_TREE_HEIGHT, KernelCircuitPublicInputs, - L1_TO_L2_MSG_TREE_HEIGHT, + L1_TO_L2_MSG_SUBTREE_HEIGHT, + L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, @@ -809,7 +810,7 @@ export function makeRootRollupInputs(seed = 0, globalVariables?: GlobalVariables return new RootRollupInputs( [makePreviousRollupData(seed, globalVariables), makePreviousRollupData(seed + 0x1000, globalVariables)], makeTuple(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, fr, 0x2100), - makeTuple(L1_TO_L2_MSG_TREE_HEIGHT, fr, 0x2100), + makeTuple(L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, fr, 0x2100), makeAppendOnlyTreeSnapshot(seed + 0x2200), makeAppendOnlyTreeSnapshot(seed + 0x2200), makeTuple(HISTORIC_BLOCKS_TREE_HEIGHT, fr, 0x2400), From 9f665936e4c2824bcabb3cbf5d3b6de489fdadc2 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 3 Aug 2023 09:51:57 +0000 Subject: [PATCH 32/58] tune --- yarn-project/circuits.js/src/tests/factories.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index a182e28721b..b9be09a861d 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -28,7 +28,6 @@ import { G1AffineElement, HISTORIC_BLOCKS_TREE_HEIGHT, KernelCircuitPublicInputs, - L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, From 468bac0e0d0e82954c0a040771d49de65724616b Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:43:23 +0000 Subject: [PATCH 33/58] clean: fix cbind naming, remove unused constants --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 10 +++++++--- .../cpp/src/aztec3/circuits/abis/c_bind.h | 2 +- .../abis/combined_historic_tree_roots.hpp | 13 ++++++++++++- .../cpp/src/aztec3/circuits/abis/packers.hpp | 19 ++++++++----------- circuits/cpp/src/aztec3/circuits/hash.hpp | 2 +- .../circuits/rollup/test_utils/utils.cpp | 15 --------------- circuits/cpp/src/aztec3/constants.hpp | 3 --- yarn-project/circuits.js/src/abis/abis.ts | 10 +++++----- .../circuits.js/src/cbind/circuits.gen.ts | 12 ++++++------ .../circuits.js/src/cbind/constants.gen.ts | 3 --- .../noir-libs/noir-aztec/src/constants_gen.nr | 3 --- .../block_builder/solo_block_builder.test.ts | 4 ++-- .../src/block_builder/solo_block_builder.ts | 6 +++--- .../src/world-state-db/merkle_trees.ts | 6 +++--- 14 files changed, 48 insertions(+), 60 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 5ca145154a6..2b2cc168eba 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -443,11 +443,15 @@ CBIND(abis__silo_nullifier, aztec3::circuits::silo_nullifier); /** * @brief Computes the block hash from the block information. + * Globals is provided as a hash in this instance. */ -CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash_with_globals); +CBIND(abis__compute_block_hash, aztec3::circuits::compute_block_hash); -// TODO: FIX NAMES -CBIND(abis__compute_block_hash_with_globals_hash, aztec3::circuits::compute_block_hash); +/** + * @brief Computes the block hash from the block information. + * The entire globals object is provided in this instance, rather than a hash as in above. + */ +CBIND(abis__compute_block_hash_with_globals, aztec3::circuits::compute_block_hash_with_globals); /** * @brief Computes the hash of the global variables diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 4015371bdef..37fb1aa8cbb 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -39,7 +39,7 @@ CBIND_DECL(abis__compute_unique_commitment); CBIND_DECL(abis__silo_commitment); CBIND_DECL(abis__silo_nullifier); CBIND_DECL(abis__compute_block_hash); -CBIND_DECL(abis__compute_block_hash_with_globals_hash); +CBIND_DECL(abis__compute_block_hash_with_globals); CBIND_DECL(abis__compute_globals_hash); WASM_EXPORT void abis__compute_message_secret_hash(uint8_t const* secret, uint8_t* output); diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp index a2991e28d46..8a954815a70 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp @@ -3,6 +3,7 @@ #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" #include "aztec3/circuits/abis/global_variables.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" @@ -22,7 +23,6 @@ template struct CombinedHistoricTreeRoots { PrivateHistoricTreeRoots private_historic_tree_roots{}; - // TODO(Maddiaa) Experiment adding the rest of the block hash data here. fr public_data_tree_root = 0; fr prev_global_variables_hash = 0; @@ -76,6 +76,17 @@ template struct CombinedHistoricTreeRoots { public_data_tree_root.set_public(); prev_global_variables_hash.set_public(); } + + + fr hash() + { + return compute_block_hash(prev_global_variables_hash, + private_historic_tree_roots.private_data_tree_root, + private_historic_tree_roots.nullifier_tree_root, + private_historic_tree_roots.contract_tree_root, + private_historic_tree_roots.l1_to_l2_data_tree_root, + public_data_tree_root); + } }; template diff --git a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp index 0217e5e804a..48a58da6247 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp @@ -48,19 +48,16 @@ struct ConstantsPacker { PUBLIC_DATA_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, L1_TO_L2_MSG_TREE_HEIGHT, - PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, - CONTRACT_TREE_ROOTS_TREE_HEIGHT, - L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT, ROLLUP_VK_TREE_HEIGHT, CONTRACT_SUBTREE_HEIGHT, CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, PRIVATE_DATA_SUBTREE_HEIGHT, PRIVATE_DATA_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_HEIGHT), - NVP(HISTORIC_BLOCKS_TREE_HEIGHT, + NULLIFIER_SUBTREE_HEIGHT, + HISTORIC_BLOCKS_TREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - L1_TO_L2_MSG_SUBTREE_HEIGHT, - L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, + L1_TO_L2_MSG_SUBTREE_HEIGHT), + NVP(L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, FUNCTION_SELECTOR_NUM_BYTES, MAPPING_SLOT_PEDERSEN_SEPARATOR, NUM_FIELDS_PER_SHA256, @@ -76,11 +73,11 @@ struct ConstantsPacker { CONTRACT_DEPLOYMENT_DATA_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH, - CONTRACT_STORAGE_READ_LENGTH), - NVP(PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, + CONTRACT_STORAGE_READ_LENGTH, + PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, - EMPTY_NULLIFIED_COMMITMENT, - CALL_PRIVATE_FUNCTION_RETURN_SIZE, + EMPTY_NULLIFIED_COMMITMENT), + NVP(CALL_PRIVATE_FUNCTION_RETURN_SIZE, PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH)); // <-- Add names of new constants here } diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 6ec3f63c63a..1f98db213be 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -5,6 +5,7 @@ #include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/point.hpp" +#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/circuit_errors.hpp" @@ -178,7 +179,6 @@ template typename NCT::fr compute_globals_hash(typename abis::Glo return globals.hash(); } - /** * @brief Calculate the Merkle tree root from the sibling path and leaf. * diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index dce8cf7f88f..eb0e1b9c6ea 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -369,15 +369,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, std::array kernel_data, std::array l1_to_l2_messages) { - MemoryStore historic_private_data_store; - MerkleTree historic_private_data_tree(historic_private_data_store, PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore historic_contract_tree_store; - MerkleTree historic_contract_tree(historic_contract_tree_store, CONTRACT_TREE_ROOTS_TREE_HEIGHT); - - MemoryStore historic_l1_to_l2_msg_tree_store; - MerkleTree historic_l1_to_l2_msg_tree(historic_l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); - MemoryStore private_data_store; const MerkleTree private_data_tree(private_data_store, PRIVATE_DATA_TREE_HEIGHT); @@ -390,12 +381,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, MemoryStore historic_blocks_tree_store; MerkleTree historic_blocks_tree(historic_blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); - - // Historic trees are initialised with an empty root at position 0. - historic_private_data_tree.update_element(0, private_data_tree.root()); - historic_contract_tree.update_element(0, contract_tree.root()); - historic_l1_to_l2_msg_tree.update_element(0, l1_to_l2_msg_tree.root()); - // l1 to l2 tree auto l1_to_l2_tree_sibling_path = get_sibling_path(l1_to_l2_msg_tree, 0, L1_TO_L2_MSG_SUBTREE_HEIGHT); diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 1424500ef82..774eb7aa682 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -79,9 +79,6 @@ constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 32; constexpr size_t PUBLIC_DATA_TREE_HEIGHT = 254; constexpr size_t NULLIFIER_TREE_HEIGHT = 16; constexpr size_t L1_TO_L2_MSG_TREE_HEIGHT = 16; -constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 16; -constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 16; -constexpr size_t L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT = 16; constexpr size_t HISTORIC_BLOCKS_TREE_HEIGHT = 16; constexpr size_t ROLLUP_VK_TREE_HEIGHT = 8; // TODO: update diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 5fbf47ed8cf..ae4cede703f 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -6,7 +6,7 @@ import chunk from 'lodash.chunk'; import { abisComputeBlockHash, - abisComputeBlockHashWithGlobalsHash, + abisComputeBlockHashWithGlobals, abisComputeCommitmentNonce, abisComputeGlobalsHash, abisComputeUniqueCommitment, @@ -313,7 +313,7 @@ export function siloNullifier(wasm: IWasmModule, contract: AztecAddress, innerNu * @param publicDataTreeRoot - The root of the public data tree. * @returns The block hash. */ -export function computeBlockHash( +export function computeBlockHashWithGlobals( wasm: IWasmModule, globals: GlobalVariables, privateDataTreeRoot: Fr, @@ -323,7 +323,7 @@ export function computeBlockHash( publicDataTreeRoot: Fr, ): Fr { wasm.call('pedersen__init'); - return abisComputeBlockHash( + return abisComputeBlockHashWithGlobals( wasm, globals, privateDataTreeRoot, @@ -345,7 +345,7 @@ export function computeBlockHash( * @param publicDataTreeRoot - The root of the public data tree. * @returns The block hash. */ -export function computeBlockHashWithGlobalsHash( +export function computeBlockHash( wasm: IWasmModule, globalsHash: Fr, privateDataTreeRoot: Fr, @@ -355,7 +355,7 @@ export function computeBlockHashWithGlobalsHash( publicDataTreeRoot: Fr, ): Fr { wasm.call('pedersen__init'); - return abisComputeBlockHashWithGlobalsHash( + return abisComputeBlockHash( wasm, globalsHash, privateDataTreeRoot, diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 6a8528ed8b7..90eeaf55079 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -1530,7 +1530,7 @@ export function abisSiloNullifier(wasm: IWasmModule, arg0: Address, arg1: Fr): F } export function abisComputeBlockHash( wasm: IWasmModule, - arg0: GlobalVariables, + arg0: Fr, arg1: Fr, arg2: Fr, arg3: Fr, @@ -1539,7 +1539,7 @@ export function abisComputeBlockHash( ): Fr { return Fr.fromBuffer( callCbind(wasm, 'abis__compute_block_hash', [ - fromGlobalVariables(arg0), + toBuffer(arg0), toBuffer(arg1), toBuffer(arg2), toBuffer(arg3), @@ -1548,9 +1548,9 @@ export function abisComputeBlockHash( ]), ); } -export function abisComputeBlockHashWithGlobalsHash( +export function abisComputeBlockHashWithGlobals( wasm: IWasmModule, - arg0: Fr, + arg0: GlobalVariables, arg1: Fr, arg2: Fr, arg3: Fr, @@ -1558,8 +1558,8 @@ export function abisComputeBlockHashWithGlobalsHash( arg5: Fr, ): Fr { return Fr.fromBuffer( - callCbind(wasm, 'abis__compute_block_hash_with_globals_hash', [ - toBuffer(arg0), + callCbind(wasm, 'abis__compute_block_hash_with_globals', [ + fromGlobalVariables(arg0), toBuffer(arg1), toBuffer(arg2), toBuffer(arg3), diff --git a/yarn-project/circuits.js/src/cbind/constants.gen.ts b/yarn-project/circuits.js/src/cbind/constants.gen.ts index dcdc9228266..91cf654df1b 100644 --- a/yarn-project/circuits.js/src/cbind/constants.gen.ts +++ b/yarn-project/circuits.js/src/cbind/constants.gen.ts @@ -31,9 +31,6 @@ export const PRIVATE_DATA_TREE_HEIGHT = 32; export const PUBLIC_DATA_TREE_HEIGHT = 254; export const NULLIFIER_TREE_HEIGHT = 16; export const L1_TO_L2_MSG_TREE_HEIGHT = 16; -export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 16; -export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 16; -export const L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT = 16; export const ROLLUP_VK_TREE_HEIGHT = 8; export const CONTRACT_SUBTREE_HEIGHT = 1; export const CONTRACT_SUBTREE_SIBLING_PATH_LENGTH = 15; diff --git a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr index 1beff77a6f5..376035e8cba 100644 --- a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr +++ b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr @@ -30,9 +30,6 @@ global PRIVATE_DATA_TREE_HEIGHT: comptime Field = 32; global PUBLIC_DATA_TREE_HEIGHT: comptime Field = 254; global NULLIFIER_TREE_HEIGHT: comptime Field = 16; global L1_TO_L2_MSG_TREE_HEIGHT: comptime Field = 16; -global PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT: comptime Field = 16; -global CONTRACT_TREE_ROOTS_TREE_HEIGHT: comptime Field = 16; -global L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT: comptime Field = 16; global ROLLUP_VK_TREE_HEIGHT: comptime Field = 8; global CONTRACT_SUBTREE_HEIGHT: comptime Field = 1; global CONTRACT_SUBTREE_SIBLING_PATH_LENGTH: comptime Field = 15; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index f47d5d40839..d01b1a23699 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -18,7 +18,7 @@ import { makeTuple, range, } from '@aztec/circuits.js'; -import { computeBlockHash, computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHashWithGlobals, computeContractLeaf } from '@aztec/circuits.js/abis'; import { fr, makeBaseOrMergeRollupPublicInputs, @@ -151,7 +151,7 @@ describe('sequencer/solo_block_builder', () => { }; const updateHistoricBlocksTree = async () => { - const blockHash = computeBlockHash( + const blockHash = computeBlockHashWithGlobals( wasm, globalVariables, rootRollupOutput.endPrivateDataTreeSnapshot.root, diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 1e5830fb43f..8b274b3f846 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -23,7 +23,7 @@ import { VerificationKey, makeTuple, } from '@aztec/circuits.js'; -import { computeBlockHash, computeBlockHashWithGlobalsHash, computeContractLeaf } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeBlockHashWithGlobals, computeContractLeaf } from '@aztec/circuits.js/abis'; import { toFriendlyJSON } from '@aztec/circuits.js/utils'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -322,7 +322,7 @@ export class SoloBlockBuilder implements BlockBuilder { ).map(r => r.root); const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHash( + const blockHash = computeBlockHashWithGlobals( wasm, globals, privateDataTreeRoot, @@ -513,7 +513,7 @@ export class SoloBlockBuilder implements BlockBuilder { const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = historicTreeRoots.privateHistoricTreeRoots; const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHashWithGlobalsHash( + const blockHash = computeBlockHash( wasm, historicTreeRoots.prevGlobalVariablesHash, privateDataTreeRoot, diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 45c4e3477ef..2f1b3d5fd4a 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -10,7 +10,7 @@ import { PRIVATE_DATA_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { computeBlockHash } from '@aztec/circuits.js/abis'; +import { computeBlockHash, computeBlockHashWithGlobals } from '@aztec/circuits.js/abis'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IWasmModule } from '@aztec/foundation/wasm'; @@ -170,7 +170,7 @@ export class MerkleTrees implements MerkleTreeDb { ).map(tree => this.getTreeInfo(tree, includeUncommitted)); const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); - const blockHash = computeBlockHash(wasm, globals, trees[0], trees[1], trees[2], trees[3], trees[4]); + const blockHash = computeBlockHashWithGlobals(wasm, globals, trees[0], trees[1], trees[2], trees[3], trees[4]); await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } @@ -534,7 +534,7 @@ export class MerkleTrees implements MerkleTreeDb { ).map(root => Fr.fromBuffer(root)); const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHash( + const blockHash = computeBlockHashWithGlobals( wasm, l2Block.globalVariables, treeRoots[0], From 77ec7376825f0572ab0a857964a34817c21cb8e8 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:48:26 +0000 Subject: [PATCH 34/58] post merge constants gen --- l1-contracts/src/core/libraries/ConstantsGen.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index dac79513bed..38aa6dfa762 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -45,9 +45,6 @@ library Constants { uint256 internal constant PUBLIC_DATA_TREE_HEIGHT = 254; uint256 internal constant NULLIFIER_TREE_HEIGHT = 16; uint256 internal constant L1_TO_L2_MSG_TREE_HEIGHT = 16; - uint256 internal constant PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 16; - uint256 internal constant CONTRACT_TREE_ROOTS_TREE_HEIGHT = 16; - uint256 internal constant L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT = 16; uint256 internal constant ROLLUP_VK_TREE_HEIGHT = 8; uint256 internal constant CONTRACT_SUBTREE_HEIGHT = 1; uint256 internal constant CONTRACT_SUBTREE_SIBLING_PATH_LENGTH = 15; From e7695267cac1b25479dde5f8d5f2c0cab9743a0c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:25:42 +0000 Subject: [PATCH 35/58] fix: cleanup pass 1 --- .../archiver/src/archiver/archiver.ts | 10 +-- .../archiver/src/archiver/archiver_store.ts | 6 +- .../src/aztec-node/http-node.test.ts | 25 +++++++ .../aztec-node/src/aztec-node/http-node.ts | 13 ++-- .../aztec-node/src/aztec-node/server.ts | 9 --- .../src/aztec_rpc_server/aztec_rpc_server.ts | 3 - .../src/structs/global_variables.ts | 10 --- yarn-project/rollup-provider/src/app.ts | 11 +++ .../block_builder/solo_block_builder.test.ts | 1 - .../world-state/src/world-state-db/index.ts | 1 - .../src/world-state-db/merkle_trees.ts | 71 ++++++------------- 11 files changed, 70 insertions(+), 90 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index f9d42b65a51..8b8c44a45e3 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -273,18 +273,12 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource * @returns The requested L2 block. */ public async getL2Block(number: number): Promise { - // TODO CLEAN UP + // If the number provided is -ve, then return the latest block. if (number < 0) { number = this.store.getBlocksLength(); - if (number === 0) { - return Promise.resolve(undefined); - } } const blocks = await this.store.getL2Blocks(number, 1); - if (blocks.length === 0) { - return Promise.resolve(undefined); - } - return blocks[0]; + return (blocks.length === 0) ? undefined : blocks[0]; } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index a4b8256e6be..e4a8f3125fc 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -256,10 +256,8 @@ export class MemoryArchiverStore implements ArchiverDataStore { * @returns The requested L2 blocks. */ public getL2Blocks(from: number, limit: number): Promise { - if (from < INITIAL_L2_BLOCK_NUM) { - throw new Error(`Invalid block range ${from}`); - } - if (from > this.l2Blocks.length) { + // Return an empty array if we are outside of range + if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length) { return Promise.resolve([]); } const startIndex = from - INITIAL_L2_BLOCK_NUM; diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts index a818bd31efa..66b4a76bd8a 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.test.ts @@ -84,6 +84,31 @@ describe('HttpNode', () => { }); }); + describe('getBlock', () => { + it('should fetch and parse a block', async () => { + const block1 = L2Block.random(1); + const response = { + block: block1.encode(), + }; + setFetchMock(response); + + const result = await httpNode.getBlock(1); + + expect(fetch).toHaveBeenCalledWith(`${TEST_URL}get-block?number=1`); + expect(result).toEqual(block1); + }); + + it('should return undefined if the block is not available', async () => { + const response = { block: undefined }; + setFetchMock(response); + + const result = await httpNode.getBlock(2); + + expect(fetch).toHaveBeenCalledWith(`${TEST_URL}get-block?number=2`); + expect(result).toEqual(undefined); + }); + }); + describe('getBlockHeight', () => { it('should fetch and return the block height', async () => { const response = { blockHeight: 100 }; diff --git a/yarn-project/aztec-node/src/aztec-node/http-node.ts b/yarn-project/aztec-node/src/aztec-node/http-node.ts index 321476dde72..7ceb5ac69ff 100644 --- a/yarn-project/aztec-node/src/aztec-node/http-node.ts +++ b/yarn-project/aztec-node/src/aztec-node/http-node.ts @@ -43,16 +43,19 @@ export class HttpNode implements AztecNode { return respJson.isReady; } + /** + * Method to request a block at the provided block number. + * @param number - The block number to request. + * @returns The block requested. Or undefined if it does not exist. + */ async getBlock(number: number): Promise { const url = new URL(`${this.baseUrl}/get-block`); url.searchParams.append('number', number.toString()); const response = await (await fetch(url.toString())).json(); - const block = response.blocks as string; - if (!block) { - return Promise.resolve(undefined); - } - return Promise.resolve(L2Block.decode(Buffer.from(block, 'hex'))); + const { block } = response; + return Promise.resolve(block ? L2Block.decode(Buffer.from(block, 'hex')) : block); } + /** * Method to request blocks. Will attempt to return all requested blocks but will return only those available. * @param from - The start of the range of blocks to return. diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 61b2031fa94..3b44192d604 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -196,15 +196,6 @@ export class AztecNodeService implements AztecNode { * @param tx - The transaction to be submitted. */ public async sendTx(tx: Tx) { - // TODO: Patch tx to inject historic tree roots until the private kernel circuit supplies this value - CAN WE remove this i think the - // kernel already supplies it - if (tx.data.constants.historicTreeRoots.isEmpty()) { - // TODO: make this more robust - base case is for the first rollup - const blockNumber = await this.blockSource.getBlockHeight(); - const prevBlock = await this.getBlock(blockNumber); - const globals = prevBlock ? prevBlock.globalVariables : GlobalVariables.empty(); - tx.data.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(this.merkleTreeDB.asLatest(), globals); - } this.log.info(`Received tx ${await tx.getTxHash()}`); await this.p2pClient!.sendTx(tx); } diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index efa03fdb02a..8e275aca878 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -163,9 +163,6 @@ export class AztecRPCServer implements AztecRPC { // If a negative block number is provided the current block height is fetched. if (blockNumber < 0) { blockNumber = await this.node.getBlockHeight(); - - // TODO: FIX HACK - if (blockNumber == 0) return undefined; } return await this.node.getBlock(blockNumber); } diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index 170aedfc41d..10509a5d015 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -31,16 +31,6 @@ export class GlobalVariables { return new GlobalVariables(...GlobalVariables.getFields(fields)); } - /** - * Get the genesis GlobalVariables given a chainId and version. - * @param chainId - The chainId of the L2 block. - * @param version - The version of the L2 block. - * @returns GlobalVariables for the genesis block. - */ - static genesis(chainId: bigint, version: bigint): GlobalVariables { - return new GlobalVariables(new Fr(chainId), new Fr(version), Fr.zero(), Fr.zero()); - } - static empty(): GlobalVariables { return new GlobalVariables(Fr.zero(), Fr.zero(), Fr.zero(), Fr.zero()); } diff --git a/yarn-project/rollup-provider/src/app.ts b/yarn-project/rollup-provider/src/app.ts index 98e3f321e78..066c68bf8b6 100644 --- a/yarn-project/rollup-provider/src/app.ts +++ b/yarn-project/rollup-provider/src/app.ts @@ -46,6 +46,17 @@ export function appFactory(node: AztecNode, prefix: string) { ctx.status = 200; }); + router.get('/get-block', async (ctx: Koa.Context) => { + const number = +ctx.query.number!; + const block = await node.getBlock(number); + const str = block?.encode().toString('hex'); + ctx.set('content-type', 'application/json'); + ctx.body = { + block: str, + }; + ctx.status = 200; + }); + router.get('/get-blocks', async (ctx: Koa.Context) => { const from = +ctx.query.from!; const limit = +ctx.query.limit!; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index d01b1a23699..7fe80afc2dc 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -96,7 +96,6 @@ describe('sequencer/solo_block_builder', () => { blockNumber = 3; globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO); - // TODO: really don;t like this init pattern builderDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); expectsDb = await MerkleTrees.new(levelup(createMemDown())).then(t => t.asLatest()); vks = getVerificationKeys(); diff --git a/yarn-project/world-state/src/world-state-db/index.ts b/yarn-project/world-state/src/world-state-db/index.ts index 6c6370311f2..a0f45640312 100644 --- a/yarn-project/world-state/src/world-state-db/index.ts +++ b/yarn-project/world-state/src/world-state-db/index.ts @@ -175,7 +175,6 @@ export interface MerkleTreeOperations { * This includes all of the current roots of all of the data trees and the current blocks global vars. * @param globalVariables - The global variables to insert into the block hash. */ - // TODO: i currently dont love that the global variabels are leaked in this abstraction updateHistoricBlocksTree(globalVariables: GlobalVariables): Promise; /** diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 2f1b3d5fd4a..6ec9edd3e14 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -10,7 +10,7 @@ import { PRIVATE_DATA_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { computeBlockHash, computeBlockHashWithGlobals } from '@aztec/circuits.js/abis'; +import { computeBlockHashWithGlobals } from '@aztec/circuits.js/abis'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IWasmModule } from '@aztec/foundation/wasm'; @@ -108,8 +108,7 @@ export class MerkleTrees implements MerkleTreeDb { // The roots trees must contain the empty roots of their data trees // The first leaf in the tree contains empty roots await this.updateHistoricBlocksTree(GlobalVariables.empty(), true); - const historicRootsTrees = [historicBlocksTree]; - await Promise.all(historicRootsTrees.map(tree => tree.commit())); + await historicBlocksTree.commit(); } /** @@ -156,21 +155,7 @@ export class MerkleTrees implements MerkleTreeDb { * @param includeUncommitted - Indicates whether to include uncommitted data. */ public async updateHistoricBlocksTree(globals: GlobalVariables, includeUncommitted: boolean) { - const wasm = await CircuitsWasm.get(); - - // TODO maybe use the same pattern as function below - const treePromises = ( - [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - ] as const - ).map(tree => this.getTreeInfo(tree, includeUncommitted)); - const trees = (await Promise.all(treePromises)).map(tree => Fr.fromBuffer(tree.root)); - - const blockHash = computeBlockHashWithGlobals(wasm, globals, trees[0], trees[1], trees[2], trees[3], trees[4]); + const blockHash = await this.getCurrentBlockHash(globals, includeUncommitted) await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } @@ -190,13 +175,7 @@ export class MerkleTrees implements MerkleTreeDb { * @returns The current roots of the trees. */ public getCommitmentTreeRoots(includeUncommitted: boolean): CurrentCommitmentTreeRoots { - const roots = [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.BLOCKS_TREE, - ].map(tree => this.trees[tree].getRoot(includeUncommitted)); + const roots = this.getAllTreeRoots(includeUncommitted); return { privateDataTreeRoot: roots[0], @@ -207,6 +186,22 @@ export class MerkleTrees implements MerkleTreeDb { }; } + async getCurrentBlockHash(globals: GlobalVariables, includeUncommitted: boolean): Promise { + const roots = this.getAllTreeRoots(includeUncommitted).map(root => Fr.fromBuffer(root)); + const wasm = await CircuitsWasm.get(); + return computeBlockHashWithGlobals(wasm, globals, roots[0], roots[1], roots[2], roots[3], roots[4]); + } + + getAllTreeRoots(includeUncommitted: boolean): Buffer[] { + return [ + MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.CONTRACT_TREE, + MerkleTreeId.L1_TO_L2_MESSAGES_TREE, + MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.BLOCKS_TREE, + ].map(tree => this.trees[tree].getRoot(includeUncommitted)); + } + /** * Gets the value at the given index. * @param treeId - The ID of the tree to get the leaf value from. @@ -520,30 +515,8 @@ export class MerkleTrees implements MerkleTreeDb { await this._updateLeaf(MerkleTreeId.PUBLIC_DATA_TREE, newValue.toBuffer(), leafIndex.value); } - // Sync the blocks tree. - const treeRoots = ( - await Promise.all( - [ - MerkleTreeId.PRIVATE_DATA_TREE, - MerkleTreeId.NULLIFIER_TREE, - MerkleTreeId.CONTRACT_TREE, - MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.PUBLIC_DATA_TREE, - ].map(tree => this.trees[tree].getRoot(true)), - ) - ).map(root => Fr.fromBuffer(root)); - - const wasm = await CircuitsWasm.get(); - const blockHash = computeBlockHashWithGlobals( - wasm, - l2Block.globalVariables, - treeRoots[0], - treeRoots[1], - treeRoots[2], - treeRoots[3], - treeRoots[4], - ); - // Add the block to the historic blocks tree + // Sync and add the block to the historic blocks tree + const blockHash = await this.getCurrentBlockHash(l2Block.globalVariables, true); await this._appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); await this._commit(); From acf17be364ced481eb8bc971cad1fd69baf7dbeb Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:19:33 +0000 Subject: [PATCH 36/58] refactor: historic roots -> block hash data --- .../circuits/abis/combined_constant_data.hpp | 18 +-- ...roots.hpp => constant_block_hash_data.hpp} | 14 +- .../native_private_kernel_circuit_init.cpp | 10 +- .../native_private_kernel_circuit_inner.cpp | 4 +- ...tive_private_kernel_circuit_inner.test.cpp | 24 +-- .../kernel/private/testing_harness.cpp | 8 +- .../aztec3/circuits/kernel/public/.test.cpp | 30 ++-- .../base/native_base_rollup_circuit.cpp | 2 +- .../circuits/rollup/test_utils/utils.cpp | 16 +- .../src/aztec_rpc_server/aztec_rpc_server.ts | 10 +- .../circuits.js/src/cbind/circuits.gen.ts | 36 ++--- yarn-project/circuits.js/src/cbind/types.ts | 2 +- yarn-project/circuits.js/src/structs/index.ts | 1 + .../structs/kernel/combined_constant_data.ts | 147 +----------------- .../kernel/constant_block_hash_data.ts | 142 +++++++++++++++++ .../circuits.js/src/tests/factories.ts | 6 +- .../src/integration_l1_publisher.test.ts | 2 +- .../block_builder/solo_block_builder.test.ts | 4 +- .../src/block_builder/solo_block_builder.ts | 4 +- .../src/sequencer/processed_tx.ts | 6 +- .../src/sequencer/sequencer.test.ts | 4 +- .../sequencer-client/src/sequencer/utils.ts | 4 +- 22 files changed, 249 insertions(+), 245 deletions(-) rename circuits/cpp/src/aztec3/circuits/abis/{combined_historic_tree_roots.hpp => constant_block_hash_data.hpp} (84%) create mode 100644 yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp index c57832f6f00..15f4fd161e2 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp @@ -2,7 +2,7 @@ #include "tx_context.hpp" -#include "aztec3/circuits/abis/combined_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/constant_block_hash_data.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" @@ -11,7 +11,7 @@ namespace aztec3::circuits::abis { -using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::ConstantBlockHashData; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; @@ -20,14 +20,14 @@ template struct CombinedConstantData { using fr = typename NCT::fr; using boolean = typename NCT::boolean; - CombinedHistoricTreeRoots historic_tree_roots{}; + ConstantBlockHashData block_hash_values{}; TxContext tx_context{}; // for serialization: update up with new fields - MSGPACK_FIELDS(historic_tree_roots, tx_context); + MSGPACK_FIELDS(block_hash_values, tx_context); boolean operator==(CombinedConstantData const& other) const { - return historic_tree_roots == other.historic_tree_roots && tx_context == other.tx_context; + return block_hash_values == other.block_hash_values && tx_context == other.tx_context; } template CombinedConstantData> to_circuit_type(Builder& builder) const @@ -35,7 +35,7 @@ template struct CombinedConstantData { static_assert((std::is_same::value)); CombinedConstantData> constant_data = { - historic_tree_roots.to_circuit_type(builder), + block_hash_values.to_circuit_type(builder), tx_context.to_circuit_type(builder), }; @@ -49,7 +49,7 @@ template struct CombinedConstantData { auto to_native_type = [](T& e) { return e.template to_native_type(); }; CombinedConstantData constant_data = { - to_native_type(historic_tree_roots), + to_native_type(block_hash_values), to_native_type(tx_context), }; @@ -60,14 +60,14 @@ template struct CombinedConstantData { { static_assert(!(std::is_same::value)); - historic_tree_roots.set_public(); + block_hash_values.set_public(); tx_context.set_public(); } }; template std::ostream& operator<<(std::ostream& os, CombinedConstantData const& constant_data) { - return os << "historic_tree_roots: " << constant_data.historic_tree_roots << "\n" + return os << "block_hash_values: " << constant_data.block_hash_values << "\n" << "tx_context: " << constant_data.tx_context << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp similarity index 84% rename from circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp rename to circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp index 8a954815a70..078625f7cd3 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_historic_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp @@ -17,7 +17,7 @@ using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; -template struct CombinedHistoricTreeRoots { +template struct ConstantBlockHashData { using fr = typename NCT::fr; using boolean = typename NCT::boolean; @@ -29,14 +29,14 @@ template struct CombinedHistoricTreeRoots { // for serialization, update with new fields MSGPACK_FIELDS(private_historic_tree_roots, public_data_tree_root, prev_global_variables_hash); - boolean operator==(CombinedHistoricTreeRoots const& other) const + boolean operator==(ConstantBlockHashData const& other) const { return private_historic_tree_roots == other.private_historic_tree_roots && public_data_tree_root == other.public_data_tree_root && prev_global_variables_hash == other.prev_global_variables_hash; }; - template CombinedHistoricTreeRoots> to_circuit_type(Builder& builder) const + template ConstantBlockHashData> to_circuit_type(Builder& builder) const { static_assert((std::is_same::value)); @@ -44,7 +44,7 @@ template struct CombinedHistoricTreeRoots { auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(builder); }; auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; - CombinedHistoricTreeRoots> data = { + ConstantBlockHashData> data = { to_circuit_type(private_historic_tree_roots), to_ct(public_data_tree_root), to_ct(prev_global_variables_hash), @@ -53,13 +53,13 @@ template struct CombinedHistoricTreeRoots { return data; }; - template CombinedHistoricTreeRoots to_native_type() const + template ConstantBlockHashData to_native_type() const { static_assert(std::is_same, NCT>::value); auto to_native_type = [&](T& e) { return e.template to_native_type(); }; auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; - CombinedHistoricTreeRoots data = { + ConstantBlockHashData data = { to_native_type(private_historic_tree_roots), to_nt(public_data_tree_root), to_nt(prev_global_variables_hash), @@ -90,7 +90,7 @@ template struct CombinedHistoricTreeRoots { }; template -std::ostream& operator<<(std::ostream& os, CombinedHistoricTreeRoots const& historic_tree_roots) +std::ostream& operator<<(std::ostream& os, ConstantBlockHashData const& historic_tree_roots) { return os << "private_historic_tree_roots: " << historic_tree_roots.private_historic_tree_roots << "\n" << "public_data_tree_root: " << historic_tree_roots.public_data_tree_root << "\n" diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp index 4f4867cceb2..75080dce5fd 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp @@ -2,14 +2,14 @@ #include "init.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/combined_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/constant_block_hash_data.hpp" #include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/array.hpp" using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::ConstantBlockHashData; using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; using aztec3::utils::array_push; @@ -46,8 +46,8 @@ void initialise_end_values(PrivateKernelInputsInit const& private_inputs, // Define the constants data. auto const& private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; auto const constants = CombinedConstantData{ - .historic_tree_roots = - CombinedHistoricTreeRoots{ + .block_hash_values = + ConstantBlockHashData{ .private_historic_tree_roots = PrivateHistoricTreeRoots{ // TODO(dbanks12): remove historic root from app circuit public inputs and @@ -191,7 +191,7 @@ KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyBuilder common_validate_read_requests( builder, private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address, - public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root, + public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp index 38de771f1c6..9e1e39f5b2a 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp @@ -79,7 +79,7 @@ void validate_contract_tree_root(DummyBuilder& builder, PrivateKernelInputsInner auto const& purported_contract_tree_root = private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; auto const& previous_kernel_contract_tree_root = - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .contract_tree_root; builder.do_assert( purported_contract_tree_root == previous_kernel_contract_tree_root, @@ -142,7 +142,7 @@ KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyBuilder& common_validate_read_requests( builder, private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address, - public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root, + public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp index 3d737fa455e..b082807d735 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp @@ -89,7 +89,7 @@ TEST_F(native_private_kernel_inner_tests, private_function_incorrect_contract_tr auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); // Set private_historic_tree_roots to a random scalar. - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .contract_tree_root = NT::fr::random_element(); // Invoke the native private kernel circuit @@ -248,7 +248,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_request) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -276,7 +276,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_leaf_index) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -303,7 +303,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_sibling_path) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -331,7 +331,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_root_mismatch) // generate two random sets of read requests and mix them so their roots don't match auto [read_requests0, read_request_membership_witnesses0, root] = get_random_reads(contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; auto [read_requests1, read_request_membership_witnesses1, _root] = get_random_reads(contract_address, 2); @@ -397,7 +397,7 @@ TEST_F(native_private_kernel_inner_tests, native_one_read_requests_works) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 1); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -428,7 +428,7 @@ TEST_F(native_private_kernel_inner_tests, native_two_read_requests_works) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -460,7 +460,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_works) auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -492,7 +492,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_less_than_witness get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); read_requests[MAX_READ_REQUESTS_PER_CALL - 1] = fr(0); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -519,7 +519,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_more_than_witness read_request_membership_witnesses[MAX_READ_REQUESTS_PER_CALL - 1] = ReadRequestMembershipWitness{}; - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -577,7 +577,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_one_transient auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; @@ -615,7 +615,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_all_transient auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp index dc5d281d1bd..6b2db5361bf 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp @@ -7,7 +7,7 @@ #include "aztec3/circuits/abis/call_stack_item.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/combined_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/constant_block_hash_data.hpp" #include "aztec3/circuits/abis/contract_deployment_data.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/private_circuit_public_inputs.hpp" @@ -32,7 +32,7 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CombinedAccumulatedData; using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::ConstantBlockHashData; using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::PrivateCircuitPublicInputs; @@ -460,8 +460,8 @@ PrivateKernelInputsInner do_private_call_get_kernel_inputs_inner( // Fill in some important fields in public inputs mock_previous_kernel.public_inputs.end.private_call_stack = initial_kernel_private_call_stack; mock_previous_kernel.public_inputs.constants = CombinedConstantData{ - .historic_tree_roots = - CombinedHistoricTreeRoots{ + .block_hash_values = + ConstantBlockHashData{ .private_historic_tree_roots = PrivateHistoricTreeRoots{ .private_data_tree_root = private_circuit_public_inputs.historic_private_data_tree_root, diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp index 79189514a82..b5905740aa6 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp @@ -6,7 +6,7 @@ #include "aztec3/circuits/abis/call_stack_item.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/combined_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/constant_block_hash_data.hpp" #include "aztec3/circuits/abis/contract_deployment_data.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" @@ -35,7 +35,7 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CombinedAccumulatedData; using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::ConstantBlockHashData; using aztec3::circuits::abis::NewContractData; using aztec3::circuits::abis::OptionallyRevealedData; using aztec3::circuits::abis::PreviousKernelData; @@ -360,22 +360,20 @@ PublicKernelInputs get_kernel_inputs_with_previous_kernel(NT::boolean privat }; // TODO(914) Should this be unused? - [[maybe_unused]] CombinedHistoricTreeRoots const historic_tree_roots = { .private_historic_tree_roots = { - .private_data_tree_root = 1000, - .contract_tree_root = 2000, - .l1_to_l2_messages_tree_root = - 3000, - .private_kernel_vk_tree_root = - 4000, - } }; + [[maybe_unused]] ConstantBlockHashData const historic_tree_roots = { .private_historic_tree_roots = { + .private_data_tree_root = 1000, + .contract_tree_root = 2000, + .l1_to_l2_messages_tree_root = 3000, + .private_kernel_vk_tree_root = 4000, + } }; CombinedConstantData const end_constants = { - .historic_tree_roots = - CombinedHistoricTreeRoots{ .private_historic_tree_roots = - PrivateHistoricTreeRoots{ .private_data_tree_root = ++seed, - .nullifier_tree_root = ++seed, - .contract_tree_root = ++seed, - .private_kernel_vk_tree_root = ++seed } }, + .block_hash_values = + ConstantBlockHashData{ .private_historic_tree_roots = + PrivateHistoricTreeRoots{ .private_data_tree_root = ++seed, + .nullifier_tree_root = ++seed, + .contract_tree_root = ++seed, + .private_kernel_vk_tree_root = ++seed } }, .tx_context = TxContext{ .is_fee_payment_tx = false, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index ab43014992c..43484867226 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -139,7 +139,7 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas for (size_t i = 0; i < 2; i++) { // Rebuild the block hash - auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.historic_tree_roots; + auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.block_hash_values; auto historic_tree_roots = historic_block.private_historic_tree_roots; auto private_data_tree_root = historic_tree_roots.private_data_tree_root; diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index eb0e1b9c6ea..adaca6e90dc 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -170,21 +170,21 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne // Set historic tree roots data in the public inputs. for (size_t i = 0; i < 2; i++) { - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root = + kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root = private_data_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root = + kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.nullifier_tree_root = nullifier_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root = + kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.nullifier_tree_root = nullifier_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root = + kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.contract_tree_root = contract_tree.root(); kernel_data[i] - .public_inputs.constants.historic_tree_roots.private_historic_tree_roots.l1_to_l2_messages_tree_root = + .public_inputs.constants.block_hash_values.private_historic_tree_roots.l1_to_l2_messages_tree_root = l1_to_l2_msg_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.private_historic_tree_roots.blocks_tree_root = + kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.blocks_tree_root = historic_blocks_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.public_data_tree_root = public_data_tree.root(); - kernel_data[i].public_inputs.constants.historic_tree_roots.prev_global_variables_hash = + kernel_data[i].public_inputs.constants.block_hash_values.public_data_tree_root = public_data_tree.root(); + kernel_data[i].public_inputs.constants.block_hash_values.prev_global_variables_hash = prev_global_variables_hash; } diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 8e275aca878..d0560a58543 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -6,7 +6,7 @@ import { import { AztecAddress, CircuitsWasm, - CombinedHistoricTreeRoots, + ConstantBlockHashData, FunctionData, GlobalVariables, PartialContractAddress, @@ -343,7 +343,7 @@ export class AztecRPCServer implements AztecRPC { async #simulate( txRequest: TxExecutionRequest, - prevBlockData: CombinedHistoricTreeRoots, + prevBlockData: ConstantBlockHashData, contractDataOracle?: ContractDataOracle, ) { // TODO - Pause syncing while simulating. @@ -387,7 +387,7 @@ export class AztecRPCServer implements AztecRPC { */ async #simulateUnconstrained( execRequest: ExecutionRequest, - prevBlockData: CombinedHistoricTreeRoots = CombinedHistoricTreeRoots.empty(), + prevBlockData: ConstantBlockHashData = ConstantBlockHashData.empty(), contractDataOracle?: ContractDataOracle, ) { if (!contractDataOracle) { @@ -438,7 +438,7 @@ export class AztecRPCServer implements AztecRPC { const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); const treeRoots = this.db.getTreeRoots(); - const historicTreeRoots = new CombinedHistoricTreeRoots( + const historicTreeRoots = new ConstantBlockHashData( new PrivateHistoricTreeRoots( treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], treeRoots[MerkleTreeId.NULLIFIER_TREE], @@ -463,7 +463,7 @@ export class AztecRPCServer implements AztecRPC { this.log('Proof completed!'); // TODO: FIX HACK< OVERWRITING THE ROOTS HERE - publicInputs.constants.historicTreeRoots = historicTreeRoots; + publicInputs.constants.ConstantBlockHashData = historicTreeRoots; const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 90eeaf55079..3a61c7ab4fd 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -13,7 +13,7 @@ import { CircuitError, CombinedAccumulatedData, CombinedConstantData, - CombinedHistoricTreeRoots, + ConstantBlockHashData, ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, @@ -696,38 +696,38 @@ export function fromPrivateHistoricTreeRoots(o: PrivateHistoricTreeRoots): Msgpa }; } -interface MsgpackCombinedHistoricTreeRoots { +interface MsgpackConstantBlockHashData { private_historic_tree_roots: MsgpackPrivateHistoricTreeRoots; public_data_tree_root: Buffer; prev_global_variables_hash: Buffer; } -export function toCombinedHistoricTreeRoots(o: MsgpackCombinedHistoricTreeRoots): CombinedHistoricTreeRoots { +export function toConstantBlockHashData(o: MsgpackConstantBlockHashData): ConstantBlockHashData { if (o.private_historic_tree_roots === undefined) { - throw new Error('Expected private_historic_tree_roots in CombinedHistoricTreeRoots deserialization'); + throw new Error('Expected private_historic_tree_roots in ConstantBlockHashData deserialization'); } if (o.public_data_tree_root === undefined) { - throw new Error('Expected public_data_tree_root in CombinedHistoricTreeRoots deserialization'); + throw new Error('Expected public_data_tree_root in ConstantBlockHashData deserialization'); } if (o.prev_global_variables_hash === undefined) { - throw new Error('Expected prev_global_variables_hash in CombinedHistoricTreeRoots deserialization'); + throw new Error('Expected prev_global_variables_hash in ConstantBlockHashData deserialization'); } - return new CombinedHistoricTreeRoots( + return new ConstantBlockHashData( toPrivateHistoricTreeRoots(o.private_historic_tree_roots), Fr.fromBuffer(o.public_data_tree_root), Fr.fromBuffer(o.prev_global_variables_hash), ); } -export function fromCombinedHistoricTreeRoots(o: CombinedHistoricTreeRoots): MsgpackCombinedHistoricTreeRoots { +export function fromConstantBlockHashData(o: ConstantBlockHashData): MsgpackConstantBlockHashData { if (o.privateHistoricTreeRoots === undefined) { - throw new Error('Expected privateHistoricTreeRoots in CombinedHistoricTreeRoots serialization'); + throw new Error('Expected privateHistoricTreeRoots in ConstantBlockHashData serialization'); } if (o.publicDataTreeRoot === undefined) { - throw new Error('Expected publicDataTreeRoot in CombinedHistoricTreeRoots serialization'); + throw new Error('Expected publicDataTreeRoot in ConstantBlockHashData serialization'); } if (o.prevGlobalVariablesHash === undefined) { - throw new Error('Expected prevGlobalVariablesHash in CombinedHistoricTreeRoots serialization'); + throw new Error('Expected prevGlobalVariablesHash in ConstantBlockHashData serialization'); } return { private_historic_tree_roots: fromPrivateHistoricTreeRoots(o.privateHistoricTreeRoots), @@ -890,29 +890,29 @@ export function fromTxContext(o: TxContext): MsgpackTxContext { } interface MsgpackCombinedConstantData { - historic_tree_roots: MsgpackCombinedHistoricTreeRoots; + block_hash_values: MsgpackConstantBlockHashData; tx_context: MsgpackTxContext; } export function toCombinedConstantData(o: MsgpackCombinedConstantData): CombinedConstantData { - if (o.historic_tree_roots === undefined) { - throw new Error('Expected historic_tree_roots in CombinedConstantData deserialization'); + if (o.block_hash_values === undefined) { + throw new Error('Expected block_hash_values in CombinedConstantData deserialization'); } if (o.tx_context === undefined) { throw new Error('Expected tx_context in CombinedConstantData deserialization'); } - return new CombinedConstantData(toCombinedHistoricTreeRoots(o.historic_tree_roots), toTxContext(o.tx_context)); + return new CombinedConstantData(toConstantBlockHashData(o.block_hash_values), toTxContext(o.tx_context)); } export function fromCombinedConstantData(o: CombinedConstantData): MsgpackCombinedConstantData { - if (o.historicTreeRoots === undefined) { - throw new Error('Expected historicTreeRoots in CombinedConstantData serialization'); + if (o.ConstantBlockHashData === undefined) { + throw new Error('Expected ConstantBlockHashData in CombinedConstantData serialization'); } if (o.txContext === undefined) { throw new Error('Expected txContext in CombinedConstantData serialization'); } return { - historic_tree_roots: fromCombinedHistoricTreeRoots(o.historicTreeRoots), + block_hash_values: fromConstantBlockHashData(o.ConstantBlockHashData), tx_context: fromTxContext(o.txContext), }; } diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index e27a3e463ea..165db9a656f 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -34,7 +34,7 @@ export { ReadRequestMembershipWitness, CombinedAccumulatedData, PrivateHistoricTreeRoots, - CombinedHistoricTreeRoots, + ConstantBlockHashData, ContractDeploymentData, TxContext, CombinedConstantData, diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 7fd6fb7fa3a..a937733bba7 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -11,6 +11,7 @@ export * from './kernel/private_kernel.js'; export * from './kernel/public_kernel.js'; export * from './kernel/combined_accumulated_data.js'; export * from './kernel/combined_constant_data.js'; +export * from './kernel/constant_block_hash_data.js'; export * from './kernel/previous_kernel_data.js'; export * from './kernel/public_inputs.js'; export * from './private_circuit_public_inputs.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 074eccec344..5c8c4ead146 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -1,145 +1,8 @@ -import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; - -import { FieldsOf } from '../../utils/jsUtils.js'; import { serializeToBuffer } from '../../utils/serialize.js'; import { TxContext } from '../tx_context.js'; +import { ConstantBlockHashData } from './constant_block_hash_data.js'; -/** - * Encapsulates the roots of all the trees relevant for the kernel circuits. - */ -export class PrivateHistoricTreeRoots { - constructor( - /** - * Root of the private data tree at the time of when this information was assembled. - */ - public privateDataTreeRoot: Fr, - /** - * Root of the nullifier tree at the time of when this information was assembled. - */ - public nullifierTreeRoot: Fr, - /** - * Root of the contract tree at the time of when this information was assembled. - */ - public contractTreeRoot: Fr, - /** - * Root of the l1 to l2 messages tree at the time of when this information was assembled. - */ - public l1ToL2MessagesTreeRoot: Fr, - /** - * Root of the historic blocks tree at the time of when this information was assembled. - */ - public blocksTreeRoot: Fr, - /** - * Root of the private kernel vk tree at the time of when this information was assembled. - */ - public privateKernelVkTreeRoot: Fr, // future enhancement - ) {} - - static from(fields: FieldsOf): PrivateHistoricTreeRoots { - return new PrivateHistoricTreeRoots(...PrivateHistoricTreeRoots.getFields(fields)); - } - - static getFields(fields: FieldsOf) { - return [ - fields.privateDataTreeRoot, - fields.nullifierTreeRoot, - fields.contractTreeRoot, - fields.l1ToL2MessagesTreeRoot, - fields.blocksTreeRoot, - fields.privateKernelVkTreeRoot, - ] as const; - } - - toBuffer() { - return serializeToBuffer(...PrivateHistoricTreeRoots.getFields(this)); - } - - toString() { - return this.toBuffer().toString(); - } - - isEmpty() { - return ( - this.privateDataTreeRoot.isZero() && - this.nullifierTreeRoot.isZero() && - this.contractTreeRoot.isZero() && - this.l1ToL2MessagesTreeRoot.isZero() && - this.blocksTreeRoot.isZero() && - this.privateKernelVkTreeRoot.isZero() - ); - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or reader to read from. - * @returns A new instance of PrivateHistoricTreeRoots. - */ - static fromBuffer(buffer: Buffer | BufferReader): PrivateHistoricTreeRoots { - const reader = BufferReader.asReader(buffer); - return new PrivateHistoricTreeRoots( - reader.readFr(), - reader.readFr(), - reader.readFr(), - reader.readFr(), - reader.readFr(), - reader.readFr(), - ); - } - - static fromString(str: string): PrivateHistoricTreeRoots { - return PrivateHistoricTreeRoots.fromBuffer(Buffer.from(str, 'hex')); - } - - static empty() { - return new PrivateHistoricTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); - } -} - -/** - * Information about the tree roots used for both public and private kernels. - */ -export class CombinedHistoricTreeRoots { - constructor( - /** - * Root of the trees relevant for kernel circuits. - */ - public readonly privateHistoricTreeRoots: PrivateHistoricTreeRoots, - /** - * Current public state tree hash. TODO(): THIS IS NOT A NICE SOLUTION TO THIS PROBLEM TO GET THE BLOCK HASH - */ - public readonly publicDataTreeRoot: Fr, - /** - * Previous globals hash - */ - public readonly prevGlobalVariablesHash: Fr, - ) {} - - toBuffer() { - return serializeToBuffer(this.privateHistoricTreeRoots, this.publicDataTreeRoot, this.prevGlobalVariablesHash); - } - - toString() { - return this.toBuffer().toString(); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new CombinedHistoricTreeRoots(reader.readObject(PrivateHistoricTreeRoots), reader.readFr(), reader.readFr()); - } - - isEmpty() { - return ( - this.privateHistoricTreeRoots.isEmpty() && - this.publicDataTreeRoot.isZero() && - this.prevGlobalVariablesHash.isZero() - ); - } - - static empty() { - return new CombinedHistoricTreeRoots(PrivateHistoricTreeRoots.empty(), Fr.ZERO, Fr.ZERO); - } -} /** * Data that is constant/not modified by neither of the kernels. @@ -149,7 +12,7 @@ export class CombinedConstantData { /** * Roots of the trees relevant for both kernel circuits. */ - public historicTreeRoots: CombinedHistoricTreeRoots, + public ConstantBlockHashData: ConstantBlockHashData, /** * Context of the transaction. */ @@ -157,7 +20,7 @@ export class CombinedConstantData { ) {} toBuffer() { - return serializeToBuffer(this.historicTreeRoots, this.txContext); + return serializeToBuffer(this.ConstantBlockHashData, this.txContext); } /** @@ -167,10 +30,10 @@ export class CombinedConstantData { */ static fromBuffer(buffer: Buffer | BufferReader): CombinedConstantData { const reader = BufferReader.asReader(buffer); - return new CombinedConstantData(reader.readObject(CombinedHistoricTreeRoots), reader.readObject(TxContext)); + return new CombinedConstantData(reader.readObject(ConstantBlockHashData), reader.readObject(TxContext)); } static empty() { - return new CombinedConstantData(CombinedHistoricTreeRoots.empty(), TxContext.empty()); + return new CombinedConstantData(ConstantBlockHashData.empty(), TxContext.empty()); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts b/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts new file mode 100644 index 00000000000..e2f52687d60 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts @@ -0,0 +1,142 @@ + +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader } from '@aztec/foundation/serialize'; + +import { FieldsOf } from '../../utils/jsUtils.js'; +import { serializeToBuffer } from '../../utils/serialize.js'; + +/** + * Encapsulates the roots of all the trees relevant for the kernel circuits. + */ +export class PrivateHistoricTreeRoots { + constructor( + /** + * Root of the private data tree at the time of when this information was assembled. + */ + public privateDataTreeRoot: Fr, + /** + * Root of the nullifier tree at the time of when this information was assembled. + */ + public nullifierTreeRoot: Fr, + /** + * Root of the contract tree at the time of when this information was assembled. + */ + public contractTreeRoot: Fr, + /** + * Root of the l1 to l2 messages tree at the time of when this information was assembled. + */ + public l1ToL2MessagesTreeRoot: Fr, + /** + * Root of the historic blocks tree at the time of when this information was assembled. + */ + public blocksTreeRoot: Fr, + /** + * Root of the private kernel vk tree at the time of when this information was assembled. + */ + public privateKernelVkTreeRoot: Fr, // future enhancement + ) {} + + static from(fields: FieldsOf): PrivateHistoricTreeRoots { + return new PrivateHistoricTreeRoots(...PrivateHistoricTreeRoots.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [ + fields.privateDataTreeRoot, + fields.nullifierTreeRoot, + fields.contractTreeRoot, + fields.l1ToL2MessagesTreeRoot, + fields.blocksTreeRoot, + fields.privateKernelVkTreeRoot, + ] as const; + } + + toBuffer() { + return serializeToBuffer(...PrivateHistoricTreeRoots.getFields(this)); + } + + toString() { + return this.toBuffer().toString(); + } + + isEmpty() { + return ( + this.privateDataTreeRoot.isZero() && + this.nullifierTreeRoot.isZero() && + this.contractTreeRoot.isZero() && + this.l1ToL2MessagesTreeRoot.isZero() && + this.blocksTreeRoot.isZero() && + this.privateKernelVkTreeRoot.isZero() + ); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns A new instance of PrivateHistoricTreeRoots. + */ + static fromBuffer(buffer: Buffer | BufferReader): PrivateHistoricTreeRoots { + const reader = BufferReader.asReader(buffer); + return new PrivateHistoricTreeRoots( + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + reader.readFr(), + ); + } + + static fromString(str: string): PrivateHistoricTreeRoots { + return PrivateHistoricTreeRoots.fromBuffer(Buffer.from(str, 'hex')); + } + + static empty() { + return new PrivateHistoricTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); + } +} + +/** + * Information about the tree roots used for both public and private kernels. + */ +export class ConstantBlockHashData { + constructor( + /** + * Root of the trees relevant for kernel circuits. + */ + public readonly privateHistoricTreeRoots: PrivateHistoricTreeRoots, + /** + * Current public state tree hash. + */ + public readonly publicDataTreeRoot: Fr, + /** + * Previous globals hash, this value is used to recalculate the block hash. + */ + public readonly prevGlobalVariablesHash: Fr, + ) {} + + toBuffer() { + return serializeToBuffer(this.privateHistoricTreeRoots, this.publicDataTreeRoot, this.prevGlobalVariablesHash); + } + + toString() { + return this.toBuffer().toString(); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ConstantBlockHashData(reader.readObject(PrivateHistoricTreeRoots), reader.readFr(), reader.readFr()); + } + + isEmpty() { + return ( + this.privateHistoricTreeRoots.isEmpty() && + this.publicDataTreeRoot.isZero() && + this.prevGlobalVariablesHash.isZero() + ); + } + + static empty() { + return new ConstantBlockHashData(PrivateHistoricTreeRoots.empty(), Fr.ZERO, Fr.ZERO); + } +} \ No newline at end of file diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index b9be09a861d..861230713a5 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -16,8 +16,8 @@ import { CircuitsWasm, CombinedAccumulatedData, CombinedConstantData, - CombinedHistoricTreeRoots, ConstantBaseRollupData, + ConstantBlockHashData, ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, @@ -118,8 +118,8 @@ export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeR * @param seed - The seed to use for generating the combined historic tree roots. * @returns A combined historic tree roots object. */ -export function makeCombinedHistoricTreeRoots(seed: number): CombinedHistoricTreeRoots { - return new CombinedHistoricTreeRoots(makePrivateHistoricTreeRoots(seed), fr(seed + 6), fr(seed + 7)); +export function makeCombinedHistoricTreeRoots(seed: number): ConstantBlockHashData { + return new ConstantBlockHashData(makePrivateHistoricTreeRoots(seed), fr(seed + 6), fr(seed + 7)); } /** diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 1d350dd689d..f3c64e6c8d2 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -169,7 +169,7 @@ describe('L1Publisher integration', () => { const kernelOutput = KernelCircuitPublicInputs.empty(); kernelOutput.constants.txContext.chainId = fr(config.chainId); kernelOutput.constants.txContext.version = fr(config.version); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); + kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 7fe80afc2dc..d46eb929a9f 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -169,7 +169,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(expectsDb); + kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(expectsDb); const tx = await makeProcessedTx( new Tx( @@ -305,7 +305,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(builderDb); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 8b274b3f846..d388a7527cc 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -183,7 +183,7 @@ export class SoloBlockBuilder implements BlockBuilder { 'nullifierTreeRoot', 'l1ToL2MessagesTreeRoot', ] as const) { - if (tx.data.constants.historicTreeRoots.privateHistoricTreeRoots[historicTreeRoot].isZero()) { + if (tx.data.constants.ConstantBlockHashData.privateHistoricTreeRoots[historicTreeRoot].isZero()) { throw new Error(`Empty ${historicTreeRoot} for tx: ${toFriendlyJSON(tx)}`); } } @@ -509,7 +509,7 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { - const historicTreeRoots = tx.data.constants.historicTreeRoots; + const historicTreeRoots = tx.data.constants.ConstantBlockHashData; const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = historicTreeRoots.privateHistoricTreeRoots; const wasm = await CircuitsWasm.get(); diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 85d9a0d6dc1..2f92525d87e 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -1,4 +1,4 @@ -import { CombinedHistoricTreeRoots, Fr, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; +import { ConstantBlockHashData, Fr, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; import { Tx, TxHash, TxL2Logs } from '@aztec/types'; /** @@ -60,12 +60,12 @@ export async function makeProcessedTx( * @returns A processed empty tx. */ export function makeEmptyProcessedTx( - historicTreeRoots: CombinedHistoricTreeRoots, + historicTreeRoots: ConstantBlockHashData, chainId: Fr, version: Fr, ): Promise { const emptyKernelOutput = KernelCircuitPublicInputs.empty(); - emptyKernelOutput.constants.historicTreeRoots = historicTreeRoots; + emptyKernelOutput.constants.ConstantBlockHashData = historicTreeRoots; emptyKernelOutput.constants.txContext.chainId = chainId; emptyKernelOutput.constants.txContext.version = version; const emptyProof = makeEmptyProof(); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 8de7c6f38ac..c1905ed3f65 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -1,5 +1,5 @@ import { - CombinedHistoricTreeRoots, + ConstantBlockHashData, Fr, GlobalVariables, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, @@ -57,7 +57,7 @@ describe('sequencer', () => { publicProcessor = mock({ process: async txs => [await Promise.all(txs.map(tx => makeProcessedTx(tx))), []], - makeEmptyProcessedTx: () => makeEmptyProcessedTx(CombinedHistoricTreeRoots.empty(), chainId, version), + makeEmptyProcessedTx: () => makeEmptyProcessedTx(ConstantBlockHashData.empty(), chainId, version), }); publicProcessorFactory = mock({ diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index d7e066d7c26..742e4de7a7a 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -1,6 +1,6 @@ import { CircuitsWasm, - CombinedHistoricTreeRoots, + ConstantBlockHashData, Fr, GlobalVariables, PrivateHistoricTreeRoots, @@ -19,7 +19,7 @@ export async function getCombinedHistoricTreeRoots( const wasm = await CircuitsWasm.get(); const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); - return new CombinedHistoricTreeRoots( + return new ConstantBlockHashData( new PrivateHistoricTreeRoots( Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PRIVATE_DATA_TREE)).root), Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.NULLIFIER_TREE)).root), From f0724206aa95f58af534143c443205131b806192 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:20:13 +0000 Subject: [PATCH 37/58] refactor: update snapshots --- .../src/structs/kernel/__snapshots__/index.test.ts.snap | 8 ++++---- .../structs/rollup/__snapshots__/base_rollup.test.ts.snap | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index a3d6af9dfe8..3704e3d0cd9 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -412,7 +412,7 @@ value: 0xd09 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x101 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 @@ -951,7 +951,7 @@ value: 0xd09 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x101 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 @@ -1462,7 +1462,7 @@ value: 0xd09 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x101 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 @@ -1698,7 +1698,7 @@ value: 0xd09 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x101 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap index 599e68b59cf..ee539a1a260 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap @@ -206,7 +206,7 @@ value: 0xe08 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x200 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x200 nullifier_tree_root: 0x201 contract_tree_root: 0x202 l1_to_l2_messages_tree_root: 0x203 @@ -451,7 +451,7 @@ value: 0xf08 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x300 +block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x300 nullifier_tree_root: 0x301 contract_tree_root: 0x302 l1_to_l2_messages_tree_root: 0x303 From 956bfddcf64e77ad8c5612d56e4736d2adbedfec Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:41:04 +0000 Subject: [PATCH 38/58] refactor: trees --- yarn-project/aztec-node/src/aztec-node/server.ts | 2 +- .../src/aztec_rpc_server/aztec_rpc_server.ts | 4 +++- .../circuits.js/src/cbind/circuits.gen.ts | 6 +++--- .../src/structs/kernel/combined_constant_data.ts | 4 ++-- .../src/integration_l1_publisher.test.ts | 6 +++--- .../src/block_builder/solo_block_builder.test.ts | 8 ++++---- .../src/block_builder/solo_block_builder.ts | 4 ++-- .../src/sequencer/processed_tx.ts | 2 +- .../src/sequencer/public_processor.ts | 4 ++-- .../sequencer-client/src/sequencer/utils.ts | 16 ++++++++-------- .../src/simulator/public_executor.ts | 2 +- .../merkle-tree/merkle_tree_operations_facade.ts | 6 +++--- .../world-state/src/world-state-db/index.ts | 6 ++++-- .../src/world-state-db/merkle_trees.ts | 6 ++++-- 14 files changed, 41 insertions(+), 35 deletions(-) diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 3b44192d604..3638b60f6a3 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -10,7 +10,7 @@ import { import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; import { InMemoryTxPool, P2P, createP2PClient } from '@aztec/p2p'; -import { SequencerClient, getCombinedHistoricTreeRoots } from '@aztec/sequencer-client'; +import { SequencerClient, getConstantBlockHashData } from '@aztec/sequencer-client'; import { AztecNode, ContractData, diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index d0560a58543..1afa07c9f05 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -438,6 +438,8 @@ export class AztecRPCServer implements AztecRPC { const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); const treeRoots = this.db.getTreeRoots(); + + const historicTreeRoots = new ConstantBlockHashData( new PrivateHistoricTreeRoots( treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], @@ -463,7 +465,7 @@ export class AztecRPCServer implements AztecRPC { this.log('Proof completed!'); // TODO: FIX HACK< OVERWRITING THE ROOTS HERE - publicInputs.constants.ConstantBlockHashData = historicTreeRoots; + publicInputs.constants.blockHashValues = historicTreeRoots; const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 3a61c7ab4fd..0b82101fca7 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -905,14 +905,14 @@ export function toCombinedConstantData(o: MsgpackCombinedConstantData): Combined } export function fromCombinedConstantData(o: CombinedConstantData): MsgpackCombinedConstantData { - if (o.ConstantBlockHashData === undefined) { - throw new Error('Expected ConstantBlockHashData in CombinedConstantData serialization'); + if (o.blockHashValues === undefined) { + throw new Error('Expected blockHashValues in CombinedConstantData serialization'); } if (o.txContext === undefined) { throw new Error('Expected txContext in CombinedConstantData serialization'); } return { - block_hash_values: fromConstantBlockHashData(o.ConstantBlockHashData), + block_hash_values: fromConstantBlockHashData(o.blockHashValues), tx_context: fromTxContext(o.txContext), }; } diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 5c8c4ead146..d59c9de2f1f 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -12,7 +12,7 @@ export class CombinedConstantData { /** * Roots of the trees relevant for both kernel circuits. */ - public ConstantBlockHashData: ConstantBlockHashData, + public blockHashValues: ConstantBlockHashData, /** * Context of the transaction. */ @@ -20,7 +20,7 @@ export class CombinedConstantData { ) {} toBuffer() { - return serializeToBuffer(this.ConstantBlockHashData, this.txContext); + return serializeToBuffer(this.blockHashValues, this.txContext); } /** diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index f3c64e6c8d2..da1ed9cae92 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -25,7 +25,7 @@ import { L1Publisher, SoloBlockBuilder, WasmRollupCircuitSimulator, - getCombinedHistoricTreeRoots, + getConstantBlockHashData, getL1Publisher, getVerificationKeys, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, @@ -155,7 +155,7 @@ describe('L1Publisher integration', () => { }, 100_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); + const historicTreeRoots = await getConstantBlockHashData(builderDb, prevGlobals); const tx = await makeEmptyProcessedTxFromHistoricTreeRoots( historicTreeRoots, new Fr(config.chainId), @@ -169,7 +169,7 @@ describe('L1Publisher integration', () => { const kernelOutput = KernelCircuitPublicInputs.empty(); kernelOutput.constants.txContext.chainId = fr(config.chainId); kernelOutput.constants.txContext.version = fr(config.version); - kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(builderDb, prevGlobals); + kernelOutput.constants.blockHashValues = await getConstantBlockHashData(builderDb, prevGlobals); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index d46eb929a9f..8ec0bddc19f 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -57,7 +57,7 @@ import { makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '../sequencer/processed_tx.js'; -import { getCombinedHistoricTreeRoots } from '../sequencer/utils.js'; +import { getConstantBlockHashData } from '../sequencer/utils.js'; import { RollupSimulator } from '../simulator/index.js'; import { WasmRollupCircuitSimulator } from '../simulator/rollup.js'; import { SoloBlockBuilder } from './solo_block_builder.js'; @@ -121,7 +121,7 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getCombinedHistoricTreeRoots(builderDb); + const historicTreeRoots = await getConstantBlockHashData(builderDb); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; @@ -169,7 +169,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(expectsDb); + kernelOutput.constants.blockHashValues = await getConstantBlockHashData(expectsDb); const tx = await makeProcessedTx( new Tx( @@ -305,7 +305,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.ConstantBlockHashData = await getCombinedHistoricTreeRoots(builderDb); + kernelOutput.constants.blockHashValues = await getConstantBlockHashData(builderDb); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index d388a7527cc..9ac9b30eaa7 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -183,7 +183,7 @@ export class SoloBlockBuilder implements BlockBuilder { 'nullifierTreeRoot', 'l1ToL2MessagesTreeRoot', ] as const) { - if (tx.data.constants.ConstantBlockHashData.privateHistoricTreeRoots[historicTreeRoot].isZero()) { + if (tx.data.constants.blockHashValues.privateHistoricTreeRoots[historicTreeRoot].isZero()) { throw new Error(`Empty ${historicTreeRoot} for tx: ${toFriendlyJSON(tx)}`); } } @@ -509,7 +509,7 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { - const historicTreeRoots = tx.data.constants.ConstantBlockHashData; + const historicTreeRoots = tx.data.constants.blockHashValues; const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = historicTreeRoots.privateHistoricTreeRoots; const wasm = await CircuitsWasm.get(); diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 2f92525d87e..e3c48d55b42 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -65,7 +65,7 @@ export function makeEmptyProcessedTx( version: Fr, ): Promise { const emptyKernelOutput = KernelCircuitPublicInputs.empty(); - emptyKernelOutput.constants.ConstantBlockHashData = historicTreeRoots; + emptyKernelOutput.constants.blockHashValues = historicTreeRoots; emptyKernelOutput.constants.txContext.chainId = chainId; emptyKernelOutput.constants.txContext.version = version; const emptyProof = makeEmptyProof(); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 5c654c15fcf..edefcc5d60c 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -38,7 +38,7 @@ import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { getPublicExecutor } from '../simulator/public_executor.js'; import { WasmPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; import { ProcessedTx, makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js'; -import { getCombinedHistoricTreeRoots } from './utils.js'; +import { getConstantBlockHashData } from './utils.js'; /** * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source. @@ -112,7 +112,7 @@ export class PublicProcessor { prevGlobals: GlobalVariables, currentGlobalVariables: GlobalVariables, ): Promise { - const historicTreeRoots = await getCombinedHistoricTreeRoots(this.db, prevGlobals); + const historicTreeRoots = await getConstantBlockHashData(this.db, prevGlobals); return makeEmptyProcessedTx(historicTreeRoots, currentGlobalVariables.chainId, currentGlobalVariables.version); } diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 742e4de7a7a..34f38414a46 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -6,29 +6,29 @@ import { PrivateHistoricTreeRoots, } from '@aztec/circuits.js'; import { computeGlobalsHash } from '@aztec/circuits.js/abis'; -import { MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations } from '@aztec/world-state'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getCombinedHistoricTreeRoots( +export async function getConstantBlockHashData( db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty(), ) { const wasm = await CircuitsWasm.get(); const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); + const roots = db.getTreeRoots(); return new ConstantBlockHashData( new PrivateHistoricTreeRoots( - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PRIVATE_DATA_TREE)).root), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.NULLIFIER_TREE)).root), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.CONTRACT_TREE)).root), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.L1_TO_L2_MESSAGES_TREE)).root), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.BLOCKS_TREE)).root), + Fr.fromBuffer(roots.privateDataTreeRoot), + Fr.fromBuffer(roots.nullifierTreeRoot), + Fr.fromBuffer(roots.contractDataTreeRoot), + Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), + Fr.fromBuffer(roots.blocksTreeRoot), Fr.ZERO, ), - Fr.fromBuffer((await db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE)).root), + Fr.fromBuffer(roots.publicDataTreeRoot), prevGlobalsHash, ); } diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 1949f13b9c3..162a639d7b9 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -111,7 +111,7 @@ export class WorldStateDB implements CommitmentsDB { } public getTreeRoots(): PrivateHistoricTreeRoots { - const roots = this.db.getCommitmentTreeRoots(); + const roots = this.db.getTreeRoots(); return PrivateHistoricTreeRoots.from({ privateKernelVkTreeRoot: Fr.ZERO, diff --git a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts index c9621bd7598..af4e734fdfa 100644 --- a/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts +++ b/yarn-project/world-state/src/merkle-tree/merkle_tree_operations_facade.ts @@ -2,7 +2,7 @@ import { GlobalVariables } from '@aztec/circuits.js'; import { LowLeafWitnessData } from '@aztec/merkle-tree'; import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/types'; -import { CurrentCommitmentTreeRoots, LeafData, MerkleTreeDb, MerkleTreeOperations, TreeInfo } from '../index.js'; +import { CurrentTreeRoots, LeafData, MerkleTreeDb, MerkleTreeOperations, TreeInfo } from '../index.js'; /** * Wraps a MerkleTreeDbOperations to call all functions with a preset includeUncommitted flag. @@ -24,8 +24,8 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations { * Get the current roots of the commitment trees. * @returns The current roots of the trees. */ - getCommitmentTreeRoots(): CurrentCommitmentTreeRoots { - return this.trees.getCommitmentTreeRoots(this.includeUncommitted); + getTreeRoots(): CurrentTreeRoots { + return this.trees.getTreeRoots(this.includeUncommitted); } /** diff --git a/yarn-project/world-state/src/world-state-db/index.ts b/yarn-project/world-state/src/world-state-db/index.ts index a0f45640312..0f66811c794 100644 --- a/yarn-project/world-state/src/world-state-db/index.ts +++ b/yarn-project/world-state/src/world-state-db/index.ts @@ -66,7 +66,7 @@ type WithIncludeUncommitted = F extends (...args: [...infer Rest]) => infer R /** * The current roots of the commitment trees */ -export type CurrentCommitmentTreeRoots = { +export type CurrentTreeRoots = { /** Private data tree root. */ privateDataTreeRoot: Buffer; /** Contract data tree root. */ @@ -77,6 +77,8 @@ export type CurrentCommitmentTreeRoots = { nullifierTreeRoot: Buffer; /** Blocks tree root. */ blocksTreeRoot: Buffer; + /** Public data tree root */ + publicDataTreeRoot: Buffer; }; /** @@ -113,7 +115,7 @@ export interface MerkleTreeOperations { /** * Gets the current roots of the commitment trees. */ - getCommitmentTreeRoots(): CurrentCommitmentTreeRoots; + getTreeRoots(): CurrentTreeRoots; /** * Gets sibling path for a leaf. diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 6ec9edd3e14..98b52ace0b8 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -32,7 +32,7 @@ import { default as levelup } from 'levelup'; import { MerkleTreeOperationsFacade } from '../merkle-tree/merkle_tree_operations_facade.js'; import { - CurrentCommitmentTreeRoots, + CurrentTreeRoots, INITIAL_NULLIFIER_TREE_SIZE, IndexedTreeId, MerkleTreeDb, @@ -174,7 +174,7 @@ export class MerkleTrees implements MerkleTreeDb { * @param includeUncommitted - Indicates whether to include uncommitted data. * @returns The current roots of the trees. */ - public getCommitmentTreeRoots(includeUncommitted: boolean): CurrentCommitmentTreeRoots { + public getTreeRoots(includeUncommitted: boolean): CurrentTreeRoots { const roots = this.getAllTreeRoots(includeUncommitted); return { @@ -183,6 +183,7 @@ export class MerkleTrees implements MerkleTreeDb { l1Tol2MessagesTreeRoot: roots[2], nullifierTreeRoot: roots[3], blocksTreeRoot: roots[4], + publicDataTreeRoot: roots[5], }; } @@ -199,6 +200,7 @@ export class MerkleTrees implements MerkleTreeDb { MerkleTreeId.L1_TO_L2_MESSAGES_TREE, MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.BLOCKS_TREE, + MerkleTreeId.PRIVATE_DATA_TREE, ].map(tree => this.trees[tree].getRoot(includeUncommitted)); } From 96ba6de668cd9b712313169f46071e78d43d68b6 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:58:05 +0000 Subject: [PATCH 39/58] refactor: block hash data --- .../cpp/src/aztec3/circuits/abis/packers.hpp | 2 +- .../abis/private_circuit_public_inputs.hpp | 42 +++++++++++++++ .../native_private_kernel_circuit_init.cpp | 2 + circuits/cpp/src/aztec3/constants.hpp | 10 ++-- .../src/core/libraries/ConstantsGen.sol | 10 ++-- .../acir-simulator/src/acvm/deserialize.ts | 4 ++ .../src/client/client_execution_context.ts | 12 ++--- .../src/client/private_execution.test.ts | 13 +++-- .../src/client/private_execution.ts | 16 ++++-- .../acir-simulator/src/client/simulator.ts | 16 +++--- .../client/unconstrained_execution.test.ts | 6 +-- .../src/aztec_rpc_server/aztec_rpc_server.ts | 52 +++++-------------- .../aztec-rpc/src/kernel_oracle/index.ts | 24 ++++++++- .../circuits.js/src/cbind/constants.gen.ts | 10 ++-- .../structs/private_circuit_public_inputs.ts | 14 ++++- .../circuits.js/src/tests/factories.ts | 6 ++- .../non_native_token_contract/src/main.nr | 2 +- yarn-project/noir-libs/noir-aztec/src/abi.nr | 34 ++++++------ .../noir-libs/noir-aztec/src/constants_gen.nr | 10 ++-- .../noir-libs/noir-aztec/src/context.nr | 30 ++++++----- .../noir-libs/noir-aztec/src/messaging.nr | 2 +- .../src/block_builder/solo_block_builder.ts | 11 ++-- .../src/world-state-db/merkle_trees.ts | 22 ++++---- 23 files changed, 212 insertions(+), 138 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp index 8936dc1caee..c429b8d0f04 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp @@ -68,7 +68,7 @@ struct ConstantsPacker { MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH, CALL_CONTEXT_LENGTH, - COMMITMENT_TREES_ROOTS_LENGTH, + BLOCK_HASH_DATA_LENGTH, FUNCTION_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 2c7ec6b66eb..d84ab89794c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -50,6 +50,8 @@ template class PrivateCircuitPublicInputs { fr historic_contract_tree_root = 0; fr historic_l1_to_l2_messages_tree_root = 0; fr historic_blocks_tree_root = 0; + fr historic_global_variables_hash = 0; + fr historic_public_data_tree_root = 0; ContractDeploymentData contract_deployment_data{}; @@ -72,6 +74,8 @@ template class PrivateCircuitPublicInputs { historic_contract_tree_root == other.historic_contract_tree_root && historic_l1_to_l2_messages_tree_root == other.historic_l1_to_l2_messages_tree_root && historic_blocks_tree_root == other.historic_blocks_tree_root && + historic_global_variables_hash == other.historic_global_variables_hash && + historic_public_data_tree_root == other.historic_public_data_tree_root && contract_deployment_data == other.contract_deployment_data && chain_id == other.chain_id && version == other.version; }; @@ -112,6 +116,8 @@ template class PrivateCircuitPublicInputs { to_ct(historic_contract_tree_root), to_ct(historic_l1_to_l2_messages_tree_root), to_ct(historic_blocks_tree_root), + to_ct(historic_global_variables_hash), + to_ct(historic_public_data_tree_root), to_circuit_type(contract_deployment_data), @@ -155,6 +161,8 @@ template class PrivateCircuitPublicInputs { to_nt(historic_contract_tree_root), to_nt(historic_l1_to_l2_messages_tree_root), to_nt(historic_blocks_tree_root), + to_nt(historic_global_variables_hash), + to_nt(historic_public_data_tree_root), to_native_type(contract_deployment_data), @@ -197,6 +205,8 @@ template class PrivateCircuitPublicInputs { inputs.push_back(historic_contract_tree_root); inputs.push_back(historic_l1_to_l2_messages_tree_root); inputs.push_back(historic_blocks_tree_root); + inputs.push_back(historic_global_variables_hash); + inputs.push_back(historic_public_data_tree_root); inputs.push_back(contract_deployment_data.hash()); @@ -240,6 +250,8 @@ template void read(uint8_t const*& it, PrivateCircuitPublicInputs read(it, pis.historic_contract_tree_root); read(it, pis.historic_l1_to_l2_messages_tree_root); read(it, pis.historic_blocks_tree_root); + read(it, pis.historic_global_variables_hash); + read(it, pis.historic_public_data_tree_root); read(it, pis.contract_deployment_data); read(it, pis.chain_id); read(it, pis.version); @@ -271,6 +283,8 @@ void write(std::vector& buf, PrivateCircuitPublicInputs const& pri write(buf, pis.historic_contract_tree_root); write(buf, pis.historic_l1_to_l2_messages_tree_root); write(buf, pis.historic_blocks_tree_root); + write(buf, pis.historic_global_variables_hash); + write(buf, pis.historic_public_data_tree_root); write(buf, pis.contract_deployment_data); write(buf, pis.chain_id); @@ -301,6 +315,8 @@ std::ostream& operator<<(std::ostream& os, PrivateCircuitPublicInputs const << "historic_contract_tree_root: " << pis.historic_contract_tree_root << "\n" << "historic_l1_to_l2_messages_tree_root: " << pis.historic_l1_to_l2_messages_tree_root << "\n" << "historic_blocks_tree_root: " << pis.historic_blocks_tree_root << "\n" + << "historic_global_variables_hash: " << pis.historic_global_variables_hash << "\n" + << "historic_public_data_tree_root: " << pis.historic_public_data_tree_root << "\n" << "contract_deployment_data: " << pis.contract_deployment_data << "\n" << "chain_id: " << pis.chain_id << "\n" << "version: " << pis.version << "\n"; @@ -341,6 +357,8 @@ template class OptionalPrivateCircuitPublicInputs { opt_fr historic_contract_tree_root; opt_fr historic_l1_to_l2_messages_tree_root; opt_fr historic_blocks_tree_root; + opt_fr historic_global_variables_hash; + opt_fr historic_public_data_tree_root; std::optional> contract_deployment_data; @@ -376,6 +394,8 @@ template class OptionalPrivateCircuitPublicInputs { opt_fr const& historic_contract_tree_root, opt_fr const& historic_l1_to_l2_messages_tree_root, opt_fr const& historic_blocks_tree_root, + opt_fr const& historic_global_variables_hash, + opt_fr const& historic_public_data_tree_root, std::optional> const& contract_deployment_data, @@ -400,6 +420,8 @@ template class OptionalPrivateCircuitPublicInputs { , historic_contract_tree_root(historic_contract_tree_root) , historic_l1_to_l2_messages_tree_root(historic_l1_to_l2_messages_tree_root) , historic_blocks_tree_root(historic_blocks_tree_root) + , historic_global_variables_hash(historic_global_variables_hash) + , historic_public_data_tree_root(historic_public_data_tree_root) , contract_deployment_data(contract_deployment_data) , chain_id(chain_id) , version(version){}; @@ -436,6 +458,8 @@ template class OptionalPrivateCircuitPublicInputs { new_inputs.historic_contract_tree_root = std::nullopt; new_inputs.historic_l1_to_l2_messages_tree_root = std::nullopt; new_inputs.historic_blocks_tree_root = std::nullopt; + new_inputs.historic_global_variables_hash = std::nullopt; + new_inputs.historic_public_data_tree_root = std::nullopt; new_inputs.contract_deployment_data = std::nullopt; @@ -505,6 +529,8 @@ template class OptionalPrivateCircuitPublicInputs { make_unused_element_zero(builder, historic_contract_tree_root); make_unused_element_zero(builder, historic_l1_to_l2_messages_tree_root); make_unused_element_zero(builder, historic_blocks_tree_root); + make_unused_element_zero(builder, historic_global_variables_hash); + make_unused_element_zero(builder, historic_public_data_tree_root); make_unused_element_zero(builder, contract_deployment_data); @@ -548,6 +574,8 @@ template class OptionalPrivateCircuitPublicInputs { (*historic_contract_tree_root).set_public(); (*historic_l1_to_l2_messages_tree_root).set_public(); (*historic_blocks_tree_root).set_public(); + (*historic_global_variables_hash).set_public(); + (*historic_public_data_tree_root).set_public(); (*contract_deployment_data).set_public(); @@ -593,6 +621,8 @@ template class OptionalPrivateCircuitPublicInputs { to_ct(historic_contract_tree_root), to_ct(historic_l1_to_l2_messages_tree_root), to_ct(historic_blocks_tree_root), + to_ct(historic_global_variables_hash), + to_ct(historic_public_data_tree_root), to_circuit_type(contract_deployment_data), @@ -638,6 +668,8 @@ template class OptionalPrivateCircuitPublicInputs { to_nt(historic_contract_tree_root), to_nt(historic_l1_to_l2_messages_tree_root), to_nt(historic_blocks_tree_root), + to_nt(historic_global_variables_hash), + to_nt(historic_public_data_tree_root), to_native_type(contract_deployment_data), @@ -684,6 +716,8 @@ template class OptionalPrivateCircuitPublicInputs { inputs.push_back(*historic_contract_tree_root); inputs.push_back(*historic_l1_to_l2_messages_tree_root); inputs.push_back(*historic_blocks_tree_root); + inputs.push_back(*historic_global_variables_hash); + inputs.push_back(*historic_public_data_tree_root); inputs.push_back((*contract_deployment_data).hash()); @@ -725,6 +759,8 @@ template class OptionalPrivateCircuitPublicInputs { .historic_contract_tree_root = historic_contract_tree_root.value(), .historic_l1_to_l2_messages_tree_root = historic_l1_to_l2_messages_tree_root.value(), .historic_blocks_tree_root = historic_blocks_tree_root.value(), + .historic_global_variables_hash = historic_global_variables_hash.value(), + .historic_public_data_tree_root = historic_public_data_tree_root.value(), .contract_deployment_data = contract_deployment_data.value(), @@ -825,6 +861,8 @@ void read(uint8_t const*& it, OptionalPrivateCircuitPublicInputs& private_c read(it, pis.historic_contract_tree_root); read(it, pis.historic_l1_to_l2_messages_tree_root); read(it, pis.historic_blocks_tree_root); + read(it, pis.historic_global_variables_hash); + read(it, pis.historic_public_data_tree_root); read(it, pis.contract_deployment_data); read(it, pis.chain_id); read(it, pis.version); @@ -856,6 +894,8 @@ void write(std::vector& buf, OptionalPrivateCircuitPublicInputs co write(buf, pis.historic_contract_tree_root); write(buf, pis.historic_l1_to_l2_messages_tree_root); write(buf, pis.historic_blocks_tree_root); + write(buf, pis.historic_global_variables_hash); + write(buf, pis.historic_public_data_tree_root); write(buf, pis.contract_deployment_data); write(buf, pis.chain_id); write(buf, pis.version); @@ -885,6 +925,8 @@ std::ostream& operator<<(std::ostream& os, OptionalPrivateCircuitPublicInputs const& private_inputs, .contract_tree_root = private_call_public_inputs.historic_contract_tree_root, .l1_to_l2_messages_tree_root = private_call_public_inputs.historic_l1_to_l2_messages_tree_root, }, + .public_data_tree_root = private_call_public_inputs.historic_public_data_tree_root, + .prev_global_variables_hash = private_call_public_inputs.historic_global_variables_hash, }, .tx_context = private_inputs.tx_request.tx_context, }; diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 7a3d6e38450..b9feca2ae06 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -219,7 +219,7 @@ constexpr size_t MAX_NOTES_PER_PAGE = 10; constexpr size_t VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2; constexpr size_t CALL_CONTEXT_LENGTH = 6; -constexpr size_t COMMITMENT_TREES_ROOTS_LENGTH = 5; +constexpr size_t BLOCK_HASH_DATA_LENGTH = 7; constexpr size_t FUNCTION_DATA_LENGTH = 4; constexpr size_t CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; @@ -231,14 +231,14 @@ constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + COMMITMENT_TREES_ROOTS_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version + + BLOCK_HASH_DATA_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 1 + 1 // call_context_hash + args_hash + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + COMMITMENT_TREES_ROOTS_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version + + BLOCK_HASH_DATA_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version constexpr size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; constexpr size_t CONTRACT_STORAGE_READ_LENGTH = 2; @@ -249,8 +249,8 @@ constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL * CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH + MAX_PUBLIC_DATA_READS_PER_CALL * CONTRACT_STORAGE_READ_LENGTH + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + MAX_NEW_NULLIFIERS_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + - NUM_FIELDS_PER_SHA256 + 1 + // + 1 for unencrypted logs preimage length - COMMITMENT_TREES_ROOTS_LENGTH + 2; // + 2 for chain_id and version + NUM_FIELDS_PER_SHA256 + 1 + // + 1 for unencrypted logs preimage length + BLOCK_HASH_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 2 + RETURN_VALUES_LENGTH + // + 1 for args_hash + 1 call_context.hash diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 38aa6dfa762..0dc35f361f4 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -65,18 +65,18 @@ library Constants { uint256 internal constant MAX_NOTES_PER_PAGE = 10; uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; uint256 internal constant CALL_CONTEXT_LENGTH = 6; - uint256 internal constant COMMITMENT_TREES_ROOTS_LENGTH = 5; + uint256 internal constant BLOCK_HASH_DATA_LENGTH = 7; uint256 internal constant FUNCTION_DATA_LENGTH = 4; uint256 internal constant CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 56; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; - uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 75; + uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 77; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 86; uint256 internal constant EMPTY_NULLIFIED_COMMITMENT = 1000000; - uint256 internal constant CALL_PRIVATE_FUNCTION_RETURN_SIZE = 62; + uint256 internal constant CALL_PRIVATE_FUNCTION_RETURN_SIZE = 64; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 41; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 46; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 48; uint256 internal constant COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 1024; uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 1024; uint256 internal constant PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 1024; diff --git a/yarn-project/acir-simulator/src/acvm/deserialize.ts b/yarn-project/acir-simulator/src/acvm/deserialize.ts index dc04badd535..40f46cbb7ed 100644 --- a/yarn-project/acir-simulator/src/acvm/deserialize.ts +++ b/yarn-project/acir-simulator/src/acvm/deserialize.ts @@ -143,6 +143,8 @@ export function extractPublicInputs(partialWitness: ACVMWitness, acir: Buffer): const contractTreeRoot = witnessReader.readField(); const l1Tol2TreeRoot = witnessReader.readField(); const blocksTreeRoot = witnessReader.readField(); + const prevGlobalVariablesHash = witnessReader.readField(); + const publicDataTreeRoot = witnessReader.readField(); const contractDeploymentData = new ContractDeploymentData( new Point(witnessReader.readField(), witnessReader.readField()), @@ -175,6 +177,8 @@ export function extractPublicInputs(partialWitness: ACVMWitness, acir: Buffer): contractTreeRoot, l1Tol2TreeRoot, blocksTreeRoot, + prevGlobalVariablesHash, + publicDataTreeRoot, contractDeploymentData, chainId, version, diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 2b7c150efc4..e4ee748031d 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -1,4 +1,4 @@ -import { CircuitsWasm, PrivateHistoricTreeRoots, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; +import { CircuitsWasm, ConstantBlockHashData, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; import { computeCommitmentNonce } from '@aztec/circuits.js/abis'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; @@ -34,8 +34,8 @@ export class ClientTxExecutionContext { private txNullifier: Fr, /** The tx context. */ public txContext: TxContext, - /** The old roots. */ - public historicRoots: PrivateHistoricTreeRoots, + /** Data required to reconstruct the block hash, it contains historic roots. */ + public constantBlockHashData: ConstantBlockHashData, /** The cache of packed arguments */ public packedArgsCache: PackedArgsCache, /** Pending notes created (and not nullified) up to current point in execution. @@ -57,7 +57,7 @@ export class ClientTxExecutionContext { this.db, this.txNullifier, this.txContext, - this.historicRoots, + this.constantBlockHashData, this.packedArgsCache, this.pendingNotes, this.pendingNullifiers, @@ -199,7 +199,7 @@ export class ClientTxExecutionContext { */ public async getL1ToL2Message(msgKey: Fr): Promise { const messageInputs = await this.db.getL1ToL2Message(msgKey); - return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.historicRoots.l1ToL2MessagesTreeRoot); + return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.constantBlockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot); } /** @@ -212,7 +212,7 @@ export class ClientTxExecutionContext { const commitmentInputs = await this.db.getCommitmentOracle(contractAddress, fromACVMField(commitment)); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1029): support pending commitments here this.readRequestPartialWitnesses.push(ReadRequestMembershipWitness.empty(commitmentInputs.index)); - return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.historicRoots.privateDataTreeRoot); + return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.constantBlockHashData.privateHistoricTreeRoots.privateDataTreeRoot); } /** diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index e61915b7a5a..60de09912e4 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -1,6 +1,7 @@ import { CallContext, CircuitsWasm, + ConstantBlockHashData, ContractDeploymentData, FieldsOf, FunctionData, @@ -60,7 +61,7 @@ describe('Private Execution test suite', () => { let oracle: MockProxy; let acirSimulator: AcirSimulator; let txNullifier: Fr; - let historicRoots = PrivateHistoricTreeRoots.empty(); + let blockHashData = ConstantBlockHashData.empty(); let logger: DebugLogger; const defaultContractAddress = AztecAddress.random(); @@ -111,7 +112,7 @@ describe('Private Execution test suite', () => { abi, functionData.isConstructor ? AztecAddress.ZERO : contractAddress, EthAddress.ZERO, - historicRoots, + blockHashData, ); }; @@ -128,10 +129,14 @@ describe('Private Execution test suite', () => { // Update root. const newRoot = trees[name].getRoot(false); - const prevRoots = historicRoots.toBuffer(); + const prevRoots = blockHashData.privateHistoricTreeRoots.toBuffer(); const rootIndex = name === 'privateData' ? 0 : 32 * 3; const newRoots = Buffer.concat([prevRoots.slice(0, rootIndex), newRoot, prevRoots.slice(rootIndex + 32)]); - historicRoots = PrivateHistoricTreeRoots.fromBuffer(newRoots); + blockHashData = new ConstantBlockHashData( + PrivateHistoricTreeRoots.fromBuffer(newRoots), + Fr.ZERO, + Fr.ZERO, + ); return trees[name]; }; diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index 57fb3c34bc3..4188a719a4c 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -218,6 +218,8 @@ export class PrivateFunctionExecution { */ private writeInputs() { const contractDeploymentData = this.context.txContext.contractDeploymentData ?? ContractDeploymentData.empty(); + const blockData = this.context.constantBlockHashData; + const {privateHistoricTreeRoots} = blockData; const fields = [ this.callContext.msgSender, @@ -227,11 +229,15 @@ export class PrivateFunctionExecution { this.callContext.isStaticCall, this.callContext.isContractDeployment, - this.context.historicRoots.privateDataTreeRoot, - this.context.historicRoots.nullifierTreeRoot, - this.context.historicRoots.contractTreeRoot, - this.context.historicRoots.l1ToL2MessagesTreeRoot, - this.context.historicRoots.blocksTreeRoot, + privateHistoricTreeRoots.privateDataTreeRoot, + privateHistoricTreeRoots.nullifierTreeRoot, + privateHistoricTreeRoots.contractTreeRoot, + privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + privateHistoricTreeRoots.blocksTreeRoot, + + // TODO: may need these + blockData.prevGlobalVariablesHash, + blockData.publicDataTreeRoot, contractDeploymentData.deployerPublicKey.x, contractDeploymentData.deployerPublicKey.y, diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index 425d1caf27b..57d144bdbd3 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -1,4 +1,4 @@ -import { CallContext, CircuitsWasm, FunctionData, PrivateHistoricTreeRoots, TxContext } from '@aztec/circuits.js'; +import { CallContext, CircuitsWasm, ConstantBlockHashData, FunctionData, TxContext } from '@aztec/circuits.js'; import { computeTxHash } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { ArrayType, FunctionAbi, FunctionType, encodeArguments } from '@aztec/foundation/abi'; @@ -32,7 +32,7 @@ export class AcirSimulator { * @param entryPointABI - The ABI of the entry point function. * @param contractAddress - The address of the contract (should match request.origin) * @param portalContractAddress - The address of the portal contract. - * @param historicRoots - The historic roots. + * @param constantBlockHashData - Data required to reconstruct the block hash, this also contains the historic tree roots. * @param curve - The curve instance for elliptic curve operations. * @param packedArguments - The entrypoint packed arguments * @returns The result of the execution. @@ -42,7 +42,7 @@ export class AcirSimulator { entryPointABI: FunctionAbi, contractAddress: AztecAddress, portalContractAddress: EthAddress, - historicRoots: PrivateHistoricTreeRoots, + constantBlockHashData: ConstantBlockHashData, ): Promise { if (entryPointABI.functionType !== FunctionType.SECRET) { throw new Error(`Cannot run ${entryPointABI.functionType} function as secret`); @@ -70,7 +70,7 @@ export class AcirSimulator { this.db, txNullifier, request.txContext, - historicRoots, + constantBlockHashData, await PackedArgsCache.create(request.packedArguments), ), entryPointABI, @@ -90,7 +90,7 @@ export class AcirSimulator { * @param entryPointABI - The ABI of the entry point function. * @param contractAddress - The address of the contract. * @param portalContractAddress - The address of the portal contract. - * @param historicRoots - The historic roots. + * @param constantBlockHashData - Block data containing historic roots. * @returns The return values of the function. */ public async runUnconstrained( @@ -98,7 +98,7 @@ export class AcirSimulator { entryPointABI: FunctionAbi, contractAddress: AztecAddress, portalContractAddress: EthAddress, - historicRoots: PrivateHistoricTreeRoots, + constantBlockHashData: ConstantBlockHashData, ) { if (entryPointABI.functionType !== FunctionType.UNCONSTRAINED) { throw new Error(`Cannot run ${entryPointABI.functionType} function as constrained`); @@ -117,7 +117,7 @@ export class AcirSimulator { this.db, Fr.ZERO, TxContext.empty(), - historicRoots, + constantBlockHashData, await PackedArgsCache.create([]), ), entryPointABI, @@ -162,7 +162,7 @@ export class AcirSimulator { abi, AztecAddress.ZERO, EthAddress.ZERO, - PrivateHistoricTreeRoots.empty(), + ConstantBlockHashData.empty(), ); return { diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts index bb93bb3cfe1..33ec6418752 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts @@ -1,4 +1,4 @@ -import { CircuitsWasm, FunctionData, PrivateHistoricTreeRoots, PrivateKey } from '@aztec/circuits.js'; +import { CircuitsWasm, ConstantBlockHashData, FunctionData, PrivateHistoricTreeRoots, PrivateKey } from '@aztec/circuits.js'; import { computeContractAddressFromPartial } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { encodeArguments } from '@aztec/foundation/abi'; @@ -60,7 +60,7 @@ describe('Unconstrained Execution test suite', () => { const preimages = [...Array(5).fill(buildNote(1n, owner)), ...Array(2).fill(buildNote(2n, owner))]; - const historicRoots = PrivateHistoricTreeRoots.empty(); + const constantBlockHashData = ConstantBlockHashData.empty(); oracle.getNotes.mockResolvedValue( preimages.map((preimage, index) => ({ @@ -86,7 +86,7 @@ describe('Unconstrained Execution test suite', () => { abi, AztecAddress.random(), EthAddress.ZERO, - historicRoots, + constantBlockHashData, ); expect(result).toEqual([9n]); diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 1afa07c9f05..fadb32b321b 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -1,20 +1,17 @@ import { + ExecutionResult, collectEncryptedLogs, collectEnqueuedPublicFunctionCalls, collectUnencryptedLogs, } from '@aztec/acir-simulator'; import { AztecAddress, - CircuitsWasm, ConstantBlockHashData, FunctionData, - GlobalVariables, PartialContractAddress, - PrivateHistoricTreeRoots, PrivateKey, PublicKey, } from '@aztec/circuits.js'; -import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { encodeArguments } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; @@ -30,7 +27,6 @@ import { L2Block, L2BlockL2Logs, LogType, - MerkleTreeId, NodeInfo, Tx, TxExecutionRequest, @@ -343,9 +339,9 @@ export class AztecRPCServer implements AztecRPC { async #simulate( txRequest: TxExecutionRequest, - prevBlockData: ConstantBlockHashData, + constantBlockHashData: ConstantBlockHashData, contractDataOracle?: ContractDataOracle, - ) { + ): Promise { // TODO - Pause syncing while simulating. if (!contractDataOracle) { contractDataOracle = new ContractDataOracle(this.db, this.node); @@ -365,7 +361,7 @@ export class AztecRPCServer implements AztecRPC { functionAbi, contractAddress, portalContract, - prevBlockData.privateHistoricTreeRoots, + constantBlockHashData, ); this.log('Simulation completed!'); @@ -381,13 +377,13 @@ export class AztecRPCServer implements AztecRPC { * Returns the simulation result containing the outputs of the unconstrained function. * * @param execRequest - The transaction request object containing the target contract and function data. - * @param prevBlockData - All data required to reconstruct the previous block hash. // TODO: Maybe just pass in one value for this instead of recomputing everywhere? Cache at the beginning? + * @param constantBlockHashData - All data required to reconstruct the previous block hash. // TODO: Maybe just pass in one value for this instead of recomputing everywhere? Cache at the beginning? * @param contractDataOracle - Optional instance of ContractDataOracle for fetching and caching contract information. * @returns The simulation result containing the outputs of the unconstrained function. */ async #simulateUnconstrained( execRequest: ExecutionRequest, - prevBlockData: ConstantBlockHashData = ConstantBlockHashData.empty(), + constantBlockHashData: ConstantBlockHashData = ConstantBlockHashData.empty(), contractDataOracle?: ContractDataOracle, ) { if (!contractDataOracle) { @@ -407,13 +403,14 @@ export class AztecRPCServer implements AztecRPC { functionAbi, contractAddress, portalContract, - prevBlockData.privateHistoricTreeRoots, + constantBlockHashData, ); this.log('Unconstrained simulation completed!'); return result; } + /** * Simulate a transaction, generate a kernel proof, and create a private transaction object. * The function takes in a transaction request and an ECDSA signature. It simulates the transaction, @@ -429,35 +426,14 @@ export class AztecRPCServer implements AztecRPC { async #simulateAndProve(txExecutionRequest: TxExecutionRequest, newContract: ContractDao | undefined) { // TODO - Pause syncing while simulating. - //TODO(MADDIAA) MAYBE WE SHOULD GET THE LATEST BLOCK TREE ROOTS HERE AND PASS THEM DOWN EVERYWHERE? - - // Add values that allow us to reconstruct the block hash - const wasm = await CircuitsWasm.get(); - const latestBlock = await this.getBlock(-1); - const latestGlobals = latestBlock?.globalVariables ?? GlobalVariables.empty(); - const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); - const treeRoots = this.db.getTreeRoots(); - - - - const historicTreeRoots = new ConstantBlockHashData( - new PrivateHistoricTreeRoots( - treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], - treeRoots[MerkleTreeId.NULLIFIER_TREE], - treeRoots[MerkleTreeId.CONTRACT_TREE], - treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], - treeRoots[MerkleTreeId.BLOCKS_TREE], - Fr.ZERO, - ), - treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], - prevBlockGlobalVariablesHash, - ); const contractDataOracle = new ContractDataOracle(this.db, this.node); - - // TODO: maybe could put above in this kernel oracle const kernelOracle = new KernelOracle(contractDataOracle, this.node); - const executionResult = await this.#simulate(txExecutionRequest, historicTreeRoots, contractDataOracle); + + // Get values that allow us to reconstruct the block hash + const constantBlockHashData = await kernelOracle.getConstantBlockHashData(); + + const executionResult = await this.#simulate(txExecutionRequest, constantBlockHashData, contractDataOracle); const kernelProver = new KernelProver(kernelOracle); this.log(`Executing kernel prover...`); @@ -465,7 +441,7 @@ export class AztecRPCServer implements AztecRPC { this.log('Proof completed!'); // TODO: FIX HACK< OVERWRITING THE ROOTS HERE - publicInputs.constants.blockHashValues = historicTreeRoots; + publicInputs.constants.blockHashValues = constantBlockHashData; const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; diff --git a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts index a52a160f029..53106ca63b8 100644 --- a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts @@ -1,9 +1,10 @@ -import { AztecAddress, Fr, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT } from '@aztec/circuits.js'; +import { AztecAddress, CircuitsWasm, ConstantBlockHashData, Fr, GlobalVariables, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; import { Tuple } from '@aztec/foundation/serialize'; import { AztecNode, MerkleTreeId } from '@aztec/types'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A data oracle that provides information needed for simulating a transaction. @@ -36,4 +37,25 @@ export class KernelOracle implements ProvingDataOracle { const roots = await this.node.getTreeRoots(); return roots[MerkleTreeId.PRIVATE_DATA_TREE]; } + + async getConstantBlockHashData(): Promise { + const wasm = await CircuitsWasm.get(); + const latestBlock = await this.node.getBlock(-1); + const latestGlobals = latestBlock?.globalVariables ?? GlobalVariables.empty(); + const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); + const treeRoots = await this.node.getTreeRoots(); + + return new ConstantBlockHashData( + new PrivateHistoricTreeRoots( + treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], + treeRoots[MerkleTreeId.NULLIFIER_TREE], + treeRoots[MerkleTreeId.CONTRACT_TREE], + treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], + treeRoots[MerkleTreeId.BLOCKS_TREE], + Fr.ZERO, + ), + treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], + prevBlockGlobalVariablesHash, + ); + } } diff --git a/yarn-project/circuits.js/src/cbind/constants.gen.ts b/yarn-project/circuits.js/src/cbind/constants.gen.ts index a2a02bdb9f9..dffd168161a 100644 --- a/yarn-project/circuits.js/src/cbind/constants.gen.ts +++ b/yarn-project/circuits.js/src/cbind/constants.gen.ts @@ -51,18 +51,18 @@ export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; export const CALL_CONTEXT_LENGTH = 6; -export const COMMITMENT_TREES_ROOTS_LENGTH = 5; +export const BLOCK_HASH_DATA_LENGTH = 7; export const FUNCTION_DATA_LENGTH = 4; export const CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 56; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; export const CONTRACT_STORAGE_READ_LENGTH = 2; -export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 75; +export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 77; export const GET_NOTES_ORACLE_RETURN_LENGTH = 86; export const EMPTY_NULLIFIED_COMMITMENT = 1000000; -export const CALL_PRIVATE_FUNCTION_RETURN_SIZE = 62; +export const CALL_PRIVATE_FUNCTION_RETURN_SIZE = 64; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 41; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 46; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 48; export const COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 1024; export const NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 1024; export const PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 1024; diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index cc67d2285c6..0c2b4c70fad 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -94,13 +94,21 @@ export class PrivateCircuitPublicInputs { */ public historicContractTreeRoot: Fr, /** - * Root of the L2 to L1 messages tree roots tree. + * Root of the L2 to L1 messages tree. */ public historicL1ToL2MessagesTreeRoot: Fr, /** * Root of the Blocks roots tree. */ public historicBlocksTreeRoot: Fr, + /** + * Previous blocks global variables hash. + */ + public historicGlobalVariablesHash: Fr, + /** + * Root of the Public Data tree. + */ + public historicPublicDataTreeRoot: Fr, /** * Deployment data of contracts being deployed in this kernel iteration. */ @@ -163,6 +171,8 @@ export class PrivateCircuitPublicInputs { Fr.ZERO, Fr.ZERO, Fr.ZERO, + Fr.ZERO, + Fr.ZERO, ContractDeploymentData.empty(), Fr.ZERO, Fr.ZERO, @@ -195,6 +205,8 @@ export class PrivateCircuitPublicInputs { fields.historicContractTreeRoot, fields.historicL1ToL2MessagesTreeRoot, fields.historicBlocksTreeRoot, + fields.historicGlobalVariablesHash, + fields.historicPublicDataTreeRoot, fields.contractDeploymentData, fields.chainId, fields.version, diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 861230713a5..d5b88d0138a 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -652,9 +652,11 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn historicPrivateNullifierTreeRoot: fr(seed + 0xf00), historicL1ToL2MessagesTreeRoot: fr(seed + 0x1000), historicBlocksTreeRoot: fr(seed + 0x1100), + historicGlobalVariablesHash: fr(seed + 0x1200), + historicPublicDataTreeRoot: fr(seed + 0x1300), contractDeploymentData: makeContractDeploymentData(), - chainId: fr(seed + 0x1200), - version: fr(seed + 0x1300), + chainId: fr(seed + 0x1400), + version: fr(seed + 0x1500), }); } diff --git a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr index ab590d6e41d..d20d9a27233 100644 --- a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/main.nr @@ -265,7 +265,7 @@ contract NonNativeToken { // Assert that the note exists within the tree let public_note = TransparentNote::new_from_secret(amount, secret); - public_note.consume_in_secret(&mut context, inputs.roots.private_data_tree_root, secret); + public_note.consume_in_secret(&mut context, inputs.block_hash_data.private_data_tree_root, secret); // Mint the tokens let balance = storage.balances.at(owner); diff --git a/yarn-project/noir-libs/noir-aztec/src/abi.nr b/yarn-project/noir-libs/noir-aztec/src/abi.nr index c5c7ca7c75f..428eb913b1b 100644 --- a/yarn-project/noir-libs/noir-aztec/src/abi.nr +++ b/yarn-project/noir-libs/noir-aztec/src/abi.nr @@ -10,7 +10,7 @@ use crate::constants_gen::{ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, GENERATOR_INDEX__FUNCTION_ARGS, - COMMITMENT_TREES_ROOTS_LENGTH, + BLOCK_HASH_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, CALL_CONTEXT_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, @@ -35,7 +35,7 @@ use crate::types::point::Point; // PrivateContextInputs are expected to be provided to each private function struct PrivateContextInputs { call_context : CallContext, - roots: CommitmentTreesRoots, + block_hash_data: BlockHashData, contract_deployment_data: ContractDeploymentData, @@ -45,7 +45,7 @@ struct PrivateContextInputs { // PublicContextInputs are expected to be provided to each public function struct PublicContextInputs { call_context: CallContext, - roots: CommitmentTreesRoots, + block_hash_data: BlockHashData, public_global_variables: PublicGlobalVariables, } @@ -77,29 +77,33 @@ impl CallContext { } } -struct CommitmentTreesRoots { +struct BlockHashData { private_data_tree_root : Field, nullifier_tree_root : Field, contract_tree_root : Field, l1_to_l2_messages_tree_root : Field, blocks_tree_root: Field, + prev_global_variables_hash: Field, + public_data_tree_root: Field, } -impl CommitmentTreesRoots { +impl BlockHashData { // NOTE: this order must match the order in `private_circuit_public_inputs.hpp` - fn serialize(self) -> [Field; COMMITMENT_TREES_ROOTS_LENGTH] { + fn serialize(self) -> [Field; BLOCK_HASH_DATA_LENGTH] { [ self.private_data_tree_root, self.nullifier_tree_root, self.contract_tree_root, self.l1_to_l2_messages_tree_root, self.blocks_tree_root, + self.prev_global_variables_hash, + self.public_data_tree_root ] } } -fn empty_commitment_trees_roots() -> CommitmentTreesRoots { - CommitmentTreesRoots{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0 } +fn empty_block_hash_data() -> BlockHashData { + BlockHashData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } } struct ContractDeploymentData { @@ -186,7 +190,7 @@ struct PrivateCircuitPublicInputs { unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, - commitment_trees_roots: CommitmentTreesRoots, + block_hash_data: BlockHashData, contract_deployment_data: ContractDeploymentData, chain_id: Field, version: Field, @@ -209,7 +213,7 @@ impl PrivateCircuitPublicInputs { fields.push_array(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.commitment_trees_roots.serialize()); + fields.push_array(self.block_hash_data.serialize()); fields.push(self.contract_deployment_data.hash()); fields.push(self.chain_id); fields.push(self.version); @@ -232,7 +236,7 @@ impl PrivateCircuitPublicInputs { fields.push_array(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.commitment_trees_roots.serialize()); + fields.push_array(self.block_hash_data.serialize()); fields.push_array(self.contract_deployment_data.serialize()); fields.push(self.chain_id); fields.push(self.version); @@ -292,7 +296,7 @@ struct PublicCircuitPublicInputs { new_l2_to_l1_msgs: [Field; crate::abi::MAX_NEW_L2_TO_L1_MSGS_PER_CALL], unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: Field, - commitment_trees_roots: CommitmentTreesRoots, // TODO: This is not present in cpp or ts, do we need to include it? + block_hash_data: BlockHashData, // TODO: This is not present in cpp or ts, do we need to include it? historic_public_data_tree_root: Field, prover_address: Field, } @@ -315,8 +319,8 @@ impl PublicCircuitPublicInputs { inputs.push_array(self.new_nullifiers); inputs.push_array(self.new_l2_to_l1_msgs); - // We do not include commitment_trees_roots since it's not in the cpp hash - // inputs.push(self.commitment_trees_roots.hash()); + // We do not include block_hash_data since it's not in the cpp hash + // inputs.push(self.block_hash_data.hash()); inputs.push_array(self.unencrypted_logs_hash); inputs.push(self.unencrypted_log_preimages_length); @@ -343,7 +347,7 @@ impl PublicCircuitPublicInputs { fields.push_array(self.new_l2_to_l1_msgs); fields.push_array(self.unencrypted_logs_hash); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.commitment_trees_roots.serialize()); + fields.push_array(self.block_hash_data.serialize()); fields.push(self.historic_public_data_tree_root); fields.push(self.prover_address); fields.storage diff --git a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr index a725a3f7c62..a45aa4ac156 100644 --- a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr +++ b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr @@ -50,18 +50,18 @@ global GET_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 23; global MAX_NOTES_PER_PAGE: comptime Field = 10; global VIEW_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 212; global CALL_CONTEXT_LENGTH: comptime Field = 6; -global COMMITMENT_TREES_ROOTS_LENGTH: comptime Field = 5; +global BLOCK_HASH_DATA_LENGTH: comptime Field = 7; global FUNCTION_DATA_LENGTH: comptime Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: comptime Field = 6; -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 56; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 58; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: comptime Field = 3; global CONTRACT_STORAGE_READ_LENGTH: comptime Field = 2; -global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 75; +global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 77; global GET_NOTES_ORACLE_RETURN_LENGTH: comptime Field = 86; global EMPTY_NULLIFIED_COMMITMENT: comptime Field = 1000000; -global CALL_PRIVATE_FUNCTION_RETURN_SIZE: comptime Field = 62; +global CALL_PRIVATE_FUNCTION_RETURN_SIZE: comptime Field = 64; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: comptime Field = 41; -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: comptime Field = 46; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: comptime Field = 48; global COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP: comptime Field = 1024; global NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: comptime Field = 1024; global PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: comptime Field = 1024; diff --git a/yarn-project/noir-libs/noir-aztec/src/context.nr b/yarn-project/noir-libs/noir-aztec/src/context.nr index 0b1c41ad28b..0e5c9161335 100644 --- a/yarn-project/noir-libs/noir-aztec/src/context.nr +++ b/yarn-project/noir-libs/noir-aztec/src/context.nr @@ -15,13 +15,13 @@ use crate::constants_gen::{ use crate::abi; use crate::abi::{ - empty_commitment_trees_roots, + empty_block_hash_data, empty_contract_storage_read, empty_contract_storage_update_request, hash_args, CallContext, ContractDeploymentData, - CommitmentTreesRoots, + BlockHashData, FunctionData, PrivateCircuitPublicInputs, PublicCircuitPublicInputs, @@ -118,7 +118,7 @@ impl Context { unencrypted_logs_hash: unencrypted_logs_hash, encrypted_log_preimages_length: encrypted_log_preimages_length, unencrypted_log_preimages_length: unencrypted_log_preimages_length, - commitment_trees_roots: self.inputs.roots, + block_hash_data: self.inputs.block_hash_data, contract_deployment_data: self.inputs.contract_deployment_data, chain_id: self.inputs.private_global_variables.chain_id, version: self.inputs.private_global_variables.version, @@ -146,7 +146,7 @@ impl Context { // PrivateContextInputs must be temporarily passed in to prevent too many unknowns // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned fn consume_l1_to_l2_message(&mut self, inputs: abi::PrivateContextInputs, msg_key: Field, content: Field, secret: Field) { - let nullifier = process_l1_to_l2_message(inputs.roots.l1_to_l2_messages_tree_root, inputs.call_context.storage_contract_address, msg_key, content, secret); + let nullifier = process_l1_to_l2_message(inputs.block_hash_data.l1_to_l2_messages_tree_root, inputs.call_context.storage_contract_address, msg_key, content, secret); // Push nullifier (and the "commitment" corresponding to this can be "empty") self.push_new_nullifier(nullifier, EMPTY_NULLIFIED_COMMITMENT) @@ -214,25 +214,27 @@ impl Context { unencrypted_logs_hash: arr_copy_slice(fields, [0; NUM_FIELDS_PER_SHA256], 44), encrypted_log_preimages_length: fields[46], unencrypted_log_preimages_length: fields[47], - commitment_trees_roots: CommitmentTreesRoots { + block_hash_data: BlockHashData { // Must match order in `private_circuit_public_inputs.hpp` private_data_tree_root : fields[48], nullifier_tree_root : fields[49], contract_tree_root : fields[50], l1_to_l2_messages_tree_root : fields[51], blocks_tree_root : fields[52], + prev_global_variables_hash: fields[53], + public_data_tree_root: fields[54], }, contract_deployment_data: ContractDeploymentData { - deployer_public_key: Point::new(fields[53], fields[54]), - constructor_vk_hash : fields[55], - function_tree_root : fields[56], - contract_address_salt : fields[57], - portal_contract_address : fields[58], + deployer_public_key: Point::new(fields[55], fields[56]), + constructor_vk_hash : fields[57], + function_tree_root : fields[58], + contract_address_salt : fields[59], + portal_contract_address : fields[60], }, - chain_id: fields[59], - version: fields[60], + chain_id: fields[61], + version: fields[62], }, - is_execution_request: fields[61] as bool, + is_execution_request: fields[63] as bool, }; assert(contract_address == item.contract_address); assert(function_selector == item.function_data.function_selector); @@ -306,7 +308,7 @@ impl Context { new_l2_to_l1_msgs:[0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], unencrypted_logs_hash:[0; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: 0, - commitment_trees_roots: empty_commitment_trees_roots(), + block_hash_data: empty_block_hash_data(), historic_public_data_tree_root: 0, prover_address: 0, }, diff --git a/yarn-project/noir-libs/noir-aztec/src/messaging.nr b/yarn-project/noir-libs/noir-aztec/src/messaging.nr index a340c260967..d74a8f31ff1 100644 --- a/yarn-project/noir-libs/noir-aztec/src/messaging.nr +++ b/yarn-project/noir-libs/noir-aztec/src/messaging.nr @@ -10,7 +10,7 @@ use crate::oracle::get_l1_to_l2_message::get_l1_to_l2_message_call; // TODO(Maddiaa): Where to put this code?, a context would make sense but public calls dont _really_ have one? - come back to. fn consume_l1_to_l2_message_public(pub_context: PublicContextInputs, msg_key: Field, content: Field, secret: Field) { - let nullifier = process_l1_to_l2_message(pub_context.roots.l1_to_l2_messages_tree_root, pub_context.call_context.storage_contract_address, msg_key, content, secret); + let nullifier = process_l1_to_l2_message(pub_context.block_hash_data.l1_to_l2_messages_tree_root, pub_context.call_context.storage_contract_address, msg_key, content, secret); // Push nullifier create_nullifier(nullifier); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 9ac9b30eaa7..f752b826112 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -509,18 +509,19 @@ export class SoloBlockBuilder implements BlockBuilder { } protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { - const historicTreeRoots = tx.data.constants.blockHashValues; - const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = - historicTreeRoots.privateHistoricTreeRoots; const wasm = await CircuitsWasm.get(); + + const blockHashValues = tx.data.constants.blockHashValues; + const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = + blockHashValues.privateHistoricTreeRoots; const blockHash = computeBlockHash( wasm, - historicTreeRoots.prevGlobalVariablesHash, + blockHashValues.prevGlobalVariablesHash, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot, - historicTreeRoots.publicDataTreeRoot, + blockHashValues.publicDataTreeRoot, ); return this.getMembershipWitnessFor(blockHash, MerkleTreeId.BLOCKS_TREE, HISTORIC_BLOCKS_TREE_HEIGHT); } diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 98b52ace0b8..6dee2a3c435 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -10,7 +10,7 @@ import { PRIVATE_DATA_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { computeBlockHashWithGlobals } from '@aztec/circuits.js/abis'; +import { computeBlockHashWithGlobals, computeGlobalsHash } from '@aztec/circuits.js/abis'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IWasmModule } from '@aztec/foundation/wasm'; @@ -52,7 +52,6 @@ export class MerkleTrees implements MerkleTreeDb { /** * Initialises the collection of Merkle Trees. - * @param genesisConfig - The genesis config to use for initialising the trees. * @param optionalWasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). */ public async init(optionalWasm?: IWasmModule) { @@ -105,8 +104,7 @@ export class MerkleTrees implements MerkleTreeDb { this.jobQueue.start(); - // The roots trees must contain the empty roots of their data trees - // The first leaf in the tree contains empty roots + // The first leaf in the blocks tree contains the empty roots of the other trees and empty global variables. await this.updateHistoricBlocksTree(GlobalVariables.empty(), true); await historicBlocksTree.commit(); } @@ -114,11 +112,9 @@ export class MerkleTrees implements MerkleTreeDb { /** * Method to asynchronously create and initialise a MerkleTrees instance. * @param db - The db instance to use for data persistance. - * @param genesisConfig - Initial global variables to initialise the blockHash. * @param wasm - WASM instance to use for hashing (if not provided PrimitivesWasm will be used). * @returns - A fully initialised MerkleTrees instance. */ - // TODO: remove genesis config public static async new(db: levelup.LevelUp, wasm?: IWasmModule) { const merkleTrees = new MerkleTrees(db); await merkleTrees.init(wasm); @@ -179,11 +175,11 @@ export class MerkleTrees implements MerkleTreeDb { return { privateDataTreeRoot: roots[0], - contractDataTreeRoot: roots[1], - l1Tol2MessagesTreeRoot: roots[2], - nullifierTreeRoot: roots[3], - blocksTreeRoot: roots[4], - publicDataTreeRoot: roots[5], + nullifierTreeRoot: roots[1], + contractDataTreeRoot: roots[2], + l1Tol2MessagesTreeRoot: roots[3], + publicDataTreeRoot: roots[4], + blocksTreeRoot: roots[5], }; } @@ -196,11 +192,11 @@ export class MerkleTrees implements MerkleTreeDb { getAllTreeRoots(includeUncommitted: boolean): Buffer[] { return [ MerkleTreeId.PRIVATE_DATA_TREE, + MerkleTreeId.NULLIFIER_TREE, MerkleTreeId.CONTRACT_TREE, MerkleTreeId.L1_TO_L2_MESSAGES_TREE, - MerkleTreeId.NULLIFIER_TREE, + MerkleTreeId.PUBLIC_DATA_TREE, MerkleTreeId.BLOCKS_TREE, - MerkleTreeId.PRIVATE_DATA_TREE, ].map(tree => this.trees[tree].getRoot(includeUncommitted)); } From 4f124e355acfd0b25e13425f9728dc15cb20a98a Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:02:24 +0000 Subject: [PATCH 40/58] hmmm, lint so good... gang gang, hmmm, lint so good --- .../src/client/client_execution_context.ts | 10 ++++++++-- .../src/client/private_execution.test.ts | 6 +----- .../acir-simulator/src/client/private_execution.ts | 2 +- .../src/client/unconstrained_execution.test.ts | 7 ++++++- yarn-project/archiver/src/archiver/archiver.ts | 2 +- .../archiver/src/archiver/archiver_store.ts | 2 +- yarn-project/aztec-node/src/aztec-node/server.ts | 3 +-- .../src/aztec_rpc_server/aztec_rpc_server.ts | 2 -- yarn-project/aztec-rpc/src/kernel_oracle/index.ts | 13 +++++++++++-- .../src/structs/kernel/combined_constant_data.ts | 2 +- .../src/structs/kernel/constant_block_hash_data.ts | 3 +-- .../sequencer-client/src/sequencer/utils.ts | 8 +------- .../world-state/src/world-state-db/merkle_trees.ts | 4 ++-- 13 files changed, 35 insertions(+), 29 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index e4ee748031d..3d9b6e6850f 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -199,7 +199,10 @@ export class ClientTxExecutionContext { */ public async getL1ToL2Message(msgKey: Fr): Promise { const messageInputs = await this.db.getL1ToL2Message(msgKey); - return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.constantBlockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot); + return toAcvmL1ToL2MessageLoadOracleInputs( + messageInputs, + this.constantBlockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + ); } /** @@ -212,7 +215,10 @@ export class ClientTxExecutionContext { const commitmentInputs = await this.db.getCommitmentOracle(contractAddress, fromACVMField(commitment)); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1029): support pending commitments here this.readRequestPartialWitnesses.push(ReadRequestMembershipWitness.empty(commitmentInputs.index)); - return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.constantBlockHashData.privateHistoricTreeRoots.privateDataTreeRoot); + return toAcvmCommitmentLoadOracleInputs( + commitmentInputs, + this.constantBlockHashData.privateHistoricTreeRoots.privateDataTreeRoot, + ); } /** diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index 60de09912e4..63e4ac3fb49 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -132,11 +132,7 @@ describe('Private Execution test suite', () => { const prevRoots = blockHashData.privateHistoricTreeRoots.toBuffer(); const rootIndex = name === 'privateData' ? 0 : 32 * 3; const newRoots = Buffer.concat([prevRoots.slice(0, rootIndex), newRoot, prevRoots.slice(rootIndex + 32)]); - blockHashData = new ConstantBlockHashData( - PrivateHistoricTreeRoots.fromBuffer(newRoots), - Fr.ZERO, - Fr.ZERO, - ); + blockHashData = new ConstantBlockHashData(PrivateHistoricTreeRoots.fromBuffer(newRoots), Fr.ZERO, Fr.ZERO); return trees[name]; }; diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index 4188a719a4c..625f0dd4e4a 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -219,7 +219,7 @@ export class PrivateFunctionExecution { private writeInputs() { const contractDeploymentData = this.context.txContext.contractDeploymentData ?? ContractDeploymentData.empty(); const blockData = this.context.constantBlockHashData; - const {privateHistoricTreeRoots} = blockData; + const { privateHistoricTreeRoots } = blockData; const fields = [ this.callContext.msgSender, diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts index 33ec6418752..e21282ebec0 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts @@ -1,4 +1,9 @@ -import { CircuitsWasm, ConstantBlockHashData, FunctionData, PrivateHistoricTreeRoots, PrivateKey } from '@aztec/circuits.js'; +import { + CircuitsWasm, + ConstantBlockHashData, + FunctionData, + PrivateKey, +} from '@aztec/circuits.js'; import { computeContractAddressFromPartial } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { encodeArguments } from '@aztec/foundation/abi'; diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 8b8c44a45e3..3019b0d2360 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -278,7 +278,7 @@ export class Archiver implements L2BlockSource, L2LogsSource, ContractDataSource number = this.store.getBlocksLength(); } const blocks = await this.store.getL2Blocks(number, 1); - return (blocks.length === 0) ? undefined : blocks[0]; + return blocks.length === 0 ? undefined : blocks[0]; } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index e4a8f3125fc..76fa6d50870 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -257,7 +257,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ public getL2Blocks(from: number, limit: number): Promise { // Return an empty array if we are outside of range - if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length) { + if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length) { return Promise.resolve([]); } const startIndex = from - INITIAL_L2_BLOCK_NUM; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 3638b60f6a3..5474dcfe6e8 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -3,14 +3,13 @@ import { CONTRACT_TREE_HEIGHT, CircuitsWasm, Fr, - GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT, PRIVATE_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; import { InMemoryTxPool, P2P, createP2PClient } from '@aztec/p2p'; -import { SequencerClient, getConstantBlockHashData } from '@aztec/sequencer-client'; +import { SequencerClient } from '@aztec/sequencer-client'; import { AztecNode, ContractData, diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index fadb32b321b..d371b527693 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -410,7 +410,6 @@ export class AztecRPCServer implements AztecRPC { return result; } - /** * Simulate a transaction, generate a kernel proof, and create a private transaction object. * The function takes in a transaction request and an ECDSA signature. It simulates the transaction, @@ -426,7 +425,6 @@ export class AztecRPCServer implements AztecRPC { async #simulateAndProve(txExecutionRequest: TxExecutionRequest, newContract: ContractDao | undefined) { // TODO - Pause syncing while simulating. - const contractDataOracle = new ContractDataOracle(this.db, this.node); const kernelOracle = new KernelOracle(contractDataOracle, this.node); diff --git a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts index 53106ca63b8..d715d9b208d 100644 --- a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts @@ -1,10 +1,19 @@ -import { AztecAddress, CircuitsWasm, ConstantBlockHashData, Fr, GlobalVariables, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { + AztecAddress, + CircuitsWasm, + ConstantBlockHashData, + Fr, + GlobalVariables, + MembershipWitness, + PRIVATE_DATA_TREE_HEIGHT, + PrivateHistoricTreeRoots, +} from '@aztec/circuits.js'; +import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { Tuple } from '@aztec/foundation/serialize'; import { AztecNode, MerkleTreeId } from '@aztec/types'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { ProvingDataOracle } from './../kernel_prover/proving_data_oracle.js'; -import { computeGlobalsHash } from '@aztec/circuits.js/abis'; /** * A data oracle that provides information needed for simulating a transaction. diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index d59c9de2f1f..9d037619ea8 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -1,9 +1,9 @@ import { BufferReader } from '@aztec/foundation/serialize'; + import { serializeToBuffer } from '../../utils/serialize.js'; import { TxContext } from '../tx_context.js'; import { ConstantBlockHashData } from './constant_block_hash_data.js'; - /** * Data that is constant/not modified by neither of the kernels. */ diff --git a/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts b/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts index e2f52687d60..d88e1719864 100644 --- a/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts @@ -1,4 +1,3 @@ - import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; @@ -139,4 +138,4 @@ export class ConstantBlockHashData { static empty() { return new ConstantBlockHashData(PrivateHistoricTreeRoots.empty(), Fr.ZERO, Fr.ZERO); } -} \ No newline at end of file +} diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 34f38414a46..d27d5626d07 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -1,10 +1,4 @@ -import { - CircuitsWasm, - ConstantBlockHashData, - Fr, - GlobalVariables, - PrivateHistoricTreeRoots, -} from '@aztec/circuits.js'; +import { CircuitsWasm, ConstantBlockHashData, Fr, GlobalVariables, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { MerkleTreeOperations } from '@aztec/world-state'; diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 6dee2a3c435..5c535131c04 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -10,7 +10,7 @@ import { PRIVATE_DATA_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { computeBlockHashWithGlobals, computeGlobalsHash } from '@aztec/circuits.js/abis'; +import { computeBlockHashWithGlobals } from '@aztec/circuits.js/abis'; import { SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { IWasmModule } from '@aztec/foundation/wasm'; @@ -151,7 +151,7 @@ export class MerkleTrees implements MerkleTreeDb { * @param includeUncommitted - Indicates whether to include uncommitted data. */ public async updateHistoricBlocksTree(globals: GlobalVariables, includeUncommitted: boolean) { - const blockHash = await this.getCurrentBlockHash(globals, includeUncommitted) + const blockHash = await this.getCurrentBlockHash(globals, includeUncommitted); await this.appendLeaves(MerkleTreeId.BLOCKS_TREE, [blockHash.toBuffer()]); } From 85b6b01f874c74887b52ce9e7d9409263e2cbbaa Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:30:36 +0000 Subject: [PATCH 41/58] minor fix --- .../acir-simulator/src/client/private_execution.ts | 3 +-- .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 8 +++----- yarn-project/sequencer-client/src/sequencer/sequencer.ts | 5 +---- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index e7f8a81f1be..c745e7e7e11 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -218,6 +218,7 @@ export class PrivateFunctionExecution { */ private writeInputs() { const contractDeploymentData = this.context.txContext.contractDeploymentData ?? ContractDeploymentData.empty(); + const blockData = this.context.constantBlockHashData; const { privateHistoricTreeRoots } = blockData; @@ -234,8 +235,6 @@ export class PrivateFunctionExecution { privateHistoricTreeRoots.contractTreeRoot, privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, privateHistoricTreeRoots.blocksTreeRoot, - - // TODO: may need these blockData.prevGlobalVariablesHash, blockData.publicDataTreeRoot, diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index bccf181331e..2607b5ca595 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -371,16 +371,17 @@ export class AztecRPCServer implements AztecRPC { * Returns the simulation result containing the outputs of the unconstrained function. * * @param execRequest - The transaction request object containing the target contract and function data. - * @param constantBlockHashData - Data required to rebuild the block hash, it also contains current db roots. * @param from - The origin of the request. * @returns The simulation result containing the outputs of the unconstrained function. */ async #simulateUnconstrained( execRequest: FunctionCall, - constantBlockHashData: ConstantBlockHashData = ConstantBlockHashData.empty(), from?: AztecAddress, ) { const contractDataOracle = new ContractDataOracle(this.db, this.node); + const kernelOracle = new KernelOracle(contractDataOracle, this.node); + const constantBlockHashData = await kernelOracle.getConstantBlockHashData(); + const { contractAddress, functionAbi, portalContract } = await this.#getSimulationParameters( execRequest, contractDataOracle, @@ -430,9 +431,6 @@ export class AztecRPCServer implements AztecRPC { const { proof, publicInputs } = await kernelProver.prove(txExecutionRequest.toTxRequest(), executionResult); this.log('Proof completed!'); - // TODO: FIX HACK< OVERWRITING THE ROOTS HERE - publicInputs.constants.blockHashValues = constantBlockHashData; - const newContractPublicFunctions = newContract ? getNewContractPublicFunctions(newContract) : []; const encryptedLogs = new TxL2Logs(collectEncryptedLogs(executionResult)); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index fba06da579b..d0ec332147e 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -166,10 +166,7 @@ export class Sequencer { this.log(`Assembling block with txs ${processedTxs.map(tx => tx.hash).join(', ')}`); // Get the prev globals from the block source - - // TODO CLEANUP - const prevBlock = await this.l2BlockSource.getL2Block(-1); - const prevGlobals = prevBlock ? prevBlock.globalVariables : GlobalVariables.empty(); + const prevGlobals = (await this.l2BlockSource.getL2Block(-1))?.globalVariables ?? GlobalVariables.empty(); const emptyTx = await processor.makeEmptyProcessedTx(prevGlobals, globalVariables); const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, globalVariables); From 751d6dfc54191556fcecbb371b93eb0212cc7a0c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:35:26 +0000 Subject: [PATCH 42/58] we snapshot, we are a good boy mama --- ...private_circuit_public_inputs.test.ts.snap | 6 +- .../kernel/__snapshots__/index.test.ts.snap | 60 ++++++++++++------- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index cbeabdc608a..5b3ffdcbac5 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -26,6 +26,8 @@ historic_nullifier_tree_root: 0xf00 historic_contract_tree_root: 0xd00 historic_l1_to_l2_messages_tree_root: 0x1000 historic_blocks_tree_root: 0x1100 +historic_global_variables_hash: 0x1200 +historic_public_data_tree_root: 0x1300 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -34,7 +36,7 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x1200 -version: 0x1300 +chain_id: 0x1400 +version: 0x1500 " `; diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index 3704e3d0cd9..55952adc700 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -514,6 +514,8 @@ historic_nullifier_tree_root: 0x1f11 historic_contract_tree_root: 0x1d11 historic_l1_to_l2_messages_tree_root: 0x2011 historic_blocks_tree_root: 0x2111 +historic_global_variables_hash: 0x2211 +historic_public_data_tree_root: 0x2311 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -522,8 +524,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2211 -version: 0x2311 +chain_id: 0x2411 +version: 0x2511 is_execution_request: 0 @@ -559,6 +561,8 @@ historic_nullifier_tree_root: 0x1f21 historic_contract_tree_root: 0x1d21 historic_l1_to_l2_messages_tree_root: 0x2021 historic_blocks_tree_root: 0x2121 +historic_global_variables_hash: 0x2221 +historic_public_data_tree_root: 0x2321 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -567,8 +571,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2221 -version: 0x2321 +chain_id: 0x2421 +version: 0x2521 is_execution_request: 0 contract_address: 0x1012 @@ -602,6 +606,8 @@ historic_nullifier_tree_root: 0x1f22 historic_contract_tree_root: 0x1d22 historic_l1_to_l2_messages_tree_root: 0x2022 historic_blocks_tree_root: 0x2122 +historic_global_variables_hash: 0x2222 +historic_public_data_tree_root: 0x2322 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -610,8 +616,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2222 -version: 0x2322 +chain_id: 0x2422 +version: 0x2522 is_execution_request: 0 contract_address: 0x1013 @@ -645,6 +651,8 @@ historic_nullifier_tree_root: 0x1f23 historic_contract_tree_root: 0x1d23 historic_l1_to_l2_messages_tree_root: 0x2023 historic_blocks_tree_root: 0x2123 +historic_global_variables_hash: 0x2223 +historic_public_data_tree_root: 0x2323 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -653,8 +661,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2223 -version: 0x2323 +chain_id: 0x2423 +version: 0x2523 is_execution_request: 0 contract_address: 0x1014 @@ -688,6 +696,8 @@ historic_nullifier_tree_root: 0x1f24 historic_contract_tree_root: 0x1d24 historic_l1_to_l2_messages_tree_root: 0x2024 historic_blocks_tree_root: 0x2124 +historic_global_variables_hash: 0x2224 +historic_public_data_tree_root: 0x2324 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -696,8 +706,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2224 -version: 0x2324 +chain_id: 0x2424 +version: 0x2524 is_execution_request: 0 ] @@ -1026,6 +1036,8 @@ historic_nullifier_tree_root: 0x1f11 historic_contract_tree_root: 0x1d11 historic_l1_to_l2_messages_tree_root: 0x2011 historic_blocks_tree_root: 0x2111 +historic_global_variables_hash: 0x2211 +historic_public_data_tree_root: 0x2311 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -1034,8 +1046,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2211 -version: 0x2311 +chain_id: 0x2411 +version: 0x2511 is_execution_request: 0 @@ -1071,6 +1083,8 @@ historic_nullifier_tree_root: 0x1f21 historic_contract_tree_root: 0x1d21 historic_l1_to_l2_messages_tree_root: 0x2021 historic_blocks_tree_root: 0x2121 +historic_global_variables_hash: 0x2221 +historic_public_data_tree_root: 0x2321 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -1079,8 +1093,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2221 -version: 0x2321 +chain_id: 0x2421 +version: 0x2521 is_execution_request: 0 contract_address: 0x1012 @@ -1114,6 +1128,8 @@ historic_nullifier_tree_root: 0x1f22 historic_contract_tree_root: 0x1d22 historic_l1_to_l2_messages_tree_root: 0x2022 historic_blocks_tree_root: 0x2122 +historic_global_variables_hash: 0x2222 +historic_public_data_tree_root: 0x2322 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -1122,8 +1138,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2222 -version: 0x2322 +chain_id: 0x2422 +version: 0x2522 is_execution_request: 0 contract_address: 0x1013 @@ -1157,6 +1173,8 @@ historic_nullifier_tree_root: 0x1f23 historic_contract_tree_root: 0x1d23 historic_l1_to_l2_messages_tree_root: 0x2023 historic_blocks_tree_root: 0x2123 +historic_global_variables_hash: 0x2223 +historic_public_data_tree_root: 0x2323 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -1165,8 +1183,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2223 -version: 0x2323 +chain_id: 0x2423 +version: 0x2523 is_execution_request: 0 contract_address: 0x1014 @@ -1200,6 +1218,8 @@ historic_nullifier_tree_root: 0x1f24 historic_contract_tree_root: 0x1d24 historic_l1_to_l2_messages_tree_root: 0x2024 historic_blocks_tree_root: 0x2124 +historic_global_variables_hash: 0x2224 +historic_public_data_tree_root: 0x2324 contract_deployment_data: deployer_public_key: x: 0x1 y: 0x2 @@ -1208,8 +1228,8 @@ function_tree_root: 0x3 contract_address_salt: 0x4 portal_contract_address: 0x505050505050505050505050505050505050505 -chain_id: 0x2224 -version: 0x2324 +chain_id: 0x2424 +version: 0x2524 is_execution_request: 0 ] From ce5a6bed7cd4e2aa32cb8e76adbcd9117b0e5e84 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 18:43:56 +0000 Subject: [PATCH 43/58] lint so good, hmmm, lint so gooood --- .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 2607b5ca595..236118dea0a 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -374,14 +374,11 @@ export class AztecRPCServer implements AztecRPC { * @param from - The origin of the request. * @returns The simulation result containing the outputs of the unconstrained function. */ - async #simulateUnconstrained( - execRequest: FunctionCall, - from?: AztecAddress, - ) { + async #simulateUnconstrained(execRequest: FunctionCall, from?: AztecAddress) { const contractDataOracle = new ContractDataOracle(this.db, this.node); const kernelOracle = new KernelOracle(contractDataOracle, this.node); const constantBlockHashData = await kernelOracle.getConstantBlockHashData(); - + const { contractAddress, functionAbi, portalContract } = await this.#getSimulationParameters( execRequest, contractDataOracle, From b3fcccc919f5c3b42c1f5894e116284b40226eef Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 19:28:42 +0000 Subject: [PATCH 44/58] refactor: processor && fix public tests --- .../acir-simulator/src/public/executor.ts | 33 +++++++++--------- .../acir-simulator/src/public/index.test.ts | 8 +++-- .../ecdsa_account_contract/src/main.nr | 2 -- .../src/sequencer/public_processor.ts | 34 +++++++++---------- .../src/sequencer/sequencer.ts | 14 ++++---- .../src/simulator/public_executor.ts | 4 ++- 6 files changed, 48 insertions(+), 47 deletions(-) diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index 8dd83896606..d323d8964c2 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -1,11 +1,11 @@ import { AztecAddress, CallContext, + ConstantBlockHashData, EthAddress, Fr, FunctionData, GlobalVariables, - PrivateHistoricTreeRoots, } from '@aztec/circuits.js'; import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -37,17 +37,14 @@ const NOIR_MAX_RETURN_VALUES = 4; * Handles execution of public functions. */ export class PublicExecutor { - private treeRoots: PrivateHistoricTreeRoots; constructor( private readonly stateDb: PublicStateDB, private readonly contractsDb: PublicContractsDB, private readonly commitmentsDb: CommitmentsDB, + private readonly blockHashData: ConstantBlockHashData, private log = createDebugLogger('aztec:simulator:public-executor'), - ) { - // Store the tree roots on instantiation. - this.treeRoots = this.commitmentsDb.getTreeRoots(); - } + ) {} /** * Executes a public execution request. @@ -63,7 +60,7 @@ export class PublicExecutor { const acir = await this.contractsDb.getBytecode(execution.contractAddress, selector); if (!acir) throw new Error(`Bytecode not found for ${execution.contractAddress.toString()}:${selectorHex}`); - const initialWitness = getInitialWitness(execution.args, execution.callContext, this.treeRoots, globalVariables); + const initialWitness = getInitialWitness(execution.args, execution.callContext, this.blockHashData, globalVariables); const storageActions = new ContractStorageActionsCollector(this.stateDb, execution.contractAddress); const newCommitments: Fr[] = []; const newL2ToL1Messages: Fr[] = []; @@ -85,14 +82,14 @@ export class PublicExecutor { }, getL1ToL2Message: async ([msgKey]) => { const messageInputs = await this.commitmentsDb.getL1ToL2Message(fromACVMField(msgKey)); - return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.treeRoots.l1ToL2MessagesTreeRoot); + return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.blockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot); }, // l1 to l2 messages in public contexts TODO: https://github.com/AztecProtocol/aztec-packages/issues/616 getCommitment: async ([commitment]) => { const commitmentInputs = await this.commitmentsDb.getCommitmentOracle( execution.contractAddress, fromACVMField(commitment), ); - return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.treeRoots.privateDataTreeRoot); + return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.blockHashData.privateHistoricTreeRoots.privateDataTreeRoot); }, storageRead: async ([slot], [numberOfElements]) => { const startStorageSlot = fromACVMField(slot); @@ -217,7 +214,7 @@ export class PublicExecutor { * Generates the initial witness for a public function. * @param args - The arguments to the function. * @param callContext - The call context of the function. - * @param historicTreeRoots - The historic tree roots. + * @param constantBlockHashData - Historic Trees roots and data required to reconstruct block hash. * @param globalVariables - The global variables. * @param witnessStartIndex - The index where to start inserting the parameters. * @returns The initial witness. @@ -225,10 +222,12 @@ export class PublicExecutor { function getInitialWitness( args: Fr[], callContext: CallContext, - historicTreeRoots: PrivateHistoricTreeRoots, + constantBlockHashData: ConstantBlockHashData, globalVariables: GlobalVariables, witnessStartIndex = 1, ) { + const { privateHistoricTreeRoots } = constantBlockHashData; + return toACVMWitness(witnessStartIndex, [ callContext.msgSender, callContext.storageContractAddress, @@ -237,11 +236,13 @@ function getInitialWitness( callContext.isStaticCall, callContext.isContractDeployment, - historicTreeRoots.privateDataTreeRoot, - historicTreeRoots.nullifierTreeRoot, - historicTreeRoots.contractTreeRoot, - historicTreeRoots.l1ToL2MessagesTreeRoot, - historicTreeRoots.blocksTreeRoot, + privateHistoricTreeRoots.privateDataTreeRoot, + privateHistoricTreeRoots.nullifierTreeRoot, + privateHistoricTreeRoots.contractTreeRoot, + privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + privateHistoricTreeRoots.blocksTreeRoot, + constantBlockHashData.prevGlobalVariablesHash, + constantBlockHashData.publicDataTreeRoot, globalVariables.chainId, globalVariables.version, diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index a243a3185e7..4ac8ad23e4b 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -1,10 +1,10 @@ import { CallContext, CircuitsWasm, + ConstantBlockHashData, FunctionData, GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT, - PrivateHistoricTreeRoots, } from '@aztec/circuits.js'; import { pedersenPlookupCommitInputs } from '@aztec/circuits.js/barretenberg'; import { FunctionAbi, encodeArguments, generateFunctionSelector } from '@aztec/foundation/abi'; @@ -37,6 +37,8 @@ describe('ACIR public execution simulator', () => { let publicContracts: MockProxy; let commitmentsDb: MockProxy; let executor: PublicExecutor; + let blockHashData: ConstantBlockHashData; + beforeAll(async () => { circuitsWasm = await CircuitsWasm.get(); @@ -47,8 +49,8 @@ describe('ACIR public execution simulator', () => { publicContracts = mock(); commitmentsDb = mock(); - commitmentsDb.getTreeRoots.mockReturnValue(PrivateHistoricTreeRoots.empty()); - executor = new PublicExecutor(publicState, publicContracts, commitmentsDb); + blockHashData = ConstantBlockHashData.empty(); + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, blockHashData); }, 10000); describe('PublicToken contract', () => { diff --git a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr index 295e769e616..baf3d2bea7a 100644 --- a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr @@ -13,8 +13,6 @@ contract EcdsaAccount { use dep::aztec::context::Context; use dep::aztec::log::emit_encrypted_log; use dep::aztec::oracle::get_public_key::get_public_key; - use dep::aztec::private_call_stack_item::PrivateCallStackItem; - use dep::aztec::public_call_stack_item::PublicCallStackItem; use dep::aztec::types::vec::BoundedVec; use dep::aztec::types::point::Point; diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index edefcc5d60c..277574036a1 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -2,6 +2,7 @@ import { PublicExecution, PublicExecutionResult, PublicExecutor, isPublicExecuti import { AztecAddress, CircuitsWasm, + ConstantBlockHashData, ContractStorageRead, ContractStorageUpdateRequest, Fr, @@ -52,15 +53,20 @@ export class PublicProcessorFactory { /** * Creates a new instance of a PublicProcessor. + * @param prevGlobalVariables - The global variables for the previous block, used to calculate the prev global variables hash. + * @param globalVariables - The global variables for the block being processed. * @returns A new instance of a PublicProcessor. */ - public create() { + public async create(prevGlobalVariables: GlobalVariables, globalVariables: GlobalVariables): Promise { + const blockHashData = await getConstantBlockHashData(this.merkleTree, prevGlobalVariables); return new PublicProcessor( this.merkleTree, - getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource), + getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource, blockHashData), new WasmPublicKernelCircuitSimulator(), new EmptyPublicProver(), this.contractDataSource, + globalVariables, + blockHashData ); } } @@ -76,6 +82,8 @@ export class PublicProcessor { protected publicKernel: PublicKernelCircuitSimulator, protected publicProver: PublicProver, protected contractDataSource: ContractDataSource, + protected globalVariables: GlobalVariables, + protected blockHashData: ConstantBlockHashData, private log = createDebugLogger('aztec:sequencer:public-processor'), ) {} @@ -83,17 +91,16 @@ export class PublicProcessor { /** * Run each tx through the public circuit and the public kernel circuit if needed. * @param txs - Txs to process. - * @param globalVariables - The global variables for the block. * @returns The list of processed txs with their circuit simulation outputs. */ - public async process(txs: Tx[], globalVariables: GlobalVariables): Promise<[ProcessedTx[], Tx[]]> { + public async process(txs: Tx[]): Promise<[ProcessedTx[], Tx[]]> { const result: ProcessedTx[] = []; const failed: Tx[] = []; for (const tx of txs) { this.log(`Processing tx ${await tx.getTxHash()}`); try { - result.push(await this.processTx(tx, globalVariables)); + result.push(await this.processTx(tx)); } catch (err) { this.log(`Error processing tx ${await tx.getTxHash()}: ${err}`); failed.push(tx); @@ -104,23 +111,17 @@ export class PublicProcessor { /** * Makes an empty processed tx. Useful for padding a block to a power of two number of txs. - * @param prevGlobals - The global variables for the previous block. - * @param currentGlobalVariables - The global variables for this block. * @returns A processed tx with empty data. */ - public async makeEmptyProcessedTx( - prevGlobals: GlobalVariables, - currentGlobalVariables: GlobalVariables, - ): Promise { - const historicTreeRoots = await getConstantBlockHashData(this.db, prevGlobals); - return makeEmptyProcessedTx(historicTreeRoots, currentGlobalVariables.chainId, currentGlobalVariables.version); + public makeEmptyProcessedTx(): Promise { + const { chainId, version } = this.globalVariables; + return makeEmptyProcessedTx(this.blockHashData, chainId, version); } - protected async processTx(tx: Tx, globalVariables: GlobalVariables): Promise { + protected async processTx(tx: Tx): Promise { if (!isArrayEmpty(tx.data.end.publicCallStack, item => item.isZero())) { const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs] = await this.processEnqueuedPublicCalls( tx, - globalVariables, ); tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs); @@ -132,7 +133,6 @@ export class PublicProcessor { protected async processEnqueuedPublicCalls( tx: Tx, - globalVariables: GlobalVariables, ): Promise<[PublicKernelPublicInputs, Proof, FunctionL2Logs[]]> { this.log(`Executing enqueued public calls for tx ${await tx.getTxHash()}`); if (!tx.enqueuedPublicFunctionCalls) throw new Error(`Missing preimages for enqueued public calls`); @@ -147,7 +147,7 @@ export class PublicProcessor { while (executionStack.length) { const current = executionStack.pop()!; const isExecutionRequest = !isPublicExecutionResult(current); - const result = isExecutionRequest ? await this.publicExecutor.execute(current, globalVariables) : current; + const result = isExecutionRequest ? await this.publicExecutor.execute(current, this.globalVariables) : current; newUnencryptedFunctionLogs.push(result.unencryptedLogs); const functionSelector = result.execution.functionData.functionSelectorBuffer.toString('hex'); this.log(`Running public kernel circuit for ${functionSelector}@${result.execution.contractAddress.toString()}`); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index d0ec332147e..09c6c39f282 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -141,12 +141,13 @@ export class Sequencer { this.state = SequencerState.CREATING_BLOCK; const blockNumber = (await this.l2BlockSource.getBlockHeight()) + 1; - const globalVariables = await this.globalsBuilder.buildGlobalVariables(new Fr(blockNumber)); + const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables(new Fr(blockNumber)); + const prevGlobalVariables = (await this.l2BlockSource.getL2Block(-1))?.globalVariables ?? GlobalVariables.empty(); // Process txs and drop the ones that fail processing // We create a fresh processor each time to reset any cached state (eg storage writes) - const processor = this.publicProcessorFactory.create(); - const [processedTxs, failedTxs] = await processor.process(validTxs, globalVariables); + const processor = await this.publicProcessorFactory.create(prevGlobalVariables, newGlobalVariables); + const [processedTxs, failedTxs] = await processor.process(validTxs); if (failedTxs.length > 0) { this.log(`Dropping failed txs ${(await Tx.getHashes(failedTxs)).join(', ')}`); await this.p2pClient.deleteTxs(await Tx.getHashes(failedTxs)); @@ -165,11 +166,8 @@ export class Sequencer { // Build the new block by running the rollup circuits this.log(`Assembling block with txs ${processedTxs.map(tx => tx.hash).join(', ')}`); - // Get the prev globals from the block source - const prevGlobals = (await this.l2BlockSource.getL2Block(-1))?.globalVariables ?? GlobalVariables.empty(); - const emptyTx = await processor.makeEmptyProcessedTx(prevGlobals, globalVariables); - - const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, globalVariables); + const emptyTx = await processor.makeEmptyProcessedTx(); + const block = await this.buildBlock(processedTxs, l1ToL2Messages, emptyTx, newGlobalVariables); this.log(`Assembled block ${block.number}`); await this.publishContractPublicData(validTxs, block); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 162a639d7b9..b3c1095b551 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -6,7 +6,7 @@ import { PublicExecutor, PublicStateDB, } from '@aztec/acir-simulator'; -import { AztecAddress, CircuitsWasm, EthAddress, Fr, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { AztecAddress, CircuitsWasm, ConstantBlockHashData, EthAddress, Fr, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { ContractDataSource, L1ToL2MessageSource, MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations, computePublicDataTreeLeafIndex } from '@aztec/world-state'; @@ -21,11 +21,13 @@ export function getPublicExecutor( merkleTree: MerkleTreeOperations, contractDataSource: ContractDataSource, l1toL2MessageSource: L1ToL2MessageSource, + blockHashData: ConstantBlockHashData ) { return new PublicExecutor( new WorldStatePublicDB(merkleTree), new ContractsDataSourcePublicDB(contractDataSource), new WorldStateDB(merkleTree, l1toL2MessageSource), + blockHashData ); } From f0656292732c6289ed203544a5f6970ee3bf7c7c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 4 Aug 2023 19:51:30 +0000 Subject: [PATCH 45/58] fix: serialise --- .../acir-simulator/src/acvm/serialize.ts | 2 ++ .../acir-simulator/src/public/executor.ts | 17 ++++++++++++++--- .../acir-simulator/src/public/index.test.ts | 1 - .../src/sequencer/public_processor.ts | 11 ++++++----- .../src/simulator/public_executor.ts | 13 ++++++++++--- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/yarn-project/acir-simulator/src/acvm/serialize.ts b/yarn-project/acir-simulator/src/acvm/serialize.ts index 7e4f18cbd9f..04b66efa167 100644 --- a/yarn-project/acir-simulator/src/acvm/serialize.ts +++ b/yarn-project/acir-simulator/src/acvm/serialize.ts @@ -88,6 +88,8 @@ export function toACVMPublicInputs(publicInputs: PrivateCircuitPublicInputs): AC toACVMField(publicInputs.historicContractTreeRoot), toACVMField(publicInputs.historicL1ToL2MessagesTreeRoot), toACVMField(publicInputs.historicBlocksTreeRoot), + toACVMField(publicInputs.historicGlobalVariablesHash), + toACVMField(publicInputs.historicPublicDataTreeRoot), ...toACVMContractDeploymentData(publicInputs.contractDeploymentData), toACVMField(publicInputs.chainId), diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index d323d8964c2..d98ed903702 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -60,7 +60,12 @@ export class PublicExecutor { const acir = await this.contractsDb.getBytecode(execution.contractAddress, selector); if (!acir) throw new Error(`Bytecode not found for ${execution.contractAddress.toString()}:${selectorHex}`); - const initialWitness = getInitialWitness(execution.args, execution.callContext, this.blockHashData, globalVariables); + const initialWitness = getInitialWitness( + execution.args, + execution.callContext, + this.blockHashData, + globalVariables, + ); const storageActions = new ContractStorageActionsCollector(this.stateDb, execution.contractAddress); const newCommitments: Fr[] = []; const newL2ToL1Messages: Fr[] = []; @@ -82,14 +87,20 @@ export class PublicExecutor { }, getL1ToL2Message: async ([msgKey]) => { const messageInputs = await this.commitmentsDb.getL1ToL2Message(fromACVMField(msgKey)); - return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.blockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot); + return toAcvmL1ToL2MessageLoadOracleInputs( + messageInputs, + this.blockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + ); }, // l1 to l2 messages in public contexts TODO: https://github.com/AztecProtocol/aztec-packages/issues/616 getCommitment: async ([commitment]) => { const commitmentInputs = await this.commitmentsDb.getCommitmentOracle( execution.contractAddress, fromACVMField(commitment), ); - return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.blockHashData.privateHistoricTreeRoots.privateDataTreeRoot); + return toAcvmCommitmentLoadOracleInputs( + commitmentInputs, + this.blockHashData.privateHistoricTreeRoots.privateDataTreeRoot, + ); }, storageRead: async ([slot], [numberOfElements]) => { const startStorageSlot = fromACVMField(slot); diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index 4ac8ad23e4b..a3499fc0c6b 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -39,7 +39,6 @@ describe('ACIR public execution simulator', () => { let executor: PublicExecutor; let blockHashData: ConstantBlockHashData; - beforeAll(async () => { circuitsWasm = await CircuitsWasm.get(); }); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 277574036a1..0d1266fd7a7 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -57,7 +57,10 @@ export class PublicProcessorFactory { * @param globalVariables - The global variables for the block being processed. * @returns A new instance of a PublicProcessor. */ - public async create(prevGlobalVariables: GlobalVariables, globalVariables: GlobalVariables): Promise { + public async create( + prevGlobalVariables: GlobalVariables, + globalVariables: GlobalVariables, + ): Promise { const blockHashData = await getConstantBlockHashData(this.merkleTree, prevGlobalVariables); return new PublicProcessor( this.merkleTree, @@ -66,7 +69,7 @@ export class PublicProcessorFactory { new EmptyPublicProver(), this.contractDataSource, globalVariables, - blockHashData + blockHashData, ); } } @@ -131,9 +134,7 @@ export class PublicProcessor { } } - protected async processEnqueuedPublicCalls( - tx: Tx, - ): Promise<[PublicKernelPublicInputs, Proof, FunctionL2Logs[]]> { + protected async processEnqueuedPublicCalls(tx: Tx): Promise<[PublicKernelPublicInputs, Proof, FunctionL2Logs[]]> { this.log(`Executing enqueued public calls for tx ${await tx.getTxHash()}`); if (!tx.enqueuedPublicFunctionCalls) throw new Error(`Missing preimages for enqueued public calls`); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index b3c1095b551..c1ae5f284dc 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -6,7 +6,14 @@ import { PublicExecutor, PublicStateDB, } from '@aztec/acir-simulator'; -import { AztecAddress, CircuitsWasm, ConstantBlockHashData, EthAddress, Fr, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { + AztecAddress, + CircuitsWasm, + ConstantBlockHashData, + EthAddress, + Fr, + PrivateHistoricTreeRoots, +} from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { ContractDataSource, L1ToL2MessageSource, MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations, computePublicDataTreeLeafIndex } from '@aztec/world-state'; @@ -21,13 +28,13 @@ export function getPublicExecutor( merkleTree: MerkleTreeOperations, contractDataSource: ContractDataSource, l1toL2MessageSource: L1ToL2MessageSource, - blockHashData: ConstantBlockHashData + blockHashData: ConstantBlockHashData, ) { return new PublicExecutor( new WorldStatePublicDB(merkleTree), new ContractsDataSourcePublicDB(contractDataSource), new WorldStateDB(merkleTree, l1toL2MessageSource), - blockHashData + blockHashData, ); } From 8034c9501332284dd4932e73f63cd7e4cf7b8b28 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 13:53:55 +0000 Subject: [PATCH 46/58] fix: missed test updates --- .../src/sequencer/public_processor.test.ts | 29 +++++++++++++++---- .../src/sequencer/sequencer.test.ts | 2 +- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index c39555995bf..ae974b72b6e 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -4,6 +4,7 @@ import { AztecAddress, CallContext, CircuitsWasm, + ConstantBlockHashData, EthAddress, Fr, FunctionData, @@ -82,14 +83,22 @@ describe('public_processor', () => { beforeEach(() => { publicKernel = mock(); - processor = new PublicProcessor(db, publicExecutor, publicKernel, publicProver, contractDataSource); + processor = new PublicProcessor( + db, + publicExecutor, + publicKernel, + publicProver, + contractDataSource, + GlobalVariables.empty(), + ConstantBlockHashData.empty(), + ); }); it('skips txs without public execution requests', async function () { const tx = mockTx(); tx.data.end.publicCallStack = makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Fr.zero); const hash = await tx.getTxHash(); - const [processed, failed] = await processor.process([tx], GlobalVariables.empty()); + const [processed, failed] = await processor.process([tx]); expect(processed).toEqual([ { isEmpty: false, hash, ...pick(tx, 'data', 'proof', 'encryptedLogs', 'unencryptedLogs') }, @@ -101,7 +110,7 @@ describe('public_processor', () => { publicExecutor.execute.mockRejectedValue(new Error(`Failed`)); const tx = mockTx(); - const [processed, failed] = await processor.process([tx], GlobalVariables.empty()); + const [processed, failed] = await processor.process([tx]); expect(processed).toEqual([]); expect(failed).toEqual([tx]); @@ -120,7 +129,15 @@ describe('public_processor', () => { const path = times(PUBLIC_DATA_TREE_HEIGHT, i => Buffer.alloc(32, i)); db.getSiblingPath.mockResolvedValue(new SiblingPath(PUBLIC_DATA_TREE_HEIGHT, path)); publicKernel = new WasmPublicKernelCircuitSimulator(); - processor = new PublicProcessor(db, publicExecutor, publicKernel, publicProver, contractDataSource); + processor = new PublicProcessor( + db, + publicExecutor, + publicKernel, + publicProver, + contractDataSource, + GlobalVariables.empty(), + ConstantBlockHashData.empty(), + ); }); const expectedTxByHash = async (tx: Tx) => @@ -149,7 +166,7 @@ describe('public_processor', () => { throw new Error(`Unexpected execution request: ${execution}`); }); - const [processed, failed] = await processor.process([tx], GlobalVariables.empty()); + const [processed, failed] = await processor.process([tx]); expect(processed).toHaveLength(1); expect(processed).toEqual([await expectedTxByHash(tx)]); @@ -178,7 +195,7 @@ describe('public_processor', () => { ]; publicExecutor.execute.mockResolvedValue(publicExecutionResult); - const [processed, failed] = await processor.process([tx], GlobalVariables.empty()); + const [processed, failed] = await processor.process([tx]); expect(processed).toHaveLength(1); expect(processed).toEqual([await expectedTxByHash(tx)]); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index c1905ed3f65..5ad1b528c57 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -61,7 +61,7 @@ describe('sequencer', () => { }); publicProcessorFactory = mock({ - create: () => publicProcessor, + create: (_, __) => Promise.resolve(publicProcessor), }); l2BlockSource = mock({ From f8ce11e695c68ba7eed17a094b766a2e06dd886f Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:41:01 +0000 Subject: [PATCH 47/58] fix: reinstate circuits test --- .../aztec3/circuits/abis/global_variables.hpp | 13 +- .../src/aztec3/circuits/rollup/root/.test.cpp | 274 ++++++++++-------- .../circuits/rollup/test_utils/utils.cpp | 51 +++- .../circuits/rollup/test_utils/utils.hpp | 1 + 4 files changed, 210 insertions(+), 129 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp index 10a3df5ac6d..4e8e347b021 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/global_variables.hpp @@ -32,6 +32,17 @@ template struct GlobalVariables { timestamp == other.timestamp; }; + /** + * @brief Returns an object containing all global variables set to zero. + * + * @return GlobalVariables + */ + static GlobalVariables empty() + { + GlobalVariables globals = { 0, 0, 0, 0 }; + return globals; + } + template GlobalVariables> to_circuit_type(Builder& builder) const { static_assert((std::is_same::value)); @@ -71,7 +82,7 @@ template struct GlobalVariables { block_number.set_public(); timestamp.set_public(); } -}; +}; // namespace aztec3::circuits::abis template void read(uint8_t const*& it, GlobalVariables& globals) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp index 2c2bd576927..996b314c942 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp @@ -4,13 +4,16 @@ #include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/rollup/merge/previous_rollup_data.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" #include "aztec3/circuits/rollup/base/init.hpp" #include "aztec3/circuits/rollup/components/components.hpp" +#include "aztec3/circuits/rollup/test_utils/init.hpp" #include "aztec3/circuits/rollup/test_utils/utils.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/dummy_circuit_builder.hpp" @@ -34,8 +37,8 @@ using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::rollup::test_utils::utils::compare_field_hash_to_expected; using aztec3::circuits::rollup::test_utils::utils::get_empty_kernel; using aztec3::circuits::rollup::test_utils::utils::get_empty_l1_to_l2_messages; +using aztec3::circuits::rollup::test_utils::utils::get_initial_nullifier_tree_empty; using aztec3::circuits::rollup::test_utils::utils::get_root_rollup_inputs; -// using aztec3::circuits::mock::mock_kernel_inputs; using aztec3::circuits::abis::AppendOnlyTreeSnapshot; @@ -51,6 +54,7 @@ using aztec3::circuits::abis::NewContractData; using MemoryStore = stdlib::merkle_tree::MemoryStore; using MerkleTree = stdlib::merkle_tree::MerkleTree; + using KernelData = aztec3::circuits::abis::PreviousKernelData; } // namespace @@ -160,123 +164,155 @@ TEST_F(root_rollup_tests, native_check_block_hashes_empty_blocks) run_cbind(inputs, outputs, true); } -// TODO turn back on -// TEST_F(root_rollup_tests, native_root_missing_nullifier_logic) -// { -// utils::DummyCircuitBuilder builder = -// utils::DummyCircuitBuilder("root_rollup_tests__native_root_missing_nullifier_logic"); - -// MemoryStore private_data_tree_store; -// MerkleTree private_data_tree = MerkleTree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); - -// MemoryStore contract_tree_store; -// MerkleTree contract_tree = MerkleTree(contract_tree_store, CONTRACT_TREE_HEIGHT); - -// MemoryStore l1_to_l2_messages_tree_store; -// MerkleTree l1_to_l2_messages_tree = MerkleTree(l1_to_l2_messages_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); - -// std::array kernels = { -// get_empty_kernel(), get_empty_kernel(), get_empty_kernel(), get_empty_kernel() -// }; -// std::array l1_to_l2_messages = get_empty_l1_to_l2_messages(); - -// // Create commitments -// for (uint8_t kernel_j = 0; kernel_j < 4; kernel_j++) { -// std::array new_commitments; -// for (uint8_t commitment_k = 0; commitment_k < MAX_NEW_COMMITMENTS_PER_TX; commitment_k++) { -// auto val = fr(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k + 1); -// new_commitments[commitment_k] = val; -// private_data_tree.update_element(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k, val); -// } -// kernels[kernel_j].public_inputs.end.new_commitments = new_commitments; - -// std::array new_l2_to_l1_messages; -// for (uint8_t i = 0; i < MAX_NEW_L2_TO_L1_MSGS_PER_TX; i++) { -// auto val = fr(kernel_j * MAX_NEW_L2_TO_L1_MSGS_PER_TX + i + 1); -// new_l2_to_l1_messages[i] = val; -// } -// kernels[kernel_j].public_inputs.end.new_l2_to_l1_msgs = new_l2_to_l1_messages; -// } - -// // @todo @LHerskind: Add nullifiers -// // @todo @LHerskind: Add public data writes - -// // Contract tree -// NewContractData const new_contract = { -// .contract_address = fr(1), -// .portal_contract_address = fr(3), -// .function_tree_root = fr(2), -// }; -// // Update contract tree -// contract_tree.update_element(2, new_contract.hash()); -// kernels[2].public_inputs.end.new_contracts[0] = new_contract; - -// // l1 to l2 messages snapshot -// AppendOnlyTreeSnapshot const start_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), -// .next_available_leaf_index = 0 }; - -// // Create 16 empty l1 to l2 messages, and update the l1_to_l2 messages tree -// for (size_t i = 0; i < l1_to_l2_messages.size(); i++) { -// l1_to_l2_messages_tree.update_element(i, l1_to_l2_messages[i]); -// } - - -// // Compute the end snapshot -// AppendOnlyTreeSnapshot const end_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), -// .next_available_leaf_index = -// NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP -// }; - -// RootRollupInputs rootRollupInputs = get_root_rollup_inputs(builder, kernels, l1_to_l2_messages); -// RootRollupPublicInputs outputs = -// aztec3::circuits::rollup::native_root_rollup::root_rollup_circuit(builder, rootRollupInputs); - -// // Check private data trees -// ASSERT_EQ( -// outputs.start_private_data_tree_snapshot, -// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_private_data_tree_snapshot); -// ASSERT_EQ( -// outputs.end_private_data_tree_snapshot, -// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_private_data_tree_snapshot); -// AppendOnlyTreeSnapshot const expected_private_data_tree_snapshot = { .root = private_data_tree.root(), -// .next_available_leaf_index = -// 4 * MAX_NEW_COMMITMENTS_PER_TX }; -// ASSERT_EQ(outputs.end_private_data_tree_snapshot, expected_private_data_tree_snapshot); - -// // Check public data trees -// ASSERT_EQ(outputs.start_public_data_tree_root, -// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_public_data_tree_root); -// ASSERT_EQ(outputs.end_public_data_tree_root, -// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_public_data_tree_root); - -// // check contract trees -// ASSERT_EQ(outputs.start_contract_tree_snapshot, -// rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_contract_tree_snapshot); -// ASSERT_EQ(outputs.end_contract_tree_snapshot, -// rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_contract_tree_snapshot); -// AppendOnlyTreeSnapshot const expected_contract_tree_snapshot{ .root = contract_tree.root(), -// .next_available_leaf_index = 4 }; -// ASSERT_EQ(outputs.end_contract_tree_snapshot, expected_contract_tree_snapshot); - -// // @todo @LHerskind: Check nullifier trees - -// // Check l1 to l2 messages trees -// ASSERT_EQ(outputs.start_l1_to_l2_messages_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); -// ASSERT_EQ(outputs.end_l1_to_l2_messages_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); - -// // TODO(MADDIAA) Check historic block hashes tree -// // ASSERT_EQ(outputs.start_historic_blocks_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); -// // ASSERT_EQ(outputs.end_historic_blocks_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); - -// // Compute the expected calldata hash for the root rollup (including the l2 -> l1 messages) -// auto left = components::compute_kernels_calldata_hash({ kernels[0], kernels[1] }); -// auto right = components::compute_kernels_calldata_hash({ kernels[2], kernels[3] }); -// auto root = accumulate_sha256({ left[0], left[1], right[0], right[1] }); -// ASSERT_EQ(outputs.calldata_hash, root); - -// EXPECT_FALSE(builder.failed()); - -// run_cbind(rootRollupInputs, outputs, true); -// } +TEST_F(root_rollup_tests, native_root_missing_nullifier_logic) +{ + utils::DummyCircuitBuilder builder = + utils::DummyCircuitBuilder("root_rollup_tests__native_root_missing_nullifier_logic"); + + MemoryStore private_data_tree_store; + MerkleTree private_data_tree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); + + MemoryStore contract_tree_store; + MerkleTree contract_tree(contract_tree_store, CONTRACT_TREE_HEIGHT); + + MemoryStore l1_to_l2_messages_tree_store; + MerkleTree l1_to_l2_messages_tree(l1_to_l2_messages_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); + + MemoryStore public_store; + MerkleTree public_data_tree(public_store, PUBLIC_DATA_TREE_HEIGHT); + + // Create initial nullifier tree with 32 initial nullifiers + auto nullifier_tree = get_initial_nullifier_tree_empty(); + + MemoryStore blocks_tree_store; + MerkleTree blocks_tree(blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); + + std::array kernels = { + get_empty_kernel(), get_empty_kernel(), get_empty_kernel(), get_empty_kernel() + }; + std::array l1_to_l2_messages = get_empty_l1_to_l2_messages(); + + // Calculate the start block hash + abis::GlobalVariables globals = abis::GlobalVariables::empty(); + auto start_block_hash = compute_block_hash_with_globals(globals, + private_data_tree.root(), + nullifier_tree.root(), + contract_tree.root(), + l1_to_l2_messages_tree.root(), + public_data_tree.root()); + blocks_tree.update_element(0, start_block_hash); + AppendOnlyTreeSnapshot start_blocks_tree_snapshot = { .root = blocks_tree.root(), + .next_available_leaf_index = 1 }; + + // Create commitments + for (size_t kernel_j = 0; kernel_j < 4; kernel_j++) { + std::array new_commitments; + for (uint8_t commitment_k = 0; commitment_k < MAX_NEW_COMMITMENTS_PER_TX; commitment_k++) { + auto val = fr(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k + 1); + new_commitments[commitment_k] = val; + private_data_tree.update_element(kernel_j * MAX_NEW_COMMITMENTS_PER_TX + commitment_k, val); + } + kernels[kernel_j].public_inputs.end.new_commitments = new_commitments; + + std::array new_l2_to_l1_messages; + for (uint8_t i = 0; i < MAX_NEW_L2_TO_L1_MSGS_PER_TX; i++) { + auto val = fr(kernel_j * MAX_NEW_L2_TO_L1_MSGS_PER_TX + i + 1); + new_l2_to_l1_messages[i] = val; + } + kernels[kernel_j].public_inputs.end.new_l2_to_l1_msgs = new_l2_to_l1_messages; + } + + // @todo @LHerskind: Add nullifiers + // @todo @LHerskind: Add public data writes + + // Contract tree + NewContractData const new_contract = { + .contract_address = fr(1), + .portal_contract_address = fr(3), + .function_tree_root = fr(2), + }; + // Update contract tree + contract_tree.update_element(2, new_contract.hash()); + kernels[2].public_inputs.end.new_contracts[0] = new_contract; + + // l1 to l2 messages snapshot + AppendOnlyTreeSnapshot const start_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), + .next_available_leaf_index = 0 }; + + // Create 16 empty l1 to l2 messages, and update the l1_to_l2 messages tree + for (size_t i = 0; i < l1_to_l2_messages.size(); i++) { + l1_to_l2_messages_tree.update_element(i, l1_to_l2_messages[i]); + } + + // Get the block hash after. + auto end_block_hash = compute_block_hash_with_globals(globals, + private_data_tree.root(), + nullifier_tree.root(), + contract_tree.root(), + l1_to_l2_messages_tree.root(), + public_data_tree.root()); + blocks_tree.update_element(1, end_block_hash); + AppendOnlyTreeSnapshot end_blocks_tree_snapshot = { .root = blocks_tree.root(), + .next_available_leaf_index = 2 }; + + // Compute the end snapshot + AppendOnlyTreeSnapshot const end_l1_to_l2_messages_tree_snapshot = { .root = l1_to_l2_messages_tree.root(), + .next_available_leaf_index = + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP }; + + RootRollupInputs rootRollupInputs = get_root_rollup_inputs(builder, kernels, l1_to_l2_messages); + RootRollupPublicInputs outputs = + aztec3::circuits::rollup::native_root_rollup::root_rollup_circuit(builder, rootRollupInputs); + + // Check private data trees + ASSERT_EQ( + outputs.start_private_data_tree_snapshot, + rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_private_data_tree_snapshot); + ASSERT_EQ( + outputs.end_private_data_tree_snapshot, + rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_private_data_tree_snapshot); + AppendOnlyTreeSnapshot const expected_private_data_tree_snapshot = { .root = private_data_tree.root(), + .next_available_leaf_index = + 4 * MAX_NEW_COMMITMENTS_PER_TX }; + ASSERT_EQ(outputs.end_private_data_tree_snapshot, expected_private_data_tree_snapshot); + + // Check public data trees + ASSERT_EQ(outputs.start_public_data_tree_root, + rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_public_data_tree_root); + ASSERT_EQ(outputs.end_public_data_tree_root, + rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_public_data_tree_root); + + // check contract trees + ASSERT_EQ(outputs.start_contract_tree_snapshot, + rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_contract_tree_snapshot); + ASSERT_EQ(outputs.end_contract_tree_snapshot, + rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_contract_tree_snapshot); + AppendOnlyTreeSnapshot const expected_contract_tree_snapshot{ .root = contract_tree.root(), + .next_available_leaf_index = 4 }; + ASSERT_EQ(outputs.end_contract_tree_snapshot, expected_contract_tree_snapshot); + + // @todo @LHerskind: Check nullifier trees + + // Check l1 to l2 messages trees + ASSERT_EQ(outputs.start_l1_to_l2_messages_tree_snapshot, start_l1_to_l2_messages_tree_snapshot); + ASSERT_EQ(outputs.start_contract_tree_snapshot, + rootRollupInputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.start_contract_tree_snapshot); + ASSERT_EQ(outputs.end_contract_tree_snapshot, + rootRollupInputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.end_contract_tree_snapshot); + ASSERT_EQ(outputs.end_l1_to_l2_messages_tree_snapshot, end_l1_to_l2_messages_tree_snapshot); + + ASSERT_EQ(outputs.start_historic_blocks_tree_snapshot, start_blocks_tree_snapshot); + ASSERT_EQ(outputs.end_historic_blocks_tree_snapshot, end_blocks_tree_snapshot); + + // Compute the expected calldata hash for the root rollup (including the l2 -> l1 messages) + auto left = components::compute_kernels_calldata_hash({ kernels[0], kernels[1] }); + auto right = components::compute_kernels_calldata_hash({ kernels[2], kernels[3] }); + auto root = accumulate_sha256({ left[0], left[1], right[0], right[1] }); + ASSERT_EQ(outputs.calldata_hash, root); + + EXPECT_FALSE(builder.failed()); + + run_cbind(rootRollupInputs, outputs, true); +} } // namespace aztec3::circuits::rollup::root::native_root_rollup_circuit \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 2641ad1f749..b53da587b8f 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -6,6 +6,7 @@ #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" #include "aztec3/circuits/rollup/base/init.hpp" #include "aztec3/constants.hpp" @@ -154,6 +155,7 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne baseRollupInputs.start_public_data_tree_root = public_data_tree.root(); // create the original historic blocks tree leaf + info("block hash base inputs"); auto block_hash = compute_block_hash(prev_global_variables_hash, private_data_tree.root(), nullifier_tree.root(), @@ -365,22 +367,48 @@ MergeRollupInputs get_merge_rollup_inputs(utils::DummyBuilder& builder, std::arr return inputs; } + RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, std::array kernel_data, std::array l1_to_l2_messages) { + abis::GlobalVariables globals = { 0, 0, 0, 0 }; + MemoryStore private_data_store; const MerkleTree private_data_tree(private_data_store, PRIVATE_DATA_TREE_HEIGHT); + auto nullifier_tree = get_initial_nullifier_tree_empty(); + MemoryStore contract_tree_store; const MerkleTree contract_tree(contract_tree_store, CONTRACT_TREE_HEIGHT); MemoryStore l1_to_l2_msg_tree_store; MerkleTree l1_to_l2_msg_tree(l1_to_l2_msg_tree_store, L1_TO_L2_MSG_TREE_HEIGHT); + MemoryStore public_data_tree_store; + MerkleTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + MemoryStore historic_blocks_tree_store; MerkleTree historic_blocks_tree(historic_blocks_tree_store, HISTORIC_BLOCKS_TREE_HEIGHT); + // Start blocks tree + auto block_hash = compute_block_hash_with_globals(globals, + private_data_tree.root(), + nullifier_tree.root(), + contract_tree.root(), + l1_to_l2_msg_tree.root(), + public_data_tree.root()); + historic_blocks_tree.update_element(0, block_hash); + + // Blocks tree snapshots + AppendOnlyTreeSnapshot const start_historic_blocks_tree_snapshot = { + .root = historic_blocks_tree.root(), + .next_available_leaf_index = 1, + }; + + // Blocks tree + auto blocks_tree_sibling_path = get_sibling_path(historic_blocks_tree, 1, 0); + // l1 to l2 tree auto l1_to_l2_tree_sibling_path = get_sibling_path(l1_to_l2_msg_tree, 0, L1_TO_L2_MSG_SUBTREE_HEIGHT); @@ -391,15 +419,6 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, .next_available_leaf_index = 0, }; - // Blocks tree - auto blocks_tree_sibling_path = get_sibling_path(historic_blocks_tree, 0, 0); - - // Blocks tree snapshots - AppendOnlyTreeSnapshot const start_historic_blocks_tree_snapshot = { - .root = historic_blocks_tree.root(), - .next_available_leaf_index = 0, - }; - RootRollupInputs rootRollupInputs = { .previous_rollup_data = get_previous_rollup_data(builder, std::move(kernel_data)), .l1_to_l2_messages = l1_to_l2_messages, @@ -415,6 +434,20 @@ RootRollupInputs get_root_rollup_inputs(utils::DummyBuilder& builder, // NULLIFIER TREE BELOW // ////////////////////////// +/** + * @brief Get initial nullifier tree object + * + * @return NullifierMemoryTreeTestingHarness + */ +NullifierMemoryTreeTestingHarness get_initial_nullifier_tree_empty() +{ + NullifierMemoryTreeTestingHarness nullifier_tree = NullifierMemoryTreeTestingHarness(NULLIFIER_TREE_HEIGHT); + for (size_t i = 0; i < (MAX_NEW_NULLIFIERS_PER_TX * 2 - 1); i++) { + nullifier_tree.update_element(i + 1); + } + return nullifier_tree; +} + /** * @brief Get initial nullifier tree object * diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp index bf39e70ac0e..64775772657 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp @@ -94,6 +94,7 @@ std::array get_empty_l1_to_l2_messages( nullifier_tree_testing_values generate_nullifier_tree_testing_values( BaseRollupInputs inputs, std::array new_nullifiers, size_t spacing); +NullifierMemoryTreeTestingHarness get_initial_nullifier_tree_empty(); NullifierMemoryTreeTestingHarness get_initial_nullifier_tree(const std::vector& initial_values); KernelData get_empty_kernel(); From cb3f80ce977255c0e8da2f8c4b49f204f314da69 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:43:01 +0000 Subject: [PATCH 48/58] fix: recompile aztec js account contracts --- yarn-project/aztec.js/src/abis/ecdsa_account_contract.json | 4 ++-- .../aztec.js/src/abis/schnorr_multi_key_account_contract.json | 4 ++-- .../src/abis/schnorr_single_key_account_contract.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json index a1ec84c1883..84ec480d5d5 100644 --- a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json @@ -84,7 +84,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "H4sIAAAAAAAA/+1dZ3QcVxV+kmy5Ow6QuMlWce/vaSVLcpV77zaEdMteOU6xEyMndgiB9N57L/QeeocQeu+dE0IIIYQQQggh8IPDXPmO/XRZSTu73+zOPdl3ztPdq9lz9/u+aW9m7ty3qcwYQ51NedD78OfQ7yv8SuEfG/T+nj9c+COEP1L4o4Q/WvhVwh8j/LHCrxZ+jfBrhV8n/HHCHy/8CcKfKPxJwp8s/CnCnyr8acKfLvwZwp8p/FnCt8J3wq8Xfkr4DcJvZJ+2i2NYX2q0HQzn9T2S1+toXn9jeD1V8/drWfdxrO8E1nES6zWFdZnG/Gcwz1nMxzHuFONr9PDNFnibhN8s/BbhzxH+XOHPE/584S8Q/kLhtwp/kfAXC3+J8JcKf5nwlwt/hfBXCn+V8FcLf43w1wp/nfDXC3+D8DcKf5PwNwt/i/C3Cn+bObI90jZYYw412g6aeH238Hqdy+tvPq+nhbw+FrHuS1jfZazjCtZrFeuyhvmvY54bmM8mxr2F8W1jfJWm6/7xX3NoHyE7gu1ItqPYjmZbxXYM27Fsq9nWsK1lW8d2HNvxbCewnch2EtvJbKewncp2GtvpbGewncl2FlvL1rGtZ5ti28C20Yv3+qC/IYM2s/k7TWyb2bawncN2Ltt5bOezXcB2IdtWtovYLma7hO1StsvYLme7gu1KtqvYrma7hu1atuvYrme7ge1GtpvYbma7he1Wtts8bY4L+htN18an5k4+1FJ2dkNDuqk+7VJuu61vaWtutA2NbbObXbNrbG7cWd+cSqWbG5qbWtpammyLa0ilXXtjS6rdHmrHe7Fsni1OnCcowXmiEpwnKcF5shKcpyjBeaoSnNuV4GxTgnOHEpw7leBMK8HZrgTnLiDOcCw5jOPRGJPGVMexPZ7tCWxPZHsS25PZnsL2VLbb2bax3cF2J9s023a2u8yRsdxpQd9tuja0hqfjNHShhiHG05kL/e+MoJ8puFQILhTD5tGOlVzyiDYcqPHjJp79KYN+Nh/WIzLhzDHaSKB+vyusfjZX1qO6w5lDtNFA/Z4ovH42F9ZVPeGMGG0MUL/fF0c/G5X12N5wRohWDdTvyeLpZ6OwrskGZ5bRaoH6/aG4+tlsWddlizOLaOOA+j1VfP1sNqzHR8HZS7QJQP3+mAz9bG+sJ0bF2UO0SUD9nk6OfrYn1pNzwdlNtClA/f6ULP1sd6yn5oozQ7RpQP2eSZ5+NhPr6fngFNFmAPX7czL1s5L1zHxxetFmAfV7Nrn62S6sETg5mgPq95dk69dJl/7Uo3AG0VJA/Z5Lvn7UXAMw1uNA/f6qRD/gfSL3BFC/55XoB7zP4Z4E6vc3JfoBr9PdU0D9XlCiH/A60z0N1O/vSvQDXie5Z4D6vahEP+A43z0L1O8fSvQDjlPdc0D9XlKiH3Cc5Z4H6vdPJfoBxwnuBaB+LyvRD3iecy8C9fuXEv2Ax2n3ElC/V5ToBzzOuJeB+v1biX7A/cS9AtTvPwXSL1+cZwH1A24zrlD62Tzzr2YbXP5VE3C9jigr6P6bM+tmg8u/agHqN7Ks4Me/nFjPMbj8q7lA/UYVXj+bC+t5Bpd/NR+o3+ji6Gejsl5gcPlXC4H6VRVPPxuFdavJAmeW0RYB9RtTXP1stqwXmyxxZhFtCVC/scXXz2bDeqmJgLOXaMuA+lUnQz/bG+vlJiLOHqKtAOpXkxz9bE+sV5occHYTbRVQv9pk6We7Y73a5IgzQ7Q1QP3qkqefzcR6rckDp4i2DqjfuGTqZyXr9SZPnF60DUD9xidXP+uz3mgAODnaJqB+E5Ktnw1ZbzYgnEG0LUD9JiZfP2puKzCWf88pX/0mKdEPeJ/IjQLqN1mJfsD7HK4KqN8UJfoBr9PdWKB+U5XoB7zOdDVA/aYp0Q94neTqgPpNV6IfcJzvxgP1m6FEP+A41U0E6jdTiX7AcZabDNRvlhL9gOMENxWon1WiH/A856YD9XNK9AMep91MoH71SvQDHmecBeqXUqIfcD9x9UD9GgqkX7449wDXBXCbcUj9whpZfTke5Zz59W33mK41XcvZUtsb9LNN14auB3YOcB2EXMs53jnMZa/HaV/Q38TbUoXpvrUCMfUVsav//zcSWYeM/5W4+l7evxNVN0ssSkw9qgyLE1HnqZuvFL1+Ug9fK2pdol6+WrR6P7b3VpQ6Oja7VvD6NDb7VtC6LzZaK1g9FRu9FaROic2txV7/w+beYq2rYfNryHoVh68r5HjW5tdcYwwY0ePFuN6b4H8l7n0E79+JyvMXixKTP59hcSLy0rv5StHzvXv4WlHzqHv5atHyk23vrSh5vza7VvB8Wpt9K2ieqo3WCpb/aaO3guRV2txa7PmKNvcWax6gza8h8+tiGy9uU4CxPAaMceDcB8RZ5uHs8D4PZjvAHJpzlFq5978KwW2Atzxsld7nVgzexkq8npbuW/f3eBjBdygvP5r9PXs7drcfXLIvvb0jvXP93o60L2J4E7wiQ6Ay7//+zfI+3o9XiuW+sOGyfuaICIdbq4Go4SoyBTf4rbjDxLMV788grL9lVnhiojkZ8TtSx6EmxhUX10raH0Pccw3u0VpcvM/Fr6NYTwtITQt1EECecss8jOFOfl7QDwT9oMdhCNsCnbJsXKesSo9H2PxTFi3vg/3dlH/qN57eJoNuxvt9On2GQ4pd6Y6N+9vO3L1jTfpgpnVWkSGuP/SQZ1h/PYbLYj1Dhs/f/Y2MnrsfYHuQ7VFBPz/obxY40PkdwJ3InQ/EdQEOV8EOSEjMPt63eJ9Lo5I8Y17AgqLjXmiSPSoh3hfi11GsoxKkprTx+mfouDDHdSMAvN6cRg3QOM9TgvOAwZ5YSsl2pWS7bFop2S5atBqTxX5aSrY73ErJdtGilZLtokUrJdtFjJZ/rFKyXY6Nw5SS7TpR25xbKdkuWisl20WLVkq2ixatlGwXLVop2S5atFKyXbRopWS7aNFKyXbJwxjXk/9y/vzWoL/NHGlVbOlpcT/+7OdYhc8V/FysTE+aXw3JcIM8HkbwDZPhhrGfPmt3x7I9O/YdPLsjvXPt3l3+g8T+GbhneuhJrY/3uW8G3SiuXG+0bCCWf/0AwTv8bb+1ep8HelgGYbF07nuDvd8KcQ3ybLjc13owFkdnwsMgwT/0B8f3u538h/TCf0gGHEMKyN/PJpL7jX8cCJfFmpnix0RXsLjI4E8qceC8WAnOS5TgvFQJzsuU4LxcCc4rlOC8UgnOq5TgvFoJzmuU4LxWCc7rlOC8XgnOGzA42xvqG2LFeaMSPW9SgvNmJThvUYLzViU4b1OC83YlOO9QgvNOJTjvUoLzbiU471GC814lOO9TgvN+JTgfUILzQSU4H1KC8+GYcJYLnDa/1nlTHcX57Uo4lwM5v0MJ5wog53cq4dwHyPldSjj3BXJ+txLOlUDO71HC+TQg5/cq4XwRkPP7lHC+GMj5/Uo4XwLk/AElnC8Fcv6gEs6XATl/SAnny4GcP6yE8xVAzo8o4XwlkPNHlHDeB+T8USWcrwJy/pgSzlcDOX9cCedrgJw/oYTzGUDOn1TC+Vog508p4XwdkPOnlXC+Hsj5M0o43wDk/FklnG8Ecv6cEs43ATl/Xgnnm4Gcv6CE8y1Azl9UwvlWIOcvKeF8G5Dzo0o43w7k/GUlnO8Acn5MCec7gZy/ooTzXUDOX1XC+W4g568p4XwPkPPXlXC+F8j5G0o43wfk/E0lnO8Hcv6WEs4PADl/WwnnB4Gcv6OE80NAzt9VwvlhIOfvKeHcD8j5+0o49wdy/oESzgOAnH+ohPNAIOcfKeE8CMj5x0o4DwZy/okSzkOAnH+qhPNQIOefKeF8FJDzz5VwHgbk/AslnI8Gcv6lEs6vAXL+lRLOrwVy/rUSzq8Dcv6NEs7HADn/NgbO29iGhSrp3Sh6VyiczpGuC+k6ia4baBwdFvijcQedh+m8RMdpOm7RfkzbNa1n4k0T9tBEOzRBDk1sQxPS0EQyVPiSJm6hCVeo6HtN0GuDXhd0mgiEJvCgiTdowgya6IImqKCJJWhCCJrIgSZgoIkTaMIDmqiAyFChOSroT4X4qYA+FainAvBUuJ0KrlOhdCpwToXJqaA4FQKnAt5h4e1FQV8cdCosTQWhqZAzFWCmwslU8JgKFVOBYSoMTAV9qRAvFdClwrcbg06FZqlALBV23cq6zmFt6V1AejeO3hWjd6foXSJ6t4beNaF3L+hdBMrNp1x1yt2mXOZHgk65rpT7SbmQlBtIuXKUO0a5VJRbRLk2lHtCuRiUm0DP6unZNT3LfTTo9KzvsaDTsyB6NkLPCujeOd1LpnurdK+R7r3RvSi6N0P3Kujana5l6dqOrnVo7E9jYRob0liJxg50LqVzCx1r6dhD+yJtm/8DGP9R4h7wAAA=", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -152,7 +152,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json index beb60713945..9fa64651b73 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json @@ -72,7 +72,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "H4sIAAAAAAAA/+2c91cVRxzFx/coImBJAQsq9q67r8B72FBEoxKwoTEmKuWBKE18qNhjeje9J8T03usfl5P9wneP4+bl+AN3Od6jc86cu8vq7P3M7s58Z3b2/W2MGTajaYKXI17O021/Pz+wX6DbdvL3a1XjTlUikamOZdy42+LE0q2ppJNItlal3JSbTCXbY6l4PJNKpKrTrelqJ+0m4hm3I5mOdzijabpVljPGFKbPGSQ+Z5L4nEXis4LE52wSn3NIfM4l8VlJ4nMeic/5JD4XkPhcSOJzEYnPxSQ+l5D4XEricxmJz+UkPleQ+FxJ4nMVic/VJD7XkPh0SHy6JD5jJD7jJD4TJD6TQJ/iTebuKrW8Mi//4+Vy1emqM1Rnqs5SrVCdrTpHda5qpeo81fmqC1QXqi5SXay6RHWp6jLV5aorVFeqrlJdrbpG1VF1VWOqcdWEatIqr8rL1ebmhL6GKcNxr6VJfNaQ+FxL4nMdic/1JD43kPjcSOKzlsTnJhKfm0l81pH43ELis57E51aDj3mnankS70nsl1JNq9aorlVdp7pedYPqRtVa1U2qm1XrVLeo1qtuNTdizm1efsDcnNB1uB1Xh65fh77H7coif9vh5Z16TPaj+m+CY4uIqqQGLz8YMn9jCPwRLa9RWRospiYv71L+qPn/VAv0FL1FHTpjS26ZwbcXaI/lBB4jZnzaXWdsyW0y2HbXT7ut7RLVIjO6zkhSxPpbNMBWZB33U4G1XYvxGy/A16cj66YmWhwmwDtZj0/T/d6+bFfHUN1ApiWbaW/sy2bsSsxXjeYoyG4M7ON51skLAuXYFesfKzT/XdgFu7uiuQo3+Lt4twnnLt6To2LtOzNqVSaayQTOE6zHySbECxfWRdoTQrl7DS6ECIt7L/4ahdotIOt0vBoBZJc7wfLoP+T7vNzs5f0WQ6nqOHVZTlhdVoHF4Se7y5Ljedjzxu2u31j1bXLUm7HOL92nH1J0ZrK7Blu7u9p2ZoZyXbNojnLt0CPYw9rX0T8Wag8ZHEPJTSbji2bV/apTvHzAyw8FfEQDfsb6sAIfIvcA0NdBnK9xa5CQnm2/D1vbd6OSMZZ5UCsUXe4hc3tHJcJ9CH+NQo1KkHUqN6/dQ4flOayJAPB1cxnrAO1zH4nPZoPtWO5OKt55k4p2tOwHD494+VFzI1WoSlRcqNv2XJLfftpzTrki6jth0q/Y4jABXn/Sz38hlenpytb3tg0M9XuTfg19nXbANDEHe67gTlKetZ2fo96k3MLA/5Njk7D8saIAt39uO9Va25MsL8VYLyPPXol1Lt9XsaX+cbuuS7A+RgZ2xQF+f78kvPOO8Jfegr80h4/SceS3Z02Cz43dDvjHQh2B22Wi30geNvhOJQyfR0h8HiXx2ULis5XEZxuJz3YSnxkSnx0kPjtJfB4j8dlF4vM4ic8TJD67MT47ErFEqD57SOqzl8RnH4nPfhKfJ0l8DpD4PEXiM0vic5DE52kSn2dIfJ4l8TlE4vMcic/zJD4vkPi8SOLzEonPyyH5jAR8OmNLI5PqKOYrJMwRIPNjJMxRIPNVEuY8IPPjJMz5QOYnSJgLgMxPkjBvAzI/RcJ8GMj8NAnzESDzMyTMR4HMz5IwtwCZnyNhbgUyP0/C3AZkfoGEuR3I/CIJcwbI/BIJcxOQ+WUS5g4g8zUS5k4g8yskzMeAzK+SMO8AMr9GwtwFZH6dhPk4kPkNEuYTQOY3SZi7gcxvkTD3AJnfJmHuBTK/Q8LcB2R+l4S5H8j8HgnzSSDz+yTMA0DmD0iYTwGZPyRhzgKZPyJhHgQyD5MwnwYyf0zCfAbIfJ2E+SyQ+RMS5iEg86ckzOeAzJ+RMJ8HMn9OwnwByPwFCfNFIPOXJMyXgMxfkTBfBjJ/TcJcCGT+hoR5IpD5WxLmIiDzdyTMk4DM35MwFwOZfyBhLgEy/0jCXApk/omEeTKQ+WcS5ilA5l9ImKcCmX8lYZ4GZP6NhPkeIPPvJMz3Apn/IGG+D8j8Jwnz/UDmv0JgLlf1f6hSvo2Sb4X8n62XcaGMk2TcIHG0/wN/EndIPyz9krTT0m7Jcyz3tVxn4S7T8mv0HFe8LN+IXfWyfEMk39TINybyzYV8gyBr8mWNuqzZljXMsqZX1rjKmk9ZA3nNy7JGTtaMyRoqWVMka2xkzYmswZA1CfKOXt5Zyztceacp7/jknZe8Axr2srwjuO5lmUOWOVWZY5Q5N5mDkjkZmaOQMbuMYWVMJ2McifklBpaYUGIkiRmkD5U+RdpYaXPkGZR7Uq7Rv0HsEyECjAAA", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -140,7 +140,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json index 7c5814b2032..a400d9a909b 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json @@ -7,7 +7,7 @@ "isInternal": false, "parameters": [], "returnTypes": [], - "bytecode": "H4sIAAAAAAAA/9XcR2/iUBiFYZJJMr2l996rjW2wp2YyvffeCBOY3v7/JhzFSFG2OSzeK1ngjXUeAfYt3+V/oVCoFPZaW+Nobxwd+fvmeeeB8678/f7WPN/MX6OgFMe1crEWRuF2UMyqaRLESbWUhmmYpMlOMY2iWhqn5ayalYMsjKNaWE+yqB7std591woO2VqZsw+Ssx+ScwCScxCScwiScxiScwSScxSScwyScxyScwKScxKScwqScxqScwaScxaScw6Scx6ScwGScxGScwmScxmScwWScxWScw2Scx2ScwOSM4DkDCE5i5CcESRnDMmZQHKWIDnLkJxpi3K2H8gZHK6FbUZzBjG3G80XIOYjRvNFiLnDaL4EMXcazZch5i6j+QrE3Gs0X4WY+4zmTYi532i+BjEPGM1bEPOg0XwdYh4ymm9AzMNG802IecRovgUxjxrNtyHmMaP5DsQ8bjTfhZgnjOZ7EPOk0XwfYp4ymh9AzNNG80OIecZofgQxzxrNjyHmOaP5CcQ8bzQ/hZgXjOZnEPOi0fwcYl4yml9AzMtG80uIecVofgUxrxrNryHmNaP5DcS8bjS/hZg3jOZ3EHNgNL+HmEOj+QPEXDSaP0LMkdH8CWKOjebPEHNiNFcg5pLRvA0xl43mKsScGs1fIOajRvMOxHzMaK5BzMeN5jrEfMJo/goxnzSav0HMp4zm7xDzaaP5B8R8xmj+CTGfNZp/QcznjObfEPN5o/kPxNxtNP+FmHuM5n8tMPfkr83/cdOeGe0h0Z4K7THQeEH9Z/Un1b9Sf0PPXz2PdH/W/Uq/X32fu/Prpfk1tTdKe4W0d0Z7SbS3QnsNmrX3qs3eahyq3VUtq2o7Veuo2j/Vwqk2TLVSqh1SLY1qS1RrodoDrcVrbVprtVq71Fqe1ra01qO1D60FaG5cc8WaO9VcoubWNNekuZdK49DYXGNVjd00llHfXn1d9f3UF1LfQM9KPTt0L9W9Rb81fff0WewCHFR1DShPAAA=", + "bytecode": "H4sIAAAAAAAA/9Xc12/aUBzFcUKTdO/svfewsQ02XWm6994roYHu3f7/5SggRXnN4eF7JQv8Yp2PAPuO3+VfLper5LZbW/3I14/2xvvmeceu887G+52teb7WeI2CYhxXS4VqGIWbQSGrpEkQJ5ViGqZhkiZbhTSKqmmclrJKVgqyMI6qYS3Jolqw3Xp2XCvYY2tlzl5Izj5Izn5IzgFIzkFIziFIzmFIzhFIzlFIzjFIznFIzglIzklIzilIzmlIzhlIzllIzjlIznlIzgVIzkVIziVIzmVIzhVIzlVIzgCSM4TkLEByRpCcMSRnAslZhOQsQXKmkJwZJGe5RTnzu3IGe2thm9F8BmLOG81nIeZ9RvM5iLndaD4PMXcYzRcg5k6jeQ1i7jGaL0LMvUbzOsTcZzRfgpj7jebLEPOA0XwFYh40mq9CzENG8zWIedhovg4xjxjNNyDmUaP5JsQ8ZjTfgpjHjebbEPOE0XwHYp40mu9CzFNG8z2Iedpovg8xzxjNDyDmWaP5IcQ8ZzQ/gpjnjebHEPOC0fwEYl40mp9CzEtG8zOIedlofg4xrxjNLyDmVaP5JcQcGM2vIObQaH4NMReM5jcQc2Q0v4WYY6P5HcScGM0bEHPRaN6EmEtGcwViTo3m9xBzZjRvQcxlo7kKMe83mmsQ8wGj+QPEfNBo/ggxHzKaP0HMh43mzxDzEaP5C8R81Gj+CjEfM5q/QczHjebvEPMJo/kHxHzSaP4JMZ8ymn9BzKeN5t8Qc5fR/Adi7jaa/7bA3N14bf5fn/ZGaa+Q9s5oL4nGhRonadygfrT6lepnqd+h57CeS7pP676l37G+112N65Yb19ZeOO0N014p7R1q7qXRXov1+qFafNWmq1Zbtcuq5VVtq2o9VfuoWkDVxqlWTLVTqiVSbY1qTVR7oVoErc1rrVprt1rL1Nqe1rq09qO1EK0NaK5cc8eaS92oH5pr09yT5mI0N6GxusauGstpbKO+vvq+6guqb6S+gp6depbo3qp7jX57+i7qs/kPVgMtpSBRAAA=", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -95,7 +95,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] From a6812730b059ad62cf67f3a36bc137f6cb934145 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:18:02 +0000 Subject: [PATCH 49/58] refactor: rename historic block hash data and remove nested private tree roots --- .../circuits/abis/combined_constant_data.hpp | 18 ++-- .../abis/constant_block_hash_data.hpp | 100 ------------------ ...s.hpp => constant_historic_block_data.hpp} | 59 ++++++++--- circuits/cpp/src/aztec3/circuits/hash.hpp | 1 - .../native_private_kernel_circuit_init.cpp | 31 +++--- .../native_private_kernel_circuit_inner.cpp | 5 +- ...tive_private_kernel_circuit_inner.test.cpp | 38 +++---- .../kernel/private/testing_harness.cpp | 17 ++- .../aztec3/circuits/kernel/public/.test.cpp | 45 ++++---- .../base/native_base_rollup_circuit.cpp | 11 +- .../circuits/rollup/test_utils/utils.cpp | 24 ++--- 11 files changed, 120 insertions(+), 229 deletions(-) delete mode 100644 circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp rename circuits/cpp/src/aztec3/circuits/abis/{private_historic_tree_roots.hpp => constant_historic_block_data.hpp} (56%) diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp index 15f4fd161e2..6b7559ea838 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp @@ -2,7 +2,7 @@ #include "tx_context.hpp" -#include "aztec3/circuits/abis/constant_block_hash_data.hpp" +#include "aztec3/circuits/abis/constant_historic_block_data.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" @@ -11,7 +11,7 @@ namespace aztec3::circuits::abis { -using aztec3::circuits::abis::ConstantBlockHashData; +using aztec3::circuits::abis::ConstantHistoricBlockData; using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; @@ -20,14 +20,14 @@ template struct CombinedConstantData { using fr = typename NCT::fr; using boolean = typename NCT::boolean; - ConstantBlockHashData block_hash_values{}; + ConstantHistoricBlockData block_data{}; TxContext tx_context{}; // for serialization: update up with new fields - MSGPACK_FIELDS(block_hash_values, tx_context); + MSGPACK_FIELDS(block_data, tx_context); boolean operator==(CombinedConstantData const& other) const { - return block_hash_values == other.block_hash_values && tx_context == other.tx_context; + return block_data == other.block_data && tx_context == other.tx_context; } template CombinedConstantData> to_circuit_type(Builder& builder) const @@ -35,7 +35,7 @@ template struct CombinedConstantData { static_assert((std::is_same::value)); CombinedConstantData> constant_data = { - block_hash_values.to_circuit_type(builder), + block_data.to_circuit_type(builder), tx_context.to_circuit_type(builder), }; @@ -49,7 +49,7 @@ template struct CombinedConstantData { auto to_native_type = [](T& e) { return e.template to_native_type(); }; CombinedConstantData constant_data = { - to_native_type(block_hash_values), + to_native_type(block_data), to_native_type(tx_context), }; @@ -60,14 +60,14 @@ template struct CombinedConstantData { { static_assert(!(std::is_same::value)); - block_hash_values.set_public(); + block_data.set_public(); tx_context.set_public(); } }; template std::ostream& operator<<(std::ostream& os, CombinedConstantData const& constant_data) { - return os << "block_hash_values: " << constant_data.block_hash_values << "\n" + return os << "block_data: " << constant_data.block_data << "\n" << "tx_context: " << constant_data.tx_context << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp deleted file mode 100644 index 078625f7cd3..00000000000 --- a/circuits/cpp/src/aztec3/circuits/abis/constant_block_hash_data.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once -#include "private_historic_tree_roots.hpp" - -#include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" -#include "aztec3/circuits/abis/global_variables.hpp" -#include "aztec3/circuits/hash.hpp" -#include "aztec3/utils/types/circuit_types.hpp" -#include "aztec3/utils/types/convert.hpp" -#include "aztec3/utils/types/native_types.hpp" - -#include - -namespace aztec3::circuits::abis { - -using aztec3::circuits::abis::PrivateHistoricTreeRoots; -using aztec3::utils::types::CircuitTypes; -using aztec3::utils::types::NativeTypes; -using std::is_same; - -template struct ConstantBlockHashData { - using fr = typename NCT::fr; - using boolean = typename NCT::boolean; - - PrivateHistoricTreeRoots private_historic_tree_roots{}; - - fr public_data_tree_root = 0; - fr prev_global_variables_hash = 0; - - // for serialization, update with new fields - MSGPACK_FIELDS(private_historic_tree_roots, public_data_tree_root, prev_global_variables_hash); - - boolean operator==(ConstantBlockHashData const& other) const - { - return private_historic_tree_roots == other.private_historic_tree_roots && - public_data_tree_root == other.public_data_tree_root && - prev_global_variables_hash == other.prev_global_variables_hash; - }; - - template ConstantBlockHashData> to_circuit_type(Builder& builder) const - { - static_assert((std::is_same::value)); - - // Capture the circuit builder: - auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(builder); }; - auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; - - ConstantBlockHashData> data = { - to_circuit_type(private_historic_tree_roots), - to_ct(public_data_tree_root), - to_ct(prev_global_variables_hash), - }; - - return data; - }; - - template ConstantBlockHashData to_native_type() const - { - static_assert(std::is_same, NCT>::value); - auto to_native_type = [&](T& e) { return e.template to_native_type(); }; - auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; - - ConstantBlockHashData data = { - to_native_type(private_historic_tree_roots), - to_nt(public_data_tree_root), - to_nt(prev_global_variables_hash), - }; - - return data; - }; - - void set_public() - { - static_assert(!(std::is_same::value)); - - private_historic_tree_roots.set_public(); - public_data_tree_root.set_public(); - prev_global_variables_hash.set_public(); - } - - - fr hash() - { - return compute_block_hash(prev_global_variables_hash, - private_historic_tree_roots.private_data_tree_root, - private_historic_tree_roots.nullifier_tree_root, - private_historic_tree_roots.contract_tree_root, - private_historic_tree_roots.l1_to_l2_data_tree_root, - public_data_tree_root); - } -}; - -template -std::ostream& operator<<(std::ostream& os, ConstantBlockHashData const& historic_tree_roots) -{ - return os << "private_historic_tree_roots: " << historic_tree_roots.private_historic_tree_roots << "\n" - << "public_data_tree_root: " << historic_tree_roots.public_data_tree_root << "\n" - << "prev_global_variables_hash: " << historic_tree_roots.prev_global_variables_hash << "\n"; -} - -} // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_historic_tree_roots.hpp b/circuits/cpp/src/aztec3/circuits/abis/constant_historic_block_data.hpp similarity index 56% rename from circuits/cpp/src/aztec3/circuits/abis/private_historic_tree_roots.hpp rename to circuits/cpp/src/aztec3/circuits/abis/constant_historic_block_data.hpp index 0fc7676937a..8a9ed2a3a6c 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_historic_tree_roots.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/constant_historic_block_data.hpp @@ -1,5 +1,8 @@ #pragma once +#include "aztec3/circuits/abis/append_only_tree_snapshot.hpp" +#include "aztec3/circuits/abis/global_variables.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" @@ -12,10 +15,11 @@ using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; -template struct PrivateHistoricTreeRoots { +template struct ConstantHistoricBlockData { using fr = typename NCT::fr; using boolean = typename NCT::boolean; + // Private data fr private_data_tree_root = 0; fr nullifier_tree_root = 0; fr contract_tree_root = 0; @@ -23,46 +27,56 @@ template struct PrivateHistoricTreeRoots { fr blocks_tree_root = 0; fr private_kernel_vk_tree_root = 0; // TODO: future enhancement - // for serialization: update up with new fields + // Public data + fr public_data_tree_root = 0; + fr prev_global_variables_hash = 0; + + // for serialization, update with new fields MSGPACK_FIELDS(private_data_tree_root, nullifier_tree_root, contract_tree_root, l1_to_l2_messages_tree_root, blocks_tree_root, - private_kernel_vk_tree_root); + private_kernel_vk_tree_root, + public_data_tree_root, + prev_global_variables_hash); - boolean operator==(PrivateHistoricTreeRoots const& other) const + boolean operator==(ConstantHistoricBlockData const& other) const { return private_data_tree_root == other.private_data_tree_root && nullifier_tree_root == other.nullifier_tree_root && contract_tree_root == other.contract_tree_root && l1_to_l2_messages_tree_root == other.l1_to_l2_messages_tree_root && blocks_tree_root == other.historic_block_root && - private_kernel_vk_tree_root == other.private_kernel_vk_tree_root; + private_kernel_vk_tree_root == other.private_kernel_vk_tree_root && + public_data_tree_root == other.public_data_tree_root && + prev_global_variables_hash == other.prev_global_variables_hash; }; - template PrivateHistoricTreeRoots> to_circuit_type(Builder& builder) const + template ConstantHistoricBlockData> to_circuit_type(Builder& builder) const { static_assert((std::is_same::value)); // Capture the circuit builder: auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; - PrivateHistoricTreeRoots> data = { - to_ct(private_data_tree_root), to_ct(nullifier_tree_root), to_ct(contract_tree_root), - to_ct(l1_to_l2_messages_tree_root), to_ct(blocks_tree_root), to_ct(private_kernel_vk_tree_root), + ConstantHistoricBlockData> data = { + to_ct(private_data_tree_root), to_ct(nullifier_tree_root), to_ct(contract_tree_root), + to_ct(l1_to_l2_messages_tree_root), to_ct(blocks_tree_root), to_ct(private_kernel_vk_tree_root), + to_ct(public_data_tree_root), to_ct(prev_global_variables_hash), }; return data; }; - template PrivateHistoricTreeRoots to_native_type() const + template ConstantHistoricBlockData to_native_type() const { static_assert(std::is_same, NCT>::value); auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; - PrivateHistoricTreeRoots data = { - to_nt(private_data_tree_root), to_nt(nullifier_tree_root), to_nt(contract_tree_root), - to_nt(l1_to_l2_messages_tree_root), to_nt(blocks_tree_root), to_nt(private_kernel_vk_tree_root), + ConstantHistoricBlockData data = { + to_nt(private_data_tree_root), to_nt(nullifier_tree_root), to_nt(contract_tree_root), + to_nt(l1_to_l2_messages_tree_root), to_nt(blocks_tree_root), to_nt(private_kernel_vk_tree_root), + to_nt(public_data_tree_root), to_nt(prev_global_variables_hash), }; return data; @@ -78,18 +92,33 @@ template struct PrivateHistoricTreeRoots { l1_to_l2_messages_tree_root.set_public(); blocks_tree_root.set_public(); private_kernel_vk_tree_root.set_public(); + public_data_tree_root.set_public(); + prev_global_variables_hash.set_public(); + } + + + fr hash() + { + return compute_block_hash(prev_global_variables_hash, + private_data_tree_root, + nullifier_tree_root, + contract_tree_root, + l1_to_l2_messages_tree_root, + public_data_tree_root); } }; template -std::ostream& operator<<(std::ostream& os, PrivateHistoricTreeRoots const& historic_tree_roots) +std::ostream& operator<<(std::ostream& os, ConstantHistoricBlockData const& historic_tree_roots) { return os << "private_data_tree_root: " << historic_tree_roots.private_data_tree_root << "\n" << "nullifier_tree_root: " << historic_tree_roots.nullifier_tree_root << "\n" << "contract_tree_root: " << historic_tree_roots.contract_tree_root << "\n" << "l1_to_l2_messages_tree_root: " << historic_tree_roots.l1_to_l2_messages_tree_root << "\n" << "blocks_tree_root: " << historic_tree_roots.blocks_tree_root << "\n" - << "private_kernel_vk_tree_root: " << historic_tree_roots.private_kernel_vk_tree_root << "\n"; + << "private_kernel_vk_tree_root: " << historic_tree_roots.private_kernel_vk_tree_root << "\n" + << "public_data_tree_root: " << historic_tree_roots.public_data_tree_root << "\n" + << "prev_global_variables_hash: " << historic_tree_roots.prev_global_variables_hash << "\n"; } } // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 2be245ff5f9..8d3ed34711c 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -5,7 +5,6 @@ #include "aztec3/circuits/abis/global_variables.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/point.hpp" -#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/circuit_errors.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp index 022e24eaaf0..4d49ed5380a 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp @@ -2,8 +2,7 @@ #include "init.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/constant_block_hash_data.hpp" -#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/constant_historic_block_data.hpp" #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" #include "aztec3/utils/array.hpp" @@ -12,9 +11,8 @@ namespace { using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::ConstantBlockHashData; +using aztec3::circuits::abis::ConstantHistoricBlockData; using aztec3::circuits::abis::KernelCircuitPublicInputs; -using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; using aztec3::utils::array_push; using aztec3::utils::CircuitErrorCode; @@ -28,19 +26,16 @@ void initialise_end_values(PrivateKernelInputsInit const& private_inputs, // Define the constants data. auto const& private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; auto const constants = CombinedConstantData{ - .block_hash_values = - ConstantBlockHashData{ - .private_historic_tree_roots = - PrivateHistoricTreeRoots{ - // TODO(dbanks12): remove historic root from app circuit public inputs and - // add it to PrivateCallData: https://github.com/AztecProtocol/aztec-packages/issues/778 - // Then use this: - // .private_data_tree_root = private_inputs.private_call.historic_private_data_tree_root, - .private_data_tree_root = private_call_public_inputs.historic_private_data_tree_root, - .nullifier_tree_root = private_call_public_inputs.historic_nullifier_tree_root, - .contract_tree_root = private_call_public_inputs.historic_contract_tree_root, - .l1_to_l2_messages_tree_root = private_call_public_inputs.historic_l1_to_l2_messages_tree_root, - }, + .block_data = + ConstantHistoricBlockData{ + // TODO(dbanks12): remove historic root from app circuit public inputs and + // add it to PrivateCallData: https://github.com/AztecProtocol/aztec-packages/issues/778 + // Then use this: + // .private_data_tree_root = private_inputs.private_call.historic_private_data_tree_root, + .private_data_tree_root = private_call_public_inputs.historic_private_data_tree_root, + .nullifier_tree_root = private_call_public_inputs.historic_nullifier_tree_root, + .contract_tree_root = private_call_public_inputs.historic_contract_tree_root, + .l1_to_l2_messages_tree_root = private_call_public_inputs.historic_l1_to_l2_messages_tree_root, .public_data_tree_root = private_call_public_inputs.historic_public_data_tree_root, .prev_global_variables_hash = private_call_public_inputs.historic_global_variables_hash, }, @@ -195,7 +190,7 @@ KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyCircuit common_validate_read_requests( builder, - public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root, + public_inputs.constants.block_data.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp index ec1e697cf48..78f5a65b57d 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp @@ -99,8 +99,7 @@ void validate_contract_tree_root(DummyCircuitBuilder& builder, PrivateKernelInpu auto const& purported_contract_tree_root = private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; auto const& previous_kernel_contract_tree_root = - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .contract_tree_root; + private_inputs.previous_kernel.public_inputs.constants.block_data.contract_tree_root; builder.do_assert( purported_contract_tree_root == previous_kernel_contract_tree_root, "purported_contract_tree_root doesn't match previous_kernel_contract_tree_root", @@ -158,7 +157,7 @@ KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyCircuitBu common_validate_read_requests( builder, - public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root, + public_inputs.constants.block_data.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp index 81cc7eff5d2..94dcba72597 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp @@ -93,9 +93,8 @@ TEST_F(native_private_kernel_inner_tests, private_function_incorrect_contract_tr { auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); - // Set private_historic_tree_roots to a random scalar. - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .contract_tree_root = NT::fr::random_element(); + // Set historic_tree_root to a random scalar. + private_inputs.previous_kernel.public_inputs.constants.block_data.contract_tree_root = NT::fr::random_element(); // Invoke the native private kernel circuit DummyBuilder builder = DummyBuilder("private_kernel_tests__private_function_incorrect_contract_tree_root_fails"); @@ -259,8 +258,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_request) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak read_request so it gives wrong root when paired with its sibling path @@ -299,8 +297,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_leaf_index) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak leaf index so it gives wrong root when paired with its request and sibling path @@ -338,8 +335,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_sibling_path) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak sibling path so it gives wrong root when paired with its request @@ -378,8 +374,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_root_mismatch) _transient_read_requests0, _transient_read_request_membership_witnesses0, root] = get_random_reads(first_nullifier, contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; auto [read_requests1, read_request_membership_witnesses1, @@ -465,8 +460,7 @@ TEST_F(native_private_kernel_inner_tests, native_one_read_requests_works) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, 1); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -507,8 +501,7 @@ TEST_F(native_private_kernel_inner_tests, native_two_read_requests_works) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, 2); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -549,8 +542,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_works) _transient_read_requests, _transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -592,8 +584,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_less_than_witness root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); read_requests[MAX_READ_REQUESTS_PER_CALL - 1] = fr(0); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -630,8 +621,7 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_more_than_witness read_request_membership_witnesses[MAX_READ_REQUESTS_PER_CALL - 1] = ReadRequestMembershipWitness{}; - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -710,8 +700,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_one_transient transient_read_requests, transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // Make the read request at position 1 transient @@ -758,8 +747,7 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_all_transient transient_read_requests, transient_read_request_membership_witnesses, root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); - private_inputs.previous_kernel.public_inputs.constants.block_hash_values.private_historic_tree_roots - .private_data_tree_root = root; + private_inputs.previous_kernel.public_inputs.constants.block_data.private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = transient_read_requests; private_inputs.private_call.read_request_membership_witnesses = transient_read_request_membership_witnesses; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp index 36373d3b779..9343a0c5ce3 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp @@ -7,11 +7,10 @@ #include "aztec3/circuits/abis/call_stack_item.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/constant_block_hash_data.hpp" +#include "aztec3/circuits/abis/constant_historic_block_data.hpp" #include "aztec3/circuits/abis/contract_deployment_data.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/private_circuit_public_inputs.hpp" -#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" #include "aztec3/circuits/abis/tx_context.hpp" #include "aztec3/circuits/abis/tx_request.hpp" @@ -32,11 +31,10 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CombinedAccumulatedData; using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::ConstantBlockHashData; +using aztec3::circuits::abis::ConstantHistoricBlockData; using aztec3::circuits::abis::ContractDeploymentData; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::PrivateCircuitPublicInputs; -using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::PrivateTypes; using aztec3::circuits::abis::TxContext; using aztec3::circuits::abis::TxRequest; @@ -485,13 +483,10 @@ PrivateKernelInputsInner do_private_call_get_kernel_inputs_inner( // Fill in some important fields in public inputs mock_previous_kernel.public_inputs.end.private_call_stack = initial_kernel_private_call_stack; mock_previous_kernel.public_inputs.constants = CombinedConstantData{ - .block_hash_values = - ConstantBlockHashData{ - .private_historic_tree_roots = - PrivateHistoricTreeRoots{ - .private_data_tree_root = private_circuit_public_inputs.historic_private_data_tree_root, - .contract_tree_root = private_circuit_public_inputs.historic_contract_tree_root, - }, + .block_data = + ConstantHistoricBlockData{ + .private_data_tree_root = private_circuit_public_inputs.historic_private_data_tree_root, + .contract_tree_root = private_circuit_public_inputs.historic_contract_tree_root, }, .tx_context = tx_context, }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp index 5c49262d9a3..bf31be0534c 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp @@ -6,13 +6,12 @@ #include "aztec3/circuits/abis/call_stack_item.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" #include "aztec3/circuits/abis/combined_constant_data.hpp" -#include "aztec3/circuits/abis/constant_block_hash_data.hpp" +#include "aztec3/circuits/abis/constant_historic_block_data.hpp" #include "aztec3/circuits/abis/contract_deployment_data.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/private_circuit_public_inputs.hpp" -#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/circuits/abis/public_kernel/public_call_data.hpp" #include "aztec3/circuits/abis/public_kernel/public_kernel_inputs.hpp" #include "aztec3/circuits/abis/tx_context.hpp" @@ -35,11 +34,10 @@ using aztec3::circuits::abis::CallContext; using aztec3::circuits::abis::CallStackItem; using aztec3::circuits::abis::CombinedAccumulatedData; using aztec3::circuits::abis::CombinedConstantData; -using aztec3::circuits::abis::ConstantBlockHashData; +using aztec3::circuits::abis::ConstantHistoricBlockData; using aztec3::circuits::abis::NewContractData; using aztec3::circuits::abis::OptionallyRevealedData; using aztec3::circuits::abis::PreviousKernelData; -using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::PublicCircuitPublicInputs; using aztec3::circuits::abis::PublicDataRead; using aztec3::circuits::abis::PublicTypes; @@ -360,29 +358,26 @@ PublicKernelInputs get_kernel_inputs_with_previous_kernel(NT::boolean privat }; // TODO(914) Should this be unused? - [[maybe_unused]] ConstantBlockHashData const historic_tree_roots = { .private_historic_tree_roots = { - .private_data_tree_root = 1000, - .contract_tree_root = 2000, - .l1_to_l2_messages_tree_root = 3000, - .private_kernel_vk_tree_root = 4000, - } }; - - CombinedConstantData const end_constants = { - .block_hash_values = - ConstantBlockHashData{ .private_historic_tree_roots = - PrivateHistoricTreeRoots{ .private_data_tree_root = ++seed, - .nullifier_tree_root = ++seed, - .contract_tree_root = ++seed, - .private_kernel_vk_tree_root = ++seed } }, - .tx_context = - TxContext{ - .is_fee_payment_tx = false, - .is_rebate_payment_tx = false, - .is_contract_deployment_tx = false, - .contract_deployment_data = {}, - } + [[maybe_unused]] ConstantHistoricBlockData const historic_tree_roots = { + .private_data_tree_root = 1000, + .contract_tree_root = 2000, + .l1_to_l2_messages_tree_root = 3000, + .private_kernel_vk_tree_root = 4000, }; + CombinedConstantData const end_constants = { .block_data = + ConstantHistoricBlockData{ + .private_data_tree_root = ++seed, + .nullifier_tree_root = ++seed, + .contract_tree_root = ++seed, + .private_kernel_vk_tree_root = ++seed }, + .tx_context = TxContext{ + .is_fee_payment_tx = false, + .is_rebate_payment_tx = false, + .is_contract_deployment_tx = false, + .contract_deployment_data = {}, + } }; + std::array public_call_stack{}; public_call_stack[0] = public_call_data.call_stack_item.hash(); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 43484867226..d892237c29e 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -139,13 +139,12 @@ void perform_historical_blocks_tree_membership_checks(DummyBuilder& builder, Bas for (size_t i = 0; i < 2; i++) { // Rebuild the block hash - auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.block_hash_values; - auto historic_tree_roots = historic_block.private_historic_tree_roots; + auto historic_block = baseRollupInputs.kernel_data[i].public_inputs.constants.block_data; - auto private_data_tree_root = historic_tree_roots.private_data_tree_root; - auto nullifier_tree_root = historic_tree_roots.nullifier_tree_root; - auto contract_tree_root = historic_tree_roots.contract_tree_root; - auto l1_to_l2_data_tree_root = historic_tree_roots.l1_to_l2_messages_tree_root; + auto private_data_tree_root = historic_block.private_data_tree_root; + auto nullifier_tree_root = historic_block.nullifier_tree_root; + auto contract_tree_root = historic_block.contract_tree_root; + auto l1_to_l2_data_tree_root = historic_block.l1_to_l2_messages_tree_root; auto public_data_tree_root = historic_block.public_data_tree_root; auto previous_block_hash = compute_block_hash(historic_block.prev_global_variables_hash, diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index b53da587b8f..e0e5196f3a8 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -172,22 +172,14 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne // Set historic tree roots data in the public inputs. for (size_t i = 0; i < 2; i++) { - kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.private_data_tree_root = - private_data_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.nullifier_tree_root = - nullifier_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.nullifier_tree_root = - nullifier_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.contract_tree_root = - contract_tree.root(); - kernel_data[i] - .public_inputs.constants.block_hash_values.private_historic_tree_roots.l1_to_l2_messages_tree_root = - l1_to_l2_msg_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.private_historic_tree_roots.blocks_tree_root = - historic_blocks_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.public_data_tree_root = public_data_tree.root(); - kernel_data[i].public_inputs.constants.block_hash_values.prev_global_variables_hash = - prev_global_variables_hash; + kernel_data[i].public_inputs.constants.block_data.private_data_tree_root = private_data_tree.root(); + kernel_data[i].public_inputs.constants.block_data.nullifier_tree_root = nullifier_tree.root(); + kernel_data[i].public_inputs.constants.block_data.nullifier_tree_root = nullifier_tree.root(); + kernel_data[i].public_inputs.constants.block_data.contract_tree_root = contract_tree.root(); + kernel_data[i].public_inputs.constants.block_data.l1_to_l2_messages_tree_root = l1_to_l2_msg_tree.root(); + kernel_data[i].public_inputs.constants.block_data.blocks_tree_root = historic_blocks_tree.root(); + kernel_data[i].public_inputs.constants.block_data.public_data_tree_root = public_data_tree.root(); + kernel_data[i].public_inputs.constants.block_data.prev_global_variables_hash = prev_global_variables_hash; } // Then we collect all sibling paths for the reads in the left tx, and then apply the update requests while From ae967ae60a37d7754e2c68cb65ff450df79b7117 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:38:37 +0000 Subject: [PATCH 50/58] refactor: rename in ts --- .../src/client/client_execution_context.ts | 10 +- .../src/client/private_execution.test.ts | 11 +- .../src/client/private_execution.ts | 13 +- .../acir-simulator/src/client/simulator.ts | 16 +-- .../client/unconstrained_execution.test.ts | 6 +- yarn-project/acir-simulator/src/public/db.ts | 8 +- .../acir-simulator/src/public/executor.ts | 28 ++--- .../acir-simulator/src/public/index.test.ts | 6 +- .../src/aztec_rpc_server/aztec_rpc_server.ts | 14 +-- .../aztec-rpc/src/kernel_oracle/index.ts | 9 +- .../aztec-rpc/src/simulator_oracle/index.ts | 9 +- .../circuits.js/src/cbind/circuits.gen.ts | 103 +++++++--------- yarn-project/circuits.js/src/cbind/types.ts | 3 +- yarn-project/circuits.js/src/structs/index.ts | 2 +- .../structs/kernel/combined_constant_data.ts | 10 +- ...ata.ts => constant_historic_block_data.ts} | 111 ++++++------------ .../circuits.js/src/tests/factories.ts | 18 +-- .../src/integration_l1_publisher.test.ts | 6 +- .../block_builder/solo_block_builder.test.ts | 8 +- .../src/block_builder/solo_block_builder.ts | 10 +- .../src/sequencer/processed_tx.ts | 6 +- .../src/sequencer/public_processor.test.ts | 6 +- .../src/sequencer/public_processor.ts | 8 +- .../src/sequencer/sequencer.test.ts | 4 +- .../sequencer-client/src/sequencer/utils.ts | 8 +- .../src/simulator/public_executor.ts | 14 ++- 26 files changed, 189 insertions(+), 258 deletions(-) rename yarn-project/circuits.js/src/structs/kernel/{constant_block_hash_data.ts => constant_historic_block_data.ts} (55%) diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index b46d92cc301..40d3e11c278 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -1,4 +1,4 @@ -import { ConstantBlockHashData, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; +import { ConstantHistoricBlockData, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -34,7 +34,7 @@ export class ClientTxExecutionContext { /** The tx context. */ public txContext: TxContext, /** Data required to reconstruct the block hash, it contains historic roots. */ - public constantBlockHashData: ConstantBlockHashData, + public constantHistoricBlockData: ConstantHistoricBlockData, /** The cache of packed arguments */ public packedArgsCache: PackedArgsCache, /** Pending notes created (and not nullified) up to current point in execution. @@ -56,7 +56,7 @@ export class ClientTxExecutionContext { this.db, this.txNullifier, this.txContext, - this.constantBlockHashData, + this.constantHistoricBlockData, this.packedArgsCache, this.pendingNotes, this.pendingNullifiers, @@ -200,7 +200,7 @@ export class ClientTxExecutionContext { const messageInputs = await this.db.getL1ToL2Message(msgKey); return toAcvmL1ToL2MessageLoadOracleInputs( messageInputs, - this.constantBlockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + this.constantHistoricBlockData.l1ToL2MessagesTreeRoot, ); } @@ -216,7 +216,7 @@ export class ClientTxExecutionContext { this.readRequestPartialWitnesses.push(ReadRequestMembershipWitness.empty(commitmentInputs.index)); return toAcvmCommitmentLoadOracleInputs( commitmentInputs, - this.constantBlockHashData.privateHistoricTreeRoots.privateDataTreeRoot, + this.constantHistoricBlockData.privateDataTreeRoot, ); } diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index aad8dc9d266..31a075adac2 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -1,14 +1,13 @@ import { CallContext, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, ContractDeploymentData, FieldsOf, FunctionData, L1_TO_L2_MSG_TREE_HEIGHT, MAX_NEW_COMMITMENTS_PER_CALL, PRIVATE_DATA_TREE_HEIGHT, - PrivateHistoricTreeRoots, PrivateKey, PublicCallRequest, TxContext, @@ -59,7 +58,7 @@ describe('Private Execution test suite', () => { let circuitsWasm: CircuitsWasm; let oracle: MockProxy; let acirSimulator: AcirSimulator; - let blockHashData = ConstantBlockHashData.empty(); + let blockHashData = ConstantHistoricBlockData.empty(); let logger: DebugLogger; const defaultContractAddress = AztecAddress.random(); @@ -125,10 +124,10 @@ describe('Private Execution test suite', () => { // Update root. const newRoot = trees[name].getRoot(false); - const prevRoots = blockHashData.privateHistoricTreeRoots.toBuffer(); + const prevRoots = blockHashData.toBuffer(); const rootIndex = name === 'privateData' ? 0 : 32 * 3; - const newRoots = Buffer.concat([prevRoots.slice(0, rootIndex), newRoot, prevRoots.slice(rootIndex + 32)]); - blockHashData = new ConstantBlockHashData(PrivateHistoricTreeRoots.fromBuffer(newRoots), Fr.ZERO, Fr.ZERO); + const newRoots = Buffer.concat([prevRoots.subarray(0, rootIndex), newRoot, prevRoots.subarray(rootIndex + 32)]); + blockHashData = ConstantHistoricBlockData.fromBuffer(newRoots); return trees[name]; }; diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index c745e7e7e11..242cc26c2dc 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -219,8 +219,7 @@ export class PrivateFunctionExecution { private writeInputs() { const contractDeploymentData = this.context.txContext.contractDeploymentData ?? ContractDeploymentData.empty(); - const blockData = this.context.constantBlockHashData; - const { privateHistoricTreeRoots } = blockData; + const blockData = this.context.constantHistoricBlockData; const fields = [ this.callContext.msgSender, @@ -230,11 +229,11 @@ export class PrivateFunctionExecution { this.callContext.isStaticCall, this.callContext.isContractDeployment, - privateHistoricTreeRoots.privateDataTreeRoot, - privateHistoricTreeRoots.nullifierTreeRoot, - privateHistoricTreeRoots.contractTreeRoot, - privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, - privateHistoricTreeRoots.blocksTreeRoot, + blockData.privateDataTreeRoot, + blockData.nullifierTreeRoot, + blockData.contractTreeRoot, + blockData.l1ToL2MessagesTreeRoot, + blockData.blocksTreeRoot, blockData.prevGlobalVariablesHash, blockData.publicDataTreeRoot, diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index 0c91343a75a..6cec39835e0 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -1,4 +1,4 @@ -import { CallContext, CircuitsWasm, ConstantBlockHashData, FunctionData, TxContext } from '@aztec/circuits.js'; +import { CallContext, CircuitsWasm, ConstantHistoricBlockData, FunctionData, TxContext } from '@aztec/circuits.js'; import { computeTxHash } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { ArrayType, FunctionAbi, FunctionType, encodeArguments } from '@aztec/foundation/abi'; @@ -32,7 +32,7 @@ export class AcirSimulator { * @param entryPointABI - The ABI of the entry point function. * @param contractAddress - The address of the contract (should match request.origin) * @param portalContractAddress - The address of the portal contract. - * @param constantBlockHashData - Data required to reconstruct the block hash, this also contains the historic tree roots. + * @param constantHistoricBlockData - Data required to reconstruct the block hash, this also contains the historic tree roots. * @param curve - The curve instance for elliptic curve operations. * @param packedArguments - The entrypoint packed arguments * @returns The result of the execution. @@ -42,7 +42,7 @@ export class AcirSimulator { entryPointABI: FunctionAbi, contractAddress: AztecAddress, portalContractAddress: EthAddress, - constantBlockHashData: ConstantBlockHashData, + constantHistoricBlockData: ConstantHistoricBlockData, ): Promise { if (entryPointABI.functionType !== FunctionType.SECRET) { throw new Error(`Cannot run ${entryPointABI.functionType} function as secret`); @@ -70,7 +70,7 @@ export class AcirSimulator { this.db, txNullifier, request.txContext, - constantBlockHashData, + constantHistoricBlockData, await PackedArgsCache.create(request.packedArguments), ), entryPointABI, @@ -91,7 +91,7 @@ export class AcirSimulator { * @param entryPointABI - The ABI of the entry point function. * @param contractAddress - The address of the contract. * @param portalContractAddress - The address of the portal contract. - * @param constantBlockHashData - Block data containing historic roots. + * @param constantHistoricBlockData - Block data containing historic roots. * @returns The return values of the function. */ public async runUnconstrained( @@ -100,7 +100,7 @@ export class AcirSimulator { entryPointABI: FunctionAbi, contractAddress: AztecAddress, portalContractAddress: EthAddress, - constantBlockHashData: ConstantBlockHashData, + constantHistoricBlockData: ConstantHistoricBlockData, ) { if (entryPointABI.functionType !== FunctionType.UNCONSTRAINED) { throw new Error(`Cannot run ${entryPointABI.functionType} function as constrained`); @@ -119,7 +119,7 @@ export class AcirSimulator { this.db, Fr.ZERO, TxContext.empty(), - constantBlockHashData, + constantHistoricBlockData, await PackedArgsCache.create([]), ), entryPointABI, @@ -164,7 +164,7 @@ export class AcirSimulator { abi, AztecAddress.ZERO, EthAddress.ZERO, - ConstantBlockHashData.empty(), + ConstantHistoricBlockData.empty(), ); return { diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts index 9f4ccace89b..3af3e2f56ce 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts @@ -1,4 +1,4 @@ -import { CircuitsWasm, ConstantBlockHashData, FunctionData, PrivateKey } from '@aztec/circuits.js'; +import { CircuitsWasm, ConstantHistoricBlockData, FunctionData, PrivateKey } from '@aztec/circuits.js'; import { computeContractAddressFromPartial } from '@aztec/circuits.js/abis'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { encodeArguments } from '@aztec/foundation/abi'; @@ -60,7 +60,7 @@ describe('Unconstrained Execution test suite', () => { const preimages = [...Array(5).fill(buildNote(1n, owner)), ...Array(2).fill(buildNote(2n, owner))]; - const constantBlockHashData = ConstantBlockHashData.empty(); + const constantHistoricBlockData = ConstantHistoricBlockData.empty(); oracle.getNotes.mockResolvedValue( preimages.map((preimage, index) => ({ @@ -86,7 +86,7 @@ describe('Unconstrained Execution test suite', () => { abi, AztecAddress.random(), EthAddress.ZERO, - constantBlockHashData, + constantHistoricBlockData, ); expect(result).toEqual([9n]); diff --git a/yarn-project/acir-simulator/src/public/db.ts b/yarn-project/acir-simulator/src/public/db.ts index f03c075b424..3cb190e3e3a 100644 --- a/yarn-project/acir-simulator/src/public/db.ts +++ b/yarn-project/acir-simulator/src/public/db.ts @@ -1,4 +1,4 @@ -import { EthAddress, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { ConstantHistoricBlockData, EthAddress } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; @@ -73,8 +73,8 @@ export interface CommitmentsDB { getCommitmentOracle(address: AztecAddress, commitment: Fr): Promise; /** - * Gets the current tree roots from the merkle db. - * @returns current tree roots. + * Gets the current historic block data from the merkle db. + * @returns the previous blocks roots and global variables hash. */ - getTreeRoots(): PrivateHistoricTreeRoots; + getHistoricBlockData(): ConstantHistoricBlockData; } diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index d98ed903702..c8157a2ea1d 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -1,7 +1,7 @@ import { AztecAddress, CallContext, - ConstantBlockHashData, + ConstantHistoricBlockData, EthAddress, Fr, FunctionData, @@ -41,7 +41,7 @@ export class PublicExecutor { private readonly stateDb: PublicStateDB, private readonly contractsDb: PublicContractsDB, private readonly commitmentsDb: CommitmentsDB, - private readonly blockHashData: ConstantBlockHashData, + private readonly blockHashData: ConstantHistoricBlockData, private log = createDebugLogger('aztec:simulator:public-executor'), ) {} @@ -89,7 +89,7 @@ export class PublicExecutor { const messageInputs = await this.commitmentsDb.getL1ToL2Message(fromACVMField(msgKey)); return toAcvmL1ToL2MessageLoadOracleInputs( messageInputs, - this.blockHashData.privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, + this.blockHashData.l1ToL2MessagesTreeRoot, ); }, // l1 to l2 messages in public contexts TODO: https://github.com/AztecProtocol/aztec-packages/issues/616 getCommitment: async ([commitment]) => { @@ -99,7 +99,7 @@ export class PublicExecutor { ); return toAcvmCommitmentLoadOracleInputs( commitmentInputs, - this.blockHashData.privateHistoricTreeRoots.privateDataTreeRoot, + this.blockHashData.privateDataTreeRoot, ); }, storageRead: async ([slot], [numberOfElements]) => { @@ -225,7 +225,7 @@ export class PublicExecutor { * Generates the initial witness for a public function. * @param args - The arguments to the function. * @param callContext - The call context of the function. - * @param constantBlockHashData - Historic Trees roots and data required to reconstruct block hash. + * @param constantHistoricBlockData - Historic Trees roots and data required to reconstruct block hash. * @param globalVariables - The global variables. * @param witnessStartIndex - The index where to start inserting the parameters. * @returns The initial witness. @@ -233,12 +233,10 @@ export class PublicExecutor { function getInitialWitness( args: Fr[], callContext: CallContext, - constantBlockHashData: ConstantBlockHashData, + constantHistoricBlockData: ConstantHistoricBlockData, globalVariables: GlobalVariables, witnessStartIndex = 1, ) { - const { privateHistoricTreeRoots } = constantBlockHashData; - return toACVMWitness(witnessStartIndex, [ callContext.msgSender, callContext.storageContractAddress, @@ -247,13 +245,13 @@ function getInitialWitness( callContext.isStaticCall, callContext.isContractDeployment, - privateHistoricTreeRoots.privateDataTreeRoot, - privateHistoricTreeRoots.nullifierTreeRoot, - privateHistoricTreeRoots.contractTreeRoot, - privateHistoricTreeRoots.l1ToL2MessagesTreeRoot, - privateHistoricTreeRoots.blocksTreeRoot, - constantBlockHashData.prevGlobalVariablesHash, - constantBlockHashData.publicDataTreeRoot, + constantHistoricBlockData.privateDataTreeRoot, + constantHistoricBlockData.nullifierTreeRoot, + constantHistoricBlockData.contractTreeRoot, + constantHistoricBlockData.l1ToL2MessagesTreeRoot, + constantHistoricBlockData.blocksTreeRoot, + constantHistoricBlockData.prevGlobalVariablesHash, + constantHistoricBlockData.publicDataTreeRoot, globalVariables.chainId, globalVariables.version, diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index a3499fc0c6b..31d6e113db7 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -1,7 +1,7 @@ import { CallContext, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, FunctionData, GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT, @@ -37,7 +37,7 @@ describe('ACIR public execution simulator', () => { let publicContracts: MockProxy; let commitmentsDb: MockProxy; let executor: PublicExecutor; - let blockHashData: ConstantBlockHashData; + let blockHashData: ConstantHistoricBlockData; beforeAll(async () => { circuitsWasm = await CircuitsWasm.get(); @@ -48,7 +48,7 @@ describe('ACIR public execution simulator', () => { publicContracts = mock(); commitmentsDb = mock(); - blockHashData = ConstantBlockHashData.empty(); + blockHashData = ConstantHistoricBlockData.empty(); executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, blockHashData); }, 10000); diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 236118dea0a..8be1a856402 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -6,7 +6,7 @@ import { } from '@aztec/acir-simulator'; import { AztecAddress, - ConstantBlockHashData, + ConstantHistoricBlockData, FunctionData, PartialContractAddress, PrivateKey, @@ -333,7 +333,7 @@ export class AztecRPCServer implements AztecRPC { async #simulate( txRequest: TxExecutionRequest, - constantBlockHashData: ConstantBlockHashData, + constantHistoricBlockData: ConstantHistoricBlockData, contractDataOracle?: ContractDataOracle, ): Promise { // TODO - Pause syncing while simulating. @@ -355,7 +355,7 @@ export class AztecRPCServer implements AztecRPC { functionAbi, contractAddress, portalContract, - constantBlockHashData, + constantHistoricBlockData, ); this.log('Simulation completed!'); @@ -377,7 +377,7 @@ export class AztecRPCServer implements AztecRPC { async #simulateUnconstrained(execRequest: FunctionCall, from?: AztecAddress) { const contractDataOracle = new ContractDataOracle(this.db, this.node); const kernelOracle = new KernelOracle(contractDataOracle, this.node); - const constantBlockHashData = await kernelOracle.getConstantBlockHashData(); + const constantHistoricBlockData = await kernelOracle.getconstantHistoricBlockData(); const { contractAddress, functionAbi, portalContract } = await this.#getSimulationParameters( execRequest, @@ -393,7 +393,7 @@ export class AztecRPCServer implements AztecRPC { functionAbi, contractAddress, portalContract, - constantBlockHashData, + constantHistoricBlockData, ); this.log('Unconstrained simulation completed!'); @@ -419,9 +419,9 @@ export class AztecRPCServer implements AztecRPC { const kernelOracle = new KernelOracle(contractDataOracle, this.node); // Get values that allow us to reconstruct the block hash - const constantBlockHashData = await kernelOracle.getConstantBlockHashData(); + const constantHistoricBlockData = await kernelOracle.getconstantHistoricBlockData(); - const executionResult = await this.#simulate(txExecutionRequest, constantBlockHashData, contractDataOracle); + const executionResult = await this.#simulate(txExecutionRequest, constantHistoricBlockData, contractDataOracle); const kernelProver = new KernelProver(kernelOracle); this.log(`Executing kernel prover...`); diff --git a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts index d715d9b208d..d073f4ff18a 100644 --- a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts @@ -1,12 +1,11 @@ import { AztecAddress, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, Fr, GlobalVariables, MembershipWitness, PRIVATE_DATA_TREE_HEIGHT, - PrivateHistoricTreeRoots, } from '@aztec/circuits.js'; import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { Tuple } from '@aztec/foundation/serialize'; @@ -47,22 +46,20 @@ export class KernelOracle implements ProvingDataOracle { return roots[MerkleTreeId.PRIVATE_DATA_TREE]; } - async getConstantBlockHashData(): Promise { + async getconstantHistoricBlockData(): Promise { const wasm = await CircuitsWasm.get(); const latestBlock = await this.node.getBlock(-1); const latestGlobals = latestBlock?.globalVariables ?? GlobalVariables.empty(); const prevBlockGlobalVariablesHash = computeGlobalsHash(wasm, latestGlobals); const treeRoots = await this.node.getTreeRoots(); - return new ConstantBlockHashData( - new PrivateHistoricTreeRoots( + return new ConstantHistoricBlockData( treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], treeRoots[MerkleTreeId.NULLIFIER_TREE], treeRoots[MerkleTreeId.CONTRACT_TREE], treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], treeRoots[MerkleTreeId.BLOCKS_TREE], Fr.ZERO, - ), treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], prevBlockGlobalVariablesHash, ); diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 813e4a8f5e6..2874ea7c0ac 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -2,10 +2,10 @@ import { CommitmentDataOracleInputs, DBOracle, MessageLoadOracleInputs } from '@ import { AztecAddress, CircuitsWasm, + ConstantHistoricBlockData, EthAddress, Fr, PartialContractAddress, - PrivateHistoricTreeRoots, PrivateKey, PublicKey, } from '@aztec/circuits.js'; @@ -102,16 +102,19 @@ export class SimulatorOracle implements DBOracle { }); } - getTreeRoots(): PrivateHistoricTreeRoots { + getHistoricBlockData(): ConstantHistoricBlockData { const roots = this.db.getTreeRoots(); - return PrivateHistoricTreeRoots.from({ + return ConstantHistoricBlockData.from({ privateKernelVkTreeRoot: Fr.ZERO, + // TODO: work out how to get the previous globals hash in here + prevGlobalVariablesHash: Fr.ZERO, privateDataTreeRoot: roots[MerkleTreeId.PRIVATE_DATA_TREE], contractTreeRoot: roots[MerkleTreeId.CONTRACT_TREE], nullifierTreeRoot: roots[MerkleTreeId.NULLIFIER_TREE], l1ToL2MessagesTreeRoot: roots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], blocksTreeRoot: roots[MerkleTreeId.BLOCKS_TREE], + publicDataTreeRoot: roots[MerkleTreeId.PUBLIC_DATA_TREE], }); } } diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index 0b82101fca7..606d3f54725 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -13,7 +13,7 @@ import { CircuitError, CombinedAccumulatedData, CombinedConstantData, - ConstantBlockHashData, + ConstantHistoricBlockData, ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, @@ -28,7 +28,6 @@ import { OptionallyRevealedData, Point, PreviousKernelData, - PrivateHistoricTreeRoots, Proof, PublicCallData, PublicCallStackItem, @@ -629,62 +628,78 @@ export function fromCombinedAccumulatedData(o: CombinedAccumulatedData): Msgpack }; } -interface MsgpackPrivateHistoricTreeRoots { +interface MsgpackConstantHistoricBlockData { private_data_tree_root: Buffer; nullifier_tree_root: Buffer; contract_tree_root: Buffer; l1_to_l2_messages_tree_root: Buffer; blocks_tree_root: Buffer; private_kernel_vk_tree_root: Buffer; + public_data_tree_root: Buffer; + prev_global_variables_hash: Buffer; } -export function toPrivateHistoricTreeRoots(o: MsgpackPrivateHistoricTreeRoots): PrivateHistoricTreeRoots { +export function toConstantHistoricBlockData(o: MsgpackConstantHistoricBlockData): ConstantHistoricBlockData { if (o.private_data_tree_root === undefined) { - throw new Error('Expected private_data_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected private_data_tree_root in ConstantHistoricBlockData deserialization'); } if (o.nullifier_tree_root === undefined) { - throw new Error('Expected nullifier_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected nullifier_tree_root in ConstantHistoricBlockData deserialization'); } if (o.contract_tree_root === undefined) { - throw new Error('Expected contract_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected contract_tree_root in ConstantHistoricBlockData deserialization'); } if (o.l1_to_l2_messages_tree_root === undefined) { - throw new Error('Expected l1_to_l2_messages_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected l1_to_l2_messages_tree_root in ConstantHistoricBlockData deserialization'); } if (o.blocks_tree_root === undefined) { - throw new Error('Expected blocks_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected blocks_tree_root in ConstantHistoricBlockData deserialization'); } if (o.private_kernel_vk_tree_root === undefined) { - throw new Error('Expected private_kernel_vk_tree_root in PrivateHistoricTreeRoots deserialization'); + throw new Error('Expected private_kernel_vk_tree_root in ConstantHistoricBlockData deserialization'); } - return new PrivateHistoricTreeRoots( + if (o.public_data_tree_root === undefined) { + throw new Error('Expected public_data_tree_root in ConstantHistoricBlockData deserialization'); + } + if (o.prev_global_variables_hash === undefined) { + throw new Error('Expected prev_global_variables_hash in ConstantHistoricBlockData deserialization'); + } + return new ConstantHistoricBlockData( Fr.fromBuffer(o.private_data_tree_root), Fr.fromBuffer(o.nullifier_tree_root), Fr.fromBuffer(o.contract_tree_root), Fr.fromBuffer(o.l1_to_l2_messages_tree_root), Fr.fromBuffer(o.blocks_tree_root), Fr.fromBuffer(o.private_kernel_vk_tree_root), + Fr.fromBuffer(o.public_data_tree_root), + Fr.fromBuffer(o.prev_global_variables_hash), ); } -export function fromPrivateHistoricTreeRoots(o: PrivateHistoricTreeRoots): MsgpackPrivateHistoricTreeRoots { +export function fromConstantHistoricBlockData(o: ConstantHistoricBlockData): MsgpackConstantHistoricBlockData { if (o.privateDataTreeRoot === undefined) { - throw new Error('Expected privateDataTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected privateDataTreeRoot in ConstantHistoricBlockData serialization'); } if (o.nullifierTreeRoot === undefined) { - throw new Error('Expected nullifierTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected nullifierTreeRoot in ConstantHistoricBlockData serialization'); } if (o.contractTreeRoot === undefined) { - throw new Error('Expected contractTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected contractTreeRoot in ConstantHistoricBlockData serialization'); } if (o.l1ToL2MessagesTreeRoot === undefined) { - throw new Error('Expected l1ToL2MessagesTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected l1ToL2MessagesTreeRoot in ConstantHistoricBlockData serialization'); } if (o.blocksTreeRoot === undefined) { - throw new Error('Expected blocksTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected blocksTreeRoot in ConstantHistoricBlockData serialization'); } if (o.privateKernelVkTreeRoot === undefined) { - throw new Error('Expected privateKernelVkTreeRoot in PrivateHistoricTreeRoots serialization'); + throw new Error('Expected privateKernelVkTreeRoot in ConstantHistoricBlockData serialization'); + } + if (o.publicDataTreeRoot === undefined) { + throw new Error('Expected publicDataTreeRoot in ConstantHistoricBlockData serialization'); + } + if (o.prevGlobalVariablesHash === undefined) { + throw new Error('Expected prevGlobalVariablesHash in ConstantHistoricBlockData serialization'); } return { private_data_tree_root: toBuffer(o.privateDataTreeRoot), @@ -693,44 +708,6 @@ export function fromPrivateHistoricTreeRoots(o: PrivateHistoricTreeRoots): Msgpa l1_to_l2_messages_tree_root: toBuffer(o.l1ToL2MessagesTreeRoot), blocks_tree_root: toBuffer(o.blocksTreeRoot), private_kernel_vk_tree_root: toBuffer(o.privateKernelVkTreeRoot), - }; -} - -interface MsgpackConstantBlockHashData { - private_historic_tree_roots: MsgpackPrivateHistoricTreeRoots; - public_data_tree_root: Buffer; - prev_global_variables_hash: Buffer; -} - -export function toConstantBlockHashData(o: MsgpackConstantBlockHashData): ConstantBlockHashData { - if (o.private_historic_tree_roots === undefined) { - throw new Error('Expected private_historic_tree_roots in ConstantBlockHashData deserialization'); - } - if (o.public_data_tree_root === undefined) { - throw new Error('Expected public_data_tree_root in ConstantBlockHashData deserialization'); - } - if (o.prev_global_variables_hash === undefined) { - throw new Error('Expected prev_global_variables_hash in ConstantBlockHashData deserialization'); - } - return new ConstantBlockHashData( - toPrivateHistoricTreeRoots(o.private_historic_tree_roots), - Fr.fromBuffer(o.public_data_tree_root), - Fr.fromBuffer(o.prev_global_variables_hash), - ); -} - -export function fromConstantBlockHashData(o: ConstantBlockHashData): MsgpackConstantBlockHashData { - if (o.privateHistoricTreeRoots === undefined) { - throw new Error('Expected privateHistoricTreeRoots in ConstantBlockHashData serialization'); - } - if (o.publicDataTreeRoot === undefined) { - throw new Error('Expected publicDataTreeRoot in ConstantBlockHashData serialization'); - } - if (o.prevGlobalVariablesHash === undefined) { - throw new Error('Expected prevGlobalVariablesHash in ConstantBlockHashData serialization'); - } - return { - private_historic_tree_roots: fromPrivateHistoricTreeRoots(o.privateHistoricTreeRoots), public_data_tree_root: toBuffer(o.publicDataTreeRoot), prev_global_variables_hash: toBuffer(o.prevGlobalVariablesHash), }; @@ -890,29 +867,29 @@ export function fromTxContext(o: TxContext): MsgpackTxContext { } interface MsgpackCombinedConstantData { - block_hash_values: MsgpackConstantBlockHashData; + block_data: MsgpackConstantHistoricBlockData; tx_context: MsgpackTxContext; } export function toCombinedConstantData(o: MsgpackCombinedConstantData): CombinedConstantData { - if (o.block_hash_values === undefined) { - throw new Error('Expected block_hash_values in CombinedConstantData deserialization'); + if (o.block_data === undefined) { + throw new Error('Expected block_data in CombinedConstantData deserialization'); } if (o.tx_context === undefined) { throw new Error('Expected tx_context in CombinedConstantData deserialization'); } - return new CombinedConstantData(toConstantBlockHashData(o.block_hash_values), toTxContext(o.tx_context)); + return new CombinedConstantData(toConstantHistoricBlockData(o.block_data), toTxContext(o.tx_context)); } export function fromCombinedConstantData(o: CombinedConstantData): MsgpackCombinedConstantData { - if (o.blockHashValues === undefined) { - throw new Error('Expected blockHashValues in CombinedConstantData serialization'); + if (o.blockData === undefined) { + throw new Error('Expected blockData in CombinedConstantData serialization'); } if (o.txContext === undefined) { throw new Error('Expected txContext in CombinedConstantData serialization'); } return { - block_hash_values: fromConstantBlockHashData(o.blockHashValues), + block_data: fromConstantHistoricBlockData(o.blockData), tx_context: fromTxContext(o.txContext), }; } diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index 165db9a656f..5ed14bf4c1a 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -33,8 +33,7 @@ export { PublicDataUpdateRequest, ReadRequestMembershipWitness, CombinedAccumulatedData, - PrivateHistoricTreeRoots, - ConstantBlockHashData, + ConstantHistoricBlockData, ContractDeploymentData, TxContext, CombinedConstantData, diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index a937733bba7..99fb1e993f3 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -11,7 +11,7 @@ export * from './kernel/private_kernel.js'; export * from './kernel/public_kernel.js'; export * from './kernel/combined_accumulated_data.js'; export * from './kernel/combined_constant_data.js'; -export * from './kernel/constant_block_hash_data.js'; +export * from './kernel/constant_historic_block_data.js'; export * from './kernel/previous_kernel_data.js'; export * from './kernel/public_inputs.js'; export * from './private_circuit_public_inputs.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts index 9d037619ea8..978ea401a7a 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_constant_data.ts @@ -2,7 +2,7 @@ import { BufferReader } from '@aztec/foundation/serialize'; import { serializeToBuffer } from '../../utils/serialize.js'; import { TxContext } from '../tx_context.js'; -import { ConstantBlockHashData } from './constant_block_hash_data.js'; +import { ConstantHistoricBlockData } from './constant_historic_block_data.js'; /** * Data that is constant/not modified by neither of the kernels. @@ -12,7 +12,7 @@ export class CombinedConstantData { /** * Roots of the trees relevant for both kernel circuits. */ - public blockHashValues: ConstantBlockHashData, + public blockData: ConstantHistoricBlockData, /** * Context of the transaction. */ @@ -20,7 +20,7 @@ export class CombinedConstantData { ) {} toBuffer() { - return serializeToBuffer(this.blockHashValues, this.txContext); + return serializeToBuffer(this.blockData, this.txContext); } /** @@ -30,10 +30,10 @@ export class CombinedConstantData { */ static fromBuffer(buffer: Buffer | BufferReader): CombinedConstantData { const reader = BufferReader.asReader(buffer); - return new CombinedConstantData(reader.readObject(ConstantBlockHashData), reader.readObject(TxContext)); + return new CombinedConstantData(reader.readObject(ConstantHistoricBlockData), reader.readObject(TxContext)); } static empty() { - return new CombinedConstantData(ConstantBlockHashData.empty(), TxContext.empty()); + return new CombinedConstantData(ConstantHistoricBlockData.empty(), TxContext.empty()); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts b/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts similarity index 55% rename from yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts rename to yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts index d88e1719864..0f090c4effd 100644 --- a/yarn-project/circuits.js/src/structs/kernel/constant_block_hash_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts @@ -5,9 +5,9 @@ import { FieldsOf } from '../../utils/jsUtils.js'; import { serializeToBuffer } from '../../utils/serialize.js'; /** - * Encapsulates the roots of all the trees relevant for the kernel circuits. + * Information about the tree roots used for both public and private kernels. */ -export class PrivateHistoricTreeRoots { +export class ConstantHistoricBlockData { constructor( /** * Root of the private data tree at the time of when this information was assembled. @@ -33,109 +33,76 @@ export class PrivateHistoricTreeRoots { * Root of the private kernel vk tree at the time of when this information was assembled. */ public privateKernelVkTreeRoot: Fr, // future enhancement + /** + * Current public state tree hash. + */ + public readonly publicDataTreeRoot: Fr, + /** + * Previous globals hash, this value is used to recalculate the block hash. + */ + public readonly prevGlobalVariablesHash: Fr, ) {} - static from(fields: FieldsOf): PrivateHistoricTreeRoots { - return new PrivateHistoricTreeRoots(...PrivateHistoricTreeRoots.getFields(fields)); - } + static from(fields: FieldsOf) { + return new ConstantHistoricBlockData(...ConstantHistoricBlockData.getFields(fields)); + } - static getFields(fields: FieldsOf) { - return [ + static getFields(fields: FieldsOf) { + return [ fields.privateDataTreeRoot, fields.nullifierTreeRoot, fields.contractTreeRoot, fields.l1ToL2MessagesTreeRoot, fields.blocksTreeRoot, fields.privateKernelVkTreeRoot, - ] as const; - } + fields.publicDataTreeRoot, + fields.prevGlobalVariablesHash + ] as const; + + } + toBuffer() { - return serializeToBuffer(...PrivateHistoricTreeRoots.getFields(this)); + return serializeToBuffer(...ConstantHistoricBlockData.getFields(this)); } toString() { return this.toBuffer().toString(); } - isEmpty() { - return ( - this.privateDataTreeRoot.isZero() && - this.nullifierTreeRoot.isZero() && - this.contractTreeRoot.isZero() && - this.l1ToL2MessagesTreeRoot.isZero() && - this.blocksTreeRoot.isZero() && - this.privateKernelVkTreeRoot.isZero() - ); - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or reader to read from. - * @returns A new instance of PrivateHistoricTreeRoots. - */ - static fromBuffer(buffer: Buffer | BufferReader): PrivateHistoricTreeRoots { + static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new PrivateHistoricTreeRoots( + return new ConstantHistoricBlockData( reader.readFr(), reader.readFr(), reader.readFr(), reader.readFr(), reader.readFr(), reader.readFr(), - ); - } - - static fromString(str: string): PrivateHistoricTreeRoots { - return PrivateHistoricTreeRoots.fromBuffer(Buffer.from(str, 'hex')); - } - - static empty() { - return new PrivateHistoricTreeRoots(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); - } -} - -/** - * Information about the tree roots used for both public and private kernels. - */ -export class ConstantBlockHashData { - constructor( - /** - * Root of the trees relevant for kernel circuits. - */ - public readonly privateHistoricTreeRoots: PrivateHistoricTreeRoots, - /** - * Current public state tree hash. - */ - public readonly publicDataTreeRoot: Fr, - /** - * Previous globals hash, this value is used to recalculate the block hash. - */ - public readonly prevGlobalVariablesHash: Fr, - ) {} - - toBuffer() { - return serializeToBuffer(this.privateHistoricTreeRoots, this.publicDataTreeRoot, this.prevGlobalVariablesHash); - } - - toString() { - return this.toBuffer().toString(); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new ConstantBlockHashData(reader.readObject(PrivateHistoricTreeRoots), reader.readFr(), reader.readFr()); + reader.readFr(), reader.readFr()); } isEmpty() { return ( - this.privateHistoricTreeRoots.isEmpty() && + this.privateDataTreeRoot.isZero() && + this.nullifierTreeRoot.isZero() && + this.contractTreeRoot.isZero() && + this.l1ToL2MessagesTreeRoot.isZero() && + this.blocksTreeRoot.isZero() && + this.privateKernelVkTreeRoot.isZero() && this.publicDataTreeRoot.isZero() && this.prevGlobalVariablesHash.isZero() ); } static empty() { - return new ConstantBlockHashData(PrivateHistoricTreeRoots.empty(), Fr.ZERO, Fr.ZERO); + return new ConstantHistoricBlockData( + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, Fr.ZERO); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index d5b88d0138a..a7c4b199286 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -17,7 +17,7 @@ import { CombinedAccumulatedData, CombinedConstantData, ConstantBaseRollupData, - ConstantBlockHashData, + ConstantHistoricBlockData, ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, @@ -63,7 +63,6 @@ import { PrivateCallData, PrivateCallStackItem, PrivateCircuitPublicInputs, - PrivateHistoricTreeRoots, PrivateKernelInputsInit, PrivateKernelInputsInner, PrivateKey, @@ -103,23 +102,14 @@ export function makeTxContext(seed: number): TxContext { return new TxContext(false, false, true, makeContractDeploymentData(seed), Fr.ZERO, Fr.ZERO); } -/** - * Creates an arbitrary private historic tree roots object with the given seed. - * @param seed - The seed to use for generating the private historic tree roots. - * @returns A private historic tree roots object. - */ -export function makePrivateHistoricTreeRoots(seed: number): PrivateHistoricTreeRoots { - return new PrivateHistoricTreeRoots(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3), fr(seed + 4), fr(seed + 5)); -} - /** * Creates an arbitrary combined historic tree roots object from the given seed. * Note: "Combined" indicates that it's the combined output of both private and public circuit flows. * @param seed - The seed to use for generating the combined historic tree roots. * @returns A combined historic tree roots object. */ -export function makeCombinedHistoricTreeRoots(seed: number): ConstantBlockHashData { - return new ConstantBlockHashData(makePrivateHistoricTreeRoots(seed), fr(seed + 6), fr(seed + 7)); +export function makeConstantHistoricBlockData(seed: number): ConstantHistoricBlockData { + return new ConstantHistoricBlockData(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3), fr(seed + 4), fr(seed + 5), fr(seed + 6), fr(seed + 7)); } /** @@ -128,7 +118,7 @@ export function makeCombinedHistoricTreeRoots(seed: number): ConstantBlockHashDa * @returns A constant data object. */ export function makeConstantData(seed = 1): CombinedConstantData { - return new CombinedConstantData(makeCombinedHistoricTreeRoots(seed), makeTxContext(seed + 4)); + return new CombinedConstantData(makeConstantHistoricBlockData(seed), makeTxContext(seed + 4)); } /** diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 21f8a0978c8..3b937053afb 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -25,7 +25,7 @@ import { L1Publisher, SoloBlockBuilder, WasmRollupCircuitSimulator, - getConstantBlockHashData, + getconstantHistoricBlockData, getL1Publisher, getVerificationKeys, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, @@ -155,7 +155,7 @@ describe('L1Publisher integration', () => { }, 100_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getConstantBlockHashData(builderDb, prevGlobals); + const historicTreeRoots = await getconstantHistoricBlockData(builderDb, prevGlobals); const tx = await makeEmptyProcessedTxFromHistoricTreeRoots( historicTreeRoots, new Fr(config.chainId), @@ -169,7 +169,7 @@ describe('L1Publisher integration', () => { const kernelOutput = KernelCircuitPublicInputs.empty(); kernelOutput.constants.txContext.chainId = fr(config.chainId); kernelOutput.constants.txContext.version = fr(config.version); - kernelOutput.constants.blockHashValues = await getConstantBlockHashData(builderDb, prevGlobals); + kernelOutput.constants.blockData = await getconstantHistoricBlockData(builderDb, prevGlobals); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 8ec0bddc19f..bbbacfe15d7 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -57,7 +57,7 @@ import { makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '../sequencer/processed_tx.js'; -import { getConstantBlockHashData } from '../sequencer/utils.js'; +import { getconstantHistoricBlockData } from '../sequencer/utils.js'; import { RollupSimulator } from '../simulator/index.js'; import { WasmRollupCircuitSimulator } from '../simulator/rollup.js'; import { SoloBlockBuilder } from './solo_block_builder.js'; @@ -121,7 +121,7 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getConstantBlockHashData(builderDb); + const historicTreeRoots = await getconstantHistoricBlockData(builderDb); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; @@ -169,7 +169,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.blockHashValues = await getConstantBlockHashData(expectsDb); + kernelOutput.constants.blockData = await getconstantHistoricBlockData(expectsDb); const tx = await makeProcessedTx( new Tx( @@ -305,7 +305,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.blockHashValues = await getConstantBlockHashData(builderDb); + kernelOutput.constants.blockData = await getconstantHistoricBlockData(builderDb); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index f752b826112..0b8e51ca339 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -183,7 +183,7 @@ export class SoloBlockBuilder implements BlockBuilder { 'nullifierTreeRoot', 'l1ToL2MessagesTreeRoot', ] as const) { - if (tx.data.constants.blockHashValues.privateHistoricTreeRoots[historicTreeRoot].isZero()) { + if (tx.data.constants.blockData[historicTreeRoot].isZero()) { throw new Error(`Empty ${historicTreeRoot} for tx: ${toFriendlyJSON(tx)}`); } } @@ -511,17 +511,17 @@ export class SoloBlockBuilder implements BlockBuilder { protected async getHistoricTreesMembershipWitnessFor(tx: ProcessedTx) { const wasm = await CircuitsWasm.get(); - const blockHashValues = tx.data.constants.blockHashValues; + const blockData = tx.data.constants.blockData; const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = - blockHashValues.privateHistoricTreeRoots; + blockData; const blockHash = computeBlockHash( wasm, - blockHashValues.prevGlobalVariablesHash, + blockData.prevGlobalVariablesHash, privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot, - blockHashValues.publicDataTreeRoot, + blockData.publicDataTreeRoot, ); return this.getMembershipWitnessFor(blockHash, MerkleTreeId.BLOCKS_TREE, HISTORIC_BLOCKS_TREE_HEIGHT); } diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index e3c48d55b42..1d03d14ed6b 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -1,4 +1,4 @@ -import { ConstantBlockHashData, Fr, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; +import { ConstantHistoricBlockData, Fr, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; import { Tx, TxHash, TxL2Logs } from '@aztec/types'; /** @@ -60,12 +60,12 @@ export async function makeProcessedTx( * @returns A processed empty tx. */ export function makeEmptyProcessedTx( - historicTreeRoots: ConstantBlockHashData, + historicTreeRoots: ConstantHistoricBlockData, chainId: Fr, version: Fr, ): Promise { const emptyKernelOutput = KernelCircuitPublicInputs.empty(); - emptyKernelOutput.constants.blockHashValues = historicTreeRoots; + emptyKernelOutput.constants.blockData = historicTreeRoots; emptyKernelOutput.constants.txContext.chainId = chainId; emptyKernelOutput.constants.txContext.version = version; const emptyProof = makeEmptyProof(); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index ae974b72b6e..2262f57cbfc 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -4,7 +4,7 @@ import { AztecAddress, CallContext, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, EthAddress, Fr, FunctionData, @@ -90,7 +90,7 @@ describe('public_processor', () => { publicProver, contractDataSource, GlobalVariables.empty(), - ConstantBlockHashData.empty(), + ConstantHistoricBlockData.empty(), ); }); @@ -136,7 +136,7 @@ describe('public_processor', () => { publicProver, contractDataSource, GlobalVariables.empty(), - ConstantBlockHashData.empty(), + ConstantHistoricBlockData.empty(), ); }); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 0d1266fd7a7..e01459b5b14 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -2,7 +2,7 @@ import { PublicExecution, PublicExecutionResult, PublicExecutor, isPublicExecuti import { AztecAddress, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, ContractStorageRead, ContractStorageUpdateRequest, Fr, @@ -39,7 +39,7 @@ import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { getPublicExecutor } from '../simulator/public_executor.js'; import { WasmPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; import { ProcessedTx, makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js'; -import { getConstantBlockHashData } from './utils.js'; +import { getconstantHistoricBlockData } from './utils.js'; /** * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source. @@ -61,7 +61,7 @@ export class PublicProcessorFactory { prevGlobalVariables: GlobalVariables, globalVariables: GlobalVariables, ): Promise { - const blockHashData = await getConstantBlockHashData(this.merkleTree, prevGlobalVariables); + const blockHashData = await getconstantHistoricBlockData(this.merkleTree, prevGlobalVariables); return new PublicProcessor( this.merkleTree, getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource, blockHashData), @@ -86,7 +86,7 @@ export class PublicProcessor { protected publicProver: PublicProver, protected contractDataSource: ContractDataSource, protected globalVariables: GlobalVariables, - protected blockHashData: ConstantBlockHashData, + protected blockHashData: ConstantHistoricBlockData, private log = createDebugLogger('aztec:sequencer:public-processor'), ) {} diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 5ad1b528c57..770c7a22acc 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -1,5 +1,5 @@ import { - ConstantBlockHashData, + ConstantHistoricBlockData, Fr, GlobalVariables, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, @@ -57,7 +57,7 @@ describe('sequencer', () => { publicProcessor = mock({ process: async txs => [await Promise.all(txs.map(tx => makeProcessedTx(tx))), []], - makeEmptyProcessedTx: () => makeEmptyProcessedTx(ConstantBlockHashData.empty(), chainId, version), + makeEmptyProcessedTx: () => makeEmptyProcessedTx(ConstantHistoricBlockData.empty(), chainId, version), }); publicProcessorFactory = mock({ diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index d27d5626d07..17f102466ee 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -1,11 +1,11 @@ -import { CircuitsWasm, ConstantBlockHashData, Fr, GlobalVariables, PrivateHistoricTreeRoots } from '@aztec/circuits.js'; +import { CircuitsWasm, ConstantHistoricBlockData, Fr, GlobalVariables } from '@aztec/circuits.js'; import { computeGlobalsHash } from '@aztec/circuits.js/abis'; import { MerkleTreeOperations } from '@aztec/world-state'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getConstantBlockHashData( +export async function getconstantHistoricBlockData( db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty(), ) { @@ -13,15 +13,13 @@ export async function getConstantBlockHashData( const prevGlobalsHash = computeGlobalsHash(wasm, prevBlockGlobalVariables); const roots = db.getTreeRoots(); - return new ConstantBlockHashData( - new PrivateHistoricTreeRoots( + return new ConstantHistoricBlockData( Fr.fromBuffer(roots.privateDataTreeRoot), Fr.fromBuffer(roots.nullifierTreeRoot), Fr.fromBuffer(roots.contractDataTreeRoot), Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), Fr.fromBuffer(roots.blocksTreeRoot), Fr.ZERO, - ), Fr.fromBuffer(roots.publicDataTreeRoot), prevGlobalsHash, ); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index c1ae5f284dc..0b5d23f97df 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -9,10 +9,9 @@ import { import { AztecAddress, CircuitsWasm, - ConstantBlockHashData, + ConstantHistoricBlockData, EthAddress, Fr, - PrivateHistoricTreeRoots, } from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { ContractDataSource, L1ToL2MessageSource, MerkleTreeId } from '@aztec/types'; @@ -28,7 +27,7 @@ export function getPublicExecutor( merkleTree: MerkleTreeOperations, contractDataSource: ContractDataSource, l1toL2MessageSource: L1ToL2MessageSource, - blockHashData: ConstantBlockHashData, + blockHashData: ConstantHistoricBlockData, ) { return new PublicExecutor( new WorldStatePublicDB(merkleTree), @@ -119,16 +118,21 @@ export class WorldStateDB implements CommitmentsDB { }; } - public getTreeRoots(): PrivateHistoricTreeRoots { + public getHistoricBlockData(): ConstantHistoricBlockData { const roots = this.db.getTreeRoots(); - return PrivateHistoricTreeRoots.from({ + return ConstantHistoricBlockData.from({ privateKernelVkTreeRoot: Fr.ZERO, + + // TODO: work out how to get the previous globals hash in here + prevGlobalVariablesHash: Fr.ZERO, + privateDataTreeRoot: Fr.fromBuffer(roots.privateDataTreeRoot), contractTreeRoot: Fr.fromBuffer(roots.contractDataTreeRoot), nullifierTreeRoot: Fr.fromBuffer(roots.nullifierTreeRoot), l1ToL2MessagesTreeRoot: Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), blocksTreeRoot: Fr.fromBuffer(roots.blocksTreeRoot), + publicDataTreeRoot: Fr.fromBuffer(roots.publicDataTreeRoot), }); } } From 4a0f15a4499af80c953fcf7cf584823ed74b449c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 18:57:42 +0000 Subject: [PATCH 51/58] cleanup --- .../src/client/client_execution_context.ts | 10 ++---- .../acir-simulator/src/public/executor.ts | 10 ++---- .../aztec-rpc/src/kernel_oracle/index.ts | 12 +++---- .../src/abis/ecdsa_account_contract.json | 4 +-- .../schnorr_multi_key_account_contract.json | 2 +- .../schnorr_single_key_account_contract.json | 2 +- .../kernel/constant_historic_block_data.ts | 33 ++++++++----------- .../circuits.js/src/tests/factories.ts | 11 ++++++- .../src/integration_l1_publisher.test.ts | 2 +- .../src/block_builder/solo_block_builder.ts | 3 +- .../sequencer-client/src/sequencer/utils.ts | 12 +++---- .../src/simulator/public_executor.ts | 8 +---- 12 files changed, 46 insertions(+), 63 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 40d3e11c278..708b82b7ade 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -198,10 +198,7 @@ export class ClientTxExecutionContext { */ public async getL1ToL2Message(msgKey: Fr): Promise { const messageInputs = await this.db.getL1ToL2Message(msgKey); - return toAcvmL1ToL2MessageLoadOracleInputs( - messageInputs, - this.constantHistoricBlockData.l1ToL2MessagesTreeRoot, - ); + return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.constantHistoricBlockData.l1ToL2MessagesTreeRoot); } /** @@ -214,10 +211,7 @@ export class ClientTxExecutionContext { const commitmentInputs = await this.db.getCommitmentOracle(contractAddress, fromACVMField(commitment)); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1029): support pending commitments here this.readRequestPartialWitnesses.push(ReadRequestMembershipWitness.empty(commitmentInputs.index)); - return toAcvmCommitmentLoadOracleInputs( - commitmentInputs, - this.constantHistoricBlockData.privateDataTreeRoot, - ); + return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.constantHistoricBlockData.privateDataTreeRoot); } /** diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index c8157a2ea1d..3fcb3d71f11 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -87,20 +87,14 @@ export class PublicExecutor { }, getL1ToL2Message: async ([msgKey]) => { const messageInputs = await this.commitmentsDb.getL1ToL2Message(fromACVMField(msgKey)); - return toAcvmL1ToL2MessageLoadOracleInputs( - messageInputs, - this.blockHashData.l1ToL2MessagesTreeRoot, - ); + return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.blockHashData.l1ToL2MessagesTreeRoot); }, // l1 to l2 messages in public contexts TODO: https://github.com/AztecProtocol/aztec-packages/issues/616 getCommitment: async ([commitment]) => { const commitmentInputs = await this.commitmentsDb.getCommitmentOracle( execution.contractAddress, fromACVMField(commitment), ); - return toAcvmCommitmentLoadOracleInputs( - commitmentInputs, - this.blockHashData.privateDataTreeRoot, - ); + return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.blockHashData.privateDataTreeRoot); }, storageRead: async ([slot], [numberOfElements]) => { const startStorageSlot = fromACVMField(slot); diff --git a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts index d073f4ff18a..e0d27315aaa 100644 --- a/yarn-project/aztec-rpc/src/kernel_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/kernel_oracle/index.ts @@ -54,12 +54,12 @@ export class KernelOracle implements ProvingDataOracle { const treeRoots = await this.node.getTreeRoots(); return new ConstantHistoricBlockData( - treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], - treeRoots[MerkleTreeId.NULLIFIER_TREE], - treeRoots[MerkleTreeId.CONTRACT_TREE], - treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], - treeRoots[MerkleTreeId.BLOCKS_TREE], - Fr.ZERO, + treeRoots[MerkleTreeId.PRIVATE_DATA_TREE], + treeRoots[MerkleTreeId.NULLIFIER_TREE], + treeRoots[MerkleTreeId.CONTRACT_TREE], + treeRoots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], + treeRoots[MerkleTreeId.BLOCKS_TREE], + Fr.ZERO, treeRoots[MerkleTreeId.PUBLIC_DATA_TREE], prevBlockGlobalVariablesHash, ); diff --git a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json index 84ec480d5d5..40ba33f0262 100644 --- a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json @@ -84,7 +84,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "H4sIAAAAAAAA/+1dZ3QU1xV+kkB0jFNsEEIIIYQQQrzRrpBEFb13SBx3BCuMC9hE2MhxnLj33ntJ707vieP03nuO4ziO4ziO4ziO4+RHTuaKO/B0s5J2dr/ZnXuy75zR3bujc/f7vjflzcyd+zaXGGNoYVPqL0P4c+APFX658I/xl+GOf6zwxwt/gvArhD9R+JXCnyT8KuFPFn618KcIv0b4U4VfK/xpwq8T/nTh1wt/hvAbhD9T+I3CnyX8JuHPFr4Vvif8ZuEnhJ8Ufgv7tF0Y1pcabQfU9+O5jyu4Lyu5z6q4b6q5D2pY61rWtI61q2eNGliLRubcxNwsc2hmrEnGFOCbI/C2Cr9N+O3Cnyv8ecKfL/wFwl8o/EXC7xD+YuEvEf5S4S8T/nLhrxD+SuGvEv5q4a8R/lrhrxP+euFvEP5G4W8S/mbhbxH+VuFvE/52c2R7pO+qzaFG20Er93c79+s87r8F3E+LuD8Ws+5LWd/lrONK1ms167KW+a9nnhuZz2bGvZXxbWcs5abv/vEfc2gfITue7QS2FWwnsq1kO4ltFdvJbKvZTmFbw3Yq21q209jWsZ3Otp7tDLYNbGeybWQ7i20T29lsLVuPbTPbBNsk2xYn3uv85fVptJnD/9PKto1tO9u5bOexnc92AduFbBex7WC7mO0StkvZLmO7nO0KtivZrmK7mu0atmvZrmO7nu0GthvZbmK7me0WtlvZbmO73dHmOH95g+nb+NTcy4daws5JJlOtzSkv4e2wze2dbS022dI5p81r81raWnY1tyUSqbZkW2t7Z3urbfeSiZTX1dKe6LKH2vFOLJtjixLnCUpwnqgE50lKcJ6sBOcpSnCeqgTnDiU4O5Xg3KkE5y4lOFNKcHYpwbkbiDMYS47jeDTGpDHVcWyPZ3sC2xPZnsT2ZLansD2V7Q62nWx3st3FNsW2i+1uc2Qsd5q/7DF9G1rD03EaeoGGAcbTmQt9d4a/nCm4lAkuFMPm0I6RXHKIdixQ48dNNPtTGv1sLqzHp8OZZbQJQP1+m1/9bLasK/rDmUW0iUD9nsi/fjYb1pUD4QwZbRJQv98VRj8blnXVYDhDRJsM1O/Jwulnw7CuzgRnhtGmAPX7fWH1s5myrskUZwbRpgL1e6rw+tlMWNeGwTlItGlA/f4QD/3sYKzrwuIcINp0oH5Px0c/OxDr+mxw9hNtBlC/P8ZLP9sf64ZscaaJNhOo3zPx08+mY92YC04RbRZQvz/FUz8rWTflitOJNhuo37Px1c/2YY3AydE8oH5/jrd+vXTpTzMKpx8tAdTvufjrR81LAmM9DtTvL0r0A94n8p4A6ve8Ev2A9zm8J4H6/VWJfsDrdO8poH4vKNEPeJ3pPQ3U729K9ANeJ3nPAPV7UYl+wHG+9yxQv78r0Q84TvWeA+r3khL9gOMs73mgfv9Qoh9wnOC9ANTvZSX6Ac9z3otA/f6pRD/gcdp7CajfK0r0Ax5nvJeB+v1LiX7A/cR7Bajfv/OkX644zwLqB9xmvHzpZ3PMv5pjcPlXrcB+HV+S1/03a9ZtBpd/1Q7Ub0JJ3o9/WbGea3D5V/OA+lXkXz+bDev5Bpd/tQCo38TC6GfDsl5ocPlXi4D6VRZOPxuGdYfJAGeG0RYD9ZtUWP1spqyXmAxxZhBtKVC/qsLrZzNhvcyEwDlItOVA/SbHQz87GOsVJiTOAaKtBOpXHR/97ECsV5kscPYTbTVQvynx0s/2x3qNyRJnmmhrgfrVxE8/m471OpMDThFtPVC/qfHUz0rWG0yOOJ1oG4H61cZXP+uy3mQAODnaZqB+0+Ktnw1YbzEgnH60rUD96uKvHzVvGzCWe88pV/2mK9EPeJ/IqwDqV69EP+B9Dq8SqN8MJfoBr9O9KqB+DUr0A15netVA/WYq0Q94neTVAPVrVKIfcJzv1QL1m6VEP+A41asD6tekRD/gOMurB+o3W4l+wHGC1wDUzyrRD3ie8xqB+nlK9AMep70moH7NSvQDHmc8C9QvoUQ/4H7iNQP1S+ZJv1xx7gX2BXCb8ZD6BTWygrrXlHPm1rfda/rWdC1lS22fv5xt+jZ0PbBzgH0QcC3leOcwl30Op/3+8kbelspM/60DiGmoiD35f38jlnXI+KvY1fdyvo5V3SyxKjb1qNKsjkWdp37+peD1kwb4t4LWJRrkXwtW78cO3gpSR8dm1vJen8Zm3vJa98WGa3mrp2LDt7zUKbHZtcjrf9jsW6R1NWxuDVmv4vB1hRzP2tya1xIBRvR4Mar3Jvir2L2P4Hwdqzx/sSo2+fNpVsciL72ffyl4vvcA/1bQPOpB/rVg+cl28FaQvF+bWct7Pq3NvOU1T9WGa3nL/7ThW17yKm12LfJ8RZt9izQP0ObWkPl1kY0XtyvAWBoBxihw7gfiLHFwdjufR7MdYQ7NOUqt1PmuTHAb4awPWrnzuQODt6Ucr6el+9bDHR5G8B3L649mf+++7j1dPUv3p3Z0p3Zt2NedckUMboKXpQlU4nzv3iwf4vx4uVjvChusG2aOiHC4dRiIGl5ZuuAGvxV3m2i24gNphHW3zDJHTDQnI35H6jjWRNhxUXXSgQjinmtwj9ai4n0uvo8iPS0gNc3XQQB5yi1xMAY7+Xn+ctBfehwOY9jm6ZRlozpllTs8guaesmj9EOzvJtxTv3H0Nml0M87v0+kzGFLsTnVvOtB55p6da1M96fqsLE1cd+ghz7BuPwbrIj1DBs/f3Y2MnrsfZNvD9ih/Od9f3iRwoPM7gDuRdz4Q1wU4XHk7ICExu3jf7HwujkpyjHkBC4qOe6GJ96iEeF+I76NIRyVITWnjdc/QUWGO6kYAuN88jRqgcZ6nBOdBgz2xFJPtisl2mbRisl24aNUmg/20mGx3uBWT7cJFKybbhYtWTLYLGS33WMVkuywbhykm2/Witlm3YrJduFZMtgsXrZhsFy5aMdkuXLRisl24aMVku3DRisl24aIVk+3ihzGqJ/+l/Pkt/vJWc6RVsqWnxcP4s5tjFTxXcHOx0j1p/n9Ihhvl8DCCb5AMN4791Fl7upfv3bm/5+zu1K51+3a7DxKHp+Ge7qEntSHO56FpdKO4st9o3Ugs/+YRgnfw227rcD6PdLCMwmLp3fdGO78V4Brl2GC9q/VoLI7ehIdRgn/gj47ud3v5jxmE/5g0OMbkkb+bTST3G/c4EKyLNDPFjYmuYHGRwZ9UosB5sRKclyjBeakSnJcpwXm5EpxXKMF5pRKcVynBebUSnNcowXmtEpzXKcF5vRKcN2BwdiWbk5HivFGJnjcpwXmzEpy3KMF5qxKctynBebsSnHcowXmnEpx3KcF5txKc9yjBea8SnPcpwXm/EpwPKMH5oBKcDynB+XBEOEsFTptb672pjuL8NiWcS4Gc366EcxmQ8zuUcB4C5PxOJZyHAjm/SwnnciDndyvhfBqQ83uUcL4IyPm9SjhfDOT8PiWcLwFyfr8SzpcCOX9ACefLgJw/qITz5UDOH1LC+Qog50eUcL4SyPnDSjjvB3L+iBLOVwE5f1QJ56uBnD+mhPM1QM4fV8L5DCDnTyjhfC2Q8yeVcL4OyPlTSjhfD+T8aSWcbwBy/owSzjcCOX9WCeebgJw/p4TzzUDOn1fC+RYg5y8o4XwrkPMXlXC+Dcj5USWcbwdy/pISzncAOT+mhPOdQM5fVsL5LiDnryjhfDeQ81eVcL4HyPlrSjjfC+T8dSWc7wNy/oYSzvcDOX9TCecHgJy/pYTzg0DO31bC+SEg5+8o4fwwkPN3lXAeBuT8PSWchwM5f18J5xFAzj9QwnkkkPMPlXAeBeT8IyWcRwM5/1gJ5zFAzj9RwnkskPNPlXA+Csj5Z0o4jwNy/rkSzkcDOf9CCedXATn/UgnnVwM5/0oJ59cAOf9aCefXAjn/JgLO29kGhSrp3Sh6VyiYzpGuC+k6ia4baBwdFPijcQedh+m8RMdpOm7RfkzbNfUz8aYJe2iiHZoghya2oQlpaCIZKnxJE7fQhCtU9L3aX6b4S42/0EQgNIEHTbxBE2bQRBc0QQVNLEETQtBEDjQBA02cQBMe0EQFRIYKzVFBfyrETwX0qUA9FYCnwu1UcJ0KpVOBcypMTgXFqRA4FfAOCm8v9pcl/kKFpakgNBVypgLMVDiZCh5ToWIqMEyFgamgLxXipQK6VPh2k79QoVkqEEuFXbexrnNZW3oXkN6No3fF6N0pepeI3q2hd03o3Qt6F4Fy8ylXnXK3KZf5EX+hXFfK/aRcSMoNpFw5yh2jXCrKLaJcG8o9oVwMyk2gZ/X07Jqe5T7qL/Ss7zF/oWdB9GyEnhXQvXO6l0z3VuleI917o3tRdG+G7lXQtTtdy9K1HV3r0NifxsI0NqSxEo0d6FxK5xY61tKxh/ZF2jb/C3iTESQe8AAA", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" }, { @@ -152,7 +152,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json index 9fa64651b73..2c7efe755ec 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json @@ -140,7 +140,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "H4sIAAAAAAAA/+2dB5hbxfHAn6TruuLrdy7nc++2dMV35yrb2MaAccMYYxs3zmAwNsWmE3oLCT0EQgsQeu+9Qwgh9JLQW3pCOgmEAP/d8ww32ns+MJqVZ/967/vmm30rafc3s7uz+6R9T5dkeV65En2ElISVZEEaz7ON8xxIZ2/+mAcf96qUVCupUVJLPoev91TSS0lvJX3g9TB5vU5JXyX1SvqR+gYoySPnA43zQcb5YON8iHE+1DgfZpwPN85HGOcjjfNRxvlo43yMcR4zzuPGeYNx3micNxnnzcb5WOO8xThvNc7bjPNxxvl443yCcT7ROJ9knE82zhPG+RTjfKpxPs043844n26czzDOZxrn2xvns4zzHYzzHY3znYzz2cb5zsb5HON8rnE+zzifb5wvMM53Mc4XGue7GueLjPPdjPPFxvnuxvkS43ypcb7MON/DOF9unK8wzlca56vgXMeHiLe5v+hDxwE99vV412Ncj+uh3ubxq8esHqd6bOrxqMegHnd6rOnxpceUHkd67OjxoseIHhd6LOj+r/u87ue6b+v+rPvwZKhb90/dJ3U/1H1P9zfdx3S/0n1J9x/dZ3Q/0X1D9wfdB+ZAW8+DNl0AbbcQ2mgRtMVi8PkS8O0y8OFy8NVK8In2j4699eAPHW+/8DbHXK1rQNeC7gm6F+jeoPuArgPdF3Q96H6g+4MeAHog6EGgB4MeAnoo6GGgh4MeAXok6FGgR4MeAzoGOg66AXQj6CbQzaS81Ur29PHNWHhPC+hW0G2gx4EeD3oC6ImgJ4GeDDoBegroqaCngd4O9HTQM0DPBL096FmgdwC9I+idQM8GvTPoOaDngp4Hej7oBaB3Ab2Q+KZdyRov+QiBToBujI1tampvaWiPN8ZXxhraVrU2x5qaV41tjbfGm1ub92xobWxsb21qbWlb1dYSa4s3NbbH1zS3Na6JbT72ImXFUjxscu7tCOdaRzj3cYRzX0c41znCuZ8jnOsd4dzgCOf+jnAe4AjngY5wHuQI50ZHODc5wnmwI5yHOMJ5qCOchzFymtdk+ppXX5ssAr0b6MWgdwe9BPRS0MtA7wF6OegVoFeCXgV6L9B7g14Leh/Q+4JeB3o/0OtBbwC9P+gDQB8I+iDQG0FvAn0w6ENAHwr6MK/zmuxwJUd4yQd3Gx7pudHXjnKE8zuOcB7tCOcxjnAe6wjncY5wHu8I5wmOcJ7oCOdJjnCe7AjnKR7/Gq0HlKe/T9drlXbQh4M+EvRRoL8D+mjQx4A+FvRxoI8HfQLoE0GfBPpk0Kd4nWukU5V819v820+et+UjweODuL2ym2yW3WCx7EaLZTdZLLvZYtljLZbdkkPKPA3090B/H/TpoM8AfSb5zAmFm3U+iD5yvc48HEc5JA9fzyZ5+HoWycPXIyQPXw+TPHw9RPLwdc+oXx8J0LEUjxyva4yNpXhom8uIHZ6PvSEfv4R9/IevZ/v4j7YHvo7tUqwk6lO3/kwBr73xkJd8JEga66IsEUEsWYJYsgWx5AhiyRXEkieIJV8QS2gbs9CYioceTy9HOl/HdSqNw6WQpnEYYzeNw+WkTMyrIDZjXiWk6fyJjD1IHvqulOTBNJw0dxRBupzkFUO6guSVQLrSh4W2DX4mATqW2tHRNrSeBDnHugoIQ6UAlnxBLHmCWHIFseQIYskWxJIliCUiiCVssGxp7WuDjx4Jkq7wYYkIYskSxJItiCVHEEuuIJY8QSz5glgKBLFEBbEUCmIpEsRSLIilRBCL7XXE1rDYvmb6Oha/61l6zUmve8sNfnoNW0jy8FqziOThNWkxyauCdAnJC/vw4VqGXpvimoJew+LcTq91cY6l18Q412H9+nMfk+v3Gsin1++1kKbX7z0hTa/fe5EyMa83pOn1ex9I0+v3OkjnkTxkrCF5aEstyUObe5I89E0vkoc+7E3y0Nd9SF41pOt8+Gifxc8kQMdSOzr6LK0nQc6xLnqdXyeApVIQS4kglmJBLEWCWAoFsUQFsRQIYskXxJIniCVXEEuOIJZsQSxZglgigljCPiy9eVlidG3nESZ6JEiarg17MbPoMntasK/XVtjXk9hXa8E+5jLjuswaC5z1vGW26Hbo633zdqgn7dCP2T5dRn9SF3JhPVHyehXh6M/cdiFSJ5aL55Tvm7L2cIi11CHWModYyx1irXCItXobs/LXG++IybRefXQXkynLAFaWzXPOQOYydRmDCD/aiuxR8vpAYtsgXo6O9h3gJfsUzweRegP7WesN7PcC+wP7A/sD+wP7A/sD+wP7A/sD+wP7A/sD+wP7A/sD+wP7A/sD+yXYv6X7cpi/Z+92j+0AH5aIIJYsQSzZglhyBLHkCmLJE8SSL4ilQBBLVBBLoSCWIkEsxYJYSgSx9BDEUiqIpUwQS7kglgpBLJWCWKoEsVQLYqkRxFIriKWnIJZeglh6C2LpI4ilThBLX0Es9YJY+gli6S+IZaAgltA2ZtnSvd/4epjk4fdqEZI3GNL0/uchkKb3Pw8ldmLeMEjT+5+HQ5re/zyCpFGPhDS9X3kUpOm9zqMhTe+THgNpej81Pgi5L8nDh+L2I3noD+o/9Mcgkof+GEzy0B9DSB76YyjJQ38MI3noj+EkD/1B/YPfQ4wkedjfRpE8vC4fTfLw+ngMycPr1BjJw+tF9I+2Kzur83V8L+07cZ9yME3HANadwPczjAFaT4KcY130XvKYAJaBglj6C2LpJ4ilXhBLX0EsdYJY+ghi6S2IpZcglp6CWGoFsdQIYqkWxFIliKVSEEuFIJZyQSxlglhKBbH0EMRSIoilWBBLkSCWQkEsUUEsBYJY8gWx5AliyRXEkiOIJVsQS5YglogglrAPi409nfg9oD7wu7qBhAOZRhOOUcw+0WWM9OEYRTiw/pGEYwQvR8f/lQ334RhBOLD+4YRjGC9Hx3+bDfXhGEY4sH76/foQXo4mXcZgH44hhAPrH0w4mPf8dvxn2gAfjkGEA+sfQDgaeDk6/l+t0YejgXBg/fi+Le1FbuRl6/Y3Hz+WiCCWLEEs2YJYcgSx5ApiyRPEki+IpUAQS1QQS6EgliJBLMWCWEoEsfQQxFIqiKVMEEu5IJYKQSyVgliqBLFUC2KpEcRSK4ilpyCWXoJYegti6SOIpU4QS19BLPWCWPoJYukviGWAIJaBglgGCWIZLIhliCCWoYJYhgliGS6IZYQglpGCWEYJYhktiGWMIJaYIJa4IJYGQSyhbcyypfuX8HV6L0sTpOk9L82QpvfLjIU0vdemBdL0Pp1WSA8meW2QpvcHhX2Y8Xe3JpKHv381kzz8HWosycPfg1pIHv4u00ry8PcRZNJlDYh2vo48YfKZcZCm93iNhzS9x2sCKRPzJkKa3uM1CdL0Hi/kof5A7nEkD+0bT/LQDxNIHvprIslDv07yYaF9Fj+TAB1L7ejos7SeBDnHuuj9RpMEsDQIYokLYokJYhkjiGW0IJZRglhGCmIZIYhluCCWYYJYhgpiGSKIZbAglkGCWAYKYhkgiKW/IJZ+gljqBbH0FcRSJ4iljyCW3oJYegli6SmIpVYQS40glmpBLFWCWCoFsVQIYikXxFImiKVUEEsPQSwlgliKBbEUCWIpFMQSFcRSIIglXxBLniCWXEEsOYJYsgWxZAliiQhiCRss9LfANpKHv9nR3yjxtz36Wyb+Bkh/88TfCulvo5MhTX9DDRt89LdW+pshtiX9bRH7Gv0NEscC/a0SxyrWr8+39Js48iRAx1I7uv1NnP6Oa75P29ZAfvvN8/kMxmb62y/OHfS33ygpE/PovVWYh2sD+tsv1kef70nrQ431FZA8rC9K8rC+QpKH9RX5sNC2wc8kQMdSOzrahtaTIOeFxJ6QDx++TtsD7fy69kC/0fag90ZiHq4b/dqD+g/ro37urj1ou2F9tH2xPlp/DnlPAnQsxYP6gtaPzF/nW/QB9S22EbWV3i+HeSXENsyj9aHG+qgfsT7qb6yPtgvWR/uN6Vva9pRJfxav7RKgY6kdDbouvEbDo7v4VEoY8ZqX3mNXzsvXMR7LDBY8x7qihKHYHktLdAt14xEmdZdZ8INn+AGPMh+WiCCWLEEs2YJYcgSx5ApiyRPEki+IpUAQS1QQS6EgliJBLMWCWEoEsfQQxFIqiCW0jVn8rnnpOpOuxXH9RdfgFYZNOg9/O6NrcPxtj67B8bfHEpIX9uHDdVU5ycP1TQXJw3VGJcnD+b6K5OG8i/Xrz82LdmUN+7BW+dhE2xDrToCOpXZ0tCGtJ0HOsS56bVwlgKVUEEsPQSwlgliKBbEUCWIpFMQSFcRSIIglXxBLniCWXEEsOYJYsgWxZAliiQhiCfuwVPCydNyWhGtIfeCaroJwIBN9PhbzujwWMjjqSb30GWE1zG2hy6j1sb+G2I/115I8TNNrOO620TG9p9EeeqyclWXPH7rMOmY7dNvifmB9HE3sqiP+s1FvH6PeGqNe/R76XKajCSt+NkLec3FWZztcAGm6Dxz7g267vkZd9FoOX8PfU+ot2I51eFB+T5JG2+uJ7fXkM+XEdnzP5cT2vtHOz/XnZe/4Wb4flBUm3P0JK/Nzyxt0GfR50Fh+P5I3mKQxTuBn6P09gwmnjXhFObD+GpI31IdzMOEcYrxPcw7j5ezof5QjROrFuiLkPbeQvlVH+paNdh7mdfUffV7RCN46G/W4H+4lH919D0WfszKSlyVmaw0xivCjrcgeJa/T51pyP/M/5CU/8z9BzukzWgL7Wet1yv4t/U7OPM66/Z55pA9LRBBLliCWbEEsOYJYcgWx5AliyRfEUiCIJSqIpVAQS5EglmJBLCWCWHoIYikVxFImiKVcEEuFIJZKQSxVgliqBbHUCGKpFcTSUxBLL0EsvQWx9BHEUieIpa8glnpBLP0EsfQXxDJAEMtAQSyDBLEMFsQyRBDLUEEswwSxDBfEMkIQS2gbs2xpfzW+Xk3y8Ht7+vxsfGbsMJIX9qkDv1MfRfLwu20sQ3+/vGe0a31hn/pG+XDZ9iWtJ0HOsS66z3mUAJYRgliGC2IZJohlqCCWIYJYBgtiGSSIZaAglgGCWPoLYukniKVeEEtfQSx1glj6CGLpLYillyCWnoJYagWx1AhiqRbEUiWIpVIQS4UglnJBLGWCWEoFsfQQxFIiiKVYEEuRIJZCQSxRQSwFgljyBbHkCWLJFcSSI4glWxBLliCWiCCWsMES7O3/epZgb78/S7C3358l2NvvzxLs7fdnKRTEUiSIJdjb788S7O33Zwn29vuzBHv7/VmCvf3+LMHefn+WYG+/P0uwt9+fJdjb789SL4ilnyCW/oJYgr39/izB3n5/lmBvvz9LsLffn2WEIBbb38tvDctoQSyhbczydfc8jCZ5YeOz+nvyS8g9CvgfdWHyGfwvO/ofVGMhTf+DqoWUiXn4H3o5JA//ay/Xh5X+R94YSNP/0otBmv7nXhzS9L/5GiBN/8MP/xuvzYeFtiF+JgE6ltrR0Ya0ngQ5x7rovRZtAlhGC2IZJYhlhCCW4YJYhgliGSqIZYgglsGCWAYJYhkoiGWAIJb+glj6CWKpF8TSVxBLnSCWPoJYegti6SWIpacgllpBLDWCWKoFsVQJYqkUxFIhiKVcEEuZIJZSQSw9BLGUCGIpFsRSJIilUBBLVBBLgSCWfEEseYJYcgWx5AhiyRbEkiWIJSKIJezD0sLL0kB/o/EIEz0SJE1/YxlrMGu+Zgu+Gmuw4DnWFSUMIy2yRH3qtlBPQ75hsz66axP6+xj+fjaW8I1j9kOI1IPl4jnWRX01xiJL1KduC/U05Bs266O7NsH69efGQ7qJ8E1g9kOI1IPl4jnWRX0Vs8gS9anbQj0N+YbN+uiuTbB+/bmJkB5P+CYx+yFE6sFy8Rzror6KW2SJ+tRtoZ6GfMNmfXTXJli//txkSE8kfAlmP4RIPVjuZKMO6qsGiyxRn7ot1NNAfYtHd22Caf25KZCeTPimMvshROrBcvEc66K+arTIEt1C3XiESd1TLPjBM/yAxxQflogglixBLNmCWHIEseQKYskTxJIviKVAEEtUEEuhIJYiQSzFglhKBLH0EMRSKoilTBBLuSCWCkEslYJYqgSxVAtiqRHEUiuIpacgll6CWHoLYukjiKVOEEtfQSz1glj6CWLpL4hlgCCWgYJYBgliGSyIZYgglqGCWIYJYhkuiGWEIJaRglhGCWIZLYhljCCWmCCWuCCWBkEsjYJYmgSxNAtiGSuIpUUQS6sgljZBLOMEsYwXxDJBEMtEQSyTBLFMFsSSEMQS2sYsW3q+DL5On7EyFdL0+SzTIE2f7bIdpMeTvOmQnkjyZkB6MsmbCekykrc9pAeRvFmQDpO8sI9tuI9mKsnD/SzTSB7uK9mO5OH+jukkD/dZzCB5uN9hJsnDfQfbkzz8/R/ZdZ0fRbvaRPsEfj4BOpba0dEnaD0Jco510efVzBLAkhDEMlkQyyRBLBMFsUwQxDJeEMs4QSxtglhaBbG0CGIZK4ilWRBLkyCWRkEsDYJY4oJYYoJYxghiGS2IZZQglpGCWEYIYhkuiGWYIJahgliGCGIZLIhlkCCWgYJYBghi6S+IpZ8glnpBLH0FsdQJYukjiKW3IJZeglh6CmKpFcRSI4ilWhBLlSCWSkEsFYJYygWxlAliKRXE0kMQS4kglmJBLEWCWAoFsUQFsRQIYskXxJIniCVXEEuOIJZsQSxZglgigljCBksBeb0HycN9NvR5ijMgPZbk4b6dJpJn7k3SebgPaCLJmwpp3O8RPCfo61mC5wT5s+QIYgmeE+TPki+IJXhOkD9L8Jwgf5bgOUH+LMFzgvxZgucE+bMEzwnyZwmeE+TPEjwnyJ8leE6QP0vwnCB/luA5Qf4s9YJY+gli6S+IJXhOkD9L8Jwgf5bgOUH+LMMEsQwXxDJCEEvwnCB/luA5Qf4swXOC/FmC5wT5swTPCfJnCZ4T5M8SPCfInyV4TpA/S/CcIH+W4DlB/iwJQSxTBbFME8SynSCW6YJYZghimSmIZXtBLLMEsYS2MUu+1/1zyOiztXaA9AyStyOk6bO6doI0fabXbEjTZ3/tDOmpJC/sw4d77XYgebjnbUeSh3vPdiJ5uAdsNsnDvVhYv/7c5MLO1+dCfph8Zh6kIyRvPqSzSN4CUibm7QLpHJK3ENK5JG9XSOeRPGScS/LQlnkkD22eT/LQNwtIHvpwF5KHvl5I8uZAelcfPtpn8TMJ0LHUjo4+S+tJkHOsiz4nbVcBLLMEsWwviGWmIJYZglimC2LZThDLNEEsUwWxJASxTBbEMkkQy0RBLBMEsYwXxDJOEEubIJZWQSwtgljGCmJpFsTSJIilURBLgyCWuCCWmCCWMYJYRgtiGSWIZaQglhGCWIYLYhkmiGWoIJYhglgGC2IZJIhloCCWAYJY+gti6SeIpV4QS19BLHWCWPoIYuktiKWXIJaeglhqBbHUCGKpFsRSJYilUhBLhSCWckEsZYJYSgWx9BDEUiKIpVgQS5EglkJBLFFBLAWCWPIFseQJYskVxJIjiCVbEEuWIJaIIJawD8suvCwttE5dH16T0T2K85nrpPsiPeIHeiRIej5hmcvLEtP1LiLlJ0gdtN7deOuN03pDIFgH5kdI+jKcbMj79IH7+5BZv22ez/toeoHxmSh5fZ5lm+cSjgQ5x7p0LDiP2DrPh3sh4cbXdybcNczcuoz5hAPrp88dYu6XLXSPMR7djZG5hIW53TrGyGJSfoLUQevdndnvtF4cI1gH5kdI+g7Sb3bvTH7Vb5BZv22Rz/to2hxDUfL6Iss207GaIOdYlx4j1xJbF/lwzyfc+Ppswm1jjNCxjfXTMcLcLzvGCLVdH92Nkd0IC3O7dYyRJaT8BKmD1ruU2e+0XhwjWAfmR0j6KdJvlnYmv+o3yKzfttjnfTRtjqEoeX2xZZvpWE2Qc6xLj5EHiK2Lfbjp/Iev70S4bYwROraxfjpGmPtlxxihtuujuzGyO2FhbreOMbKMlJ8gddB692D2O60XxwjWgfkRkn6D9Js9OpNf9Rtk1m9b4vM+mjbHUJS8vsSyzXSsJsg51qXHyPPE1iU+3HT+w9d3JNw2xggd21g/HSPM/bJjjFDb9dHdGFlKWJjbrWOMLCflJ0gdtN4VvPXGab04RrAOzI+Q9Eek36zoTH7Vb5BZv22Zz/to2hxDUfL6Mss207GaIOdYlx4jHxBbl/lw0/kPX9+BcNsYI0sJB9ZPxwhzv+wYI9R2fXQ3RvYgLCt4WTrGyEpSfoLUQetdxVtvnNaLYwTrwPwISdMbe1d1Jr/qNytA6+613Od9NG2OoSh5fbllm1cQjgQ5x7r0GPmYjJHlPtxLCTe+PoVw2xgjdGxj/XSMrOCts2OMUNv10d0YWUFYmNutY4ysJuUnSB203j15643TenGMYB2YHyHpcjJG9uxMftVvkFl3r5U+76NpcwxFyesrLdtMx2qCnGNdeozkEVtX+nDT+Q9fn0O4bYyRFYQD68d68gkHfYa/zbiK5eI5bcsehr8ssLREferWbVcX7Uz3jdptE+qLnj5tgnkrCd9Z8COKHlv4u8Eg4CyCz+FvhPSZBQWkDMzDbkqfWUD/8wPz8Ddq+swC/A2dPrMgTNKokaGA5CFDlOQhQyHJQ4YikocMxYRpS8/VQJ4E6FhqR7fP1aC2m+/Tts0p7Gpr2MfWiI+ttM3CpEzMo/9JhXn4mVyf8qiPcgxbYqkdHT6i9SS85P9A0gd9jkOuPZaYK2XqtsnzurZhvk9egU8e9n/an3Ac0f6E48ivP9FxTD+DGj9DxzH2QTqOkYuOY2xjGkdySPkJ0LHUjgbqRzy6G7PUvgLDDznELia+jrFRYLAUGD6MEoZcayzxjvnPrLvAxw90Lw71TSEzjy6zmLlM2ufx6K4/0DkNbd2rfePOGza2HxQin8cycc9sLikjTN4X8brWneV1PbJJOoekC8nnokad2jbcU0fnR6y/hLBZiFkNdPxT++iR8LGLxgP6n4F5vHxJ8xCWi+dYV5QwROyxNEZ96i7Ygh+YY2LS3IJl6z54AFnbMse5Rv6xvPk6F8eDPo4mdtH/Y7NRb5FRb9Sol8b1HHgPsuJnI+Q9R5FrjMMgTfel0rVdiVHXlsY43WNLx2UPkkZ/0RhURtJh4zN0PzP9DzPc+50AHUvtaMw3OPTRXSyh/2FWycvS0d5VpPwEqYPWW81bb5zWi9+nYB2YHyHpM8lFT3Vn8qs+gMz0vgH6PpouMz4TJa9XWLa5knAkyDnWpfvqicTWCh9uGs/xdfr/fxXM3LqMcsKRZ7DlEztobK9Ko/+qiE+yDX9ZYOmY48y6bfm+8mt8j3n4PnO+y+Jl6njMBY25YVKvPuh+U9ofuK+9dRl+a1F63Y3102sL5vVOA7aDyeG39sH3RbfAzbwein+T60HKEhHEkiWIxeKadatZcgSx5ApiyRPEEtrGLN/ke1lcs9Pv0ej6HfNwLU6/R8N66PdeuN6n1+fmtQMtj/qoyLAlltrR4SNaT4KcY130e9liASx5glhyBbHkCGLJFsSSJYglIoglbLBsKa5h7PL7/oGu13qQNOpSUh/m4fUG/X0gbPDR3xto7MS2LCF5yEXrx7FQSvKQtYywb2l9aeM7fnokSDpqaM9LXl9ua5YsQSzZglhyBLHY+01o61ls/1a2NSz5glgKBLGEtjGL37o71d+su/uenP7OhPMEnbtwnqC/iZSRNGr8fo/OZ2Ef27qbu+gcZ66T6NxF5zhkpXMcstI5DlkpO7Iiu65zcWFXm2ifwM8nQMdSOzr6BK0nQc6xLnqdUS6ApUAQS74gljxBLLmCWHIEsWQLYskSxBIRxBI2WHBPBveeBzov0PkN4xuda3EO87v+o3MtzmF0rqXXtJjnd51I60Ntez8onS/NPTDIkwAdS/Fwpcyv23Ma9vEnzcP01u45xX0J5lqPPmuK9gdzree3J4Luc6C/a3W31qPX+zZiANaD5Zp7JqJe17WjDZaoT93UDxEBfjDXy9vCD1kC/GBeI2wLP2QL8AMy5G1DP+QI8AONo9vKD7kC/IAMBWn2g67X/J6CdWMGHhGj7MbY2Kam9paG9nhjfGWsoW1Va3OsqXnV2NZ4a7y5tXnPhtbGxvbWptaWtlVtLbG2eFNje3xNc1vjGig8zMh5OiPXWXxcsYhf45A8Lvs5mSnv2SSNgT/s0ydyLNjkGfWYfiz2LHd8G410toVyz/H4Or8tu8/hb6MYbXfpPsWD+QopfiYj57mMZaUr8J3r2Ql8PyDpIPClWOa54FDucs/zZAc+bfd5/G1kNfBx+jRdQeAMz04Q+CFJB0EgxTLPAIdyl3u+JzsIaLvP52+jjo6a43V2wtOUfKHke6C/D1ofFyj5EdhGv6c9E95zAXnvhUouIu/9JuVfrOSSbsq/mLz3UiU/9nnv6fCeS0HrAXeZkst93nsGvOcy0JrxCiU/8ZIPc7WVav/g7GtXerzfUdB9elXgl2rQNaBrQfcE3Qt0b9B9QNeB7gu6HnQ/0P2JvkrJ1eBrGhy5x9FVfGXF6qGca5Rcq+Q6JdcruUHJjUpuUnKzkluU3KrkNiW3K7lDyZ1K7lJyt5J7lNyr5D4l9yt5QMmDSh5S8rCSR5Q8quQxJY8reULJk0p+quQpcFII/KZZ8rzO82uN8+uM8+uN8xuM8xuN85uM85uN81uM81uN89uM89uN8zuM8zuN87uM87uN83uM83uN8/uM8/uN8weM8weN84eM84eN80eM80eN88eM88eN8yeM8yeN858a5095XZ/5YH7FFkvtSBozqcaraxjL+ixiZzHM9RVl+xp9xOLXMpWl2+I6Rv/9T7z/OoqOX596WQ1gc/wGRv99Ltl/TV9xxm9MrawYsTl+E6P/vpDqv4YkzvjN376smGFz/BZG/30p0H9j13ThjN/67cpq9bE5fhuj//TFgSj/tfpyxm/f+rJatmBz/A5G/4Uk+a9li5zxO7eurIZubI7fxei/sBT/tXTLGb/7m5e1+mtsjt/D6L+IBP+1fC1n/N5vVlbsG9gcv4/Rf1nb2n+xb8QZv//ry2r+hjbHH2D0X/a29F/TN+aMP9htWU1rtsLm+EOM/svZVv5r2SrO+MNbLqt1K22OP8Lov9xt4L+2NVvNGX/Uv6zYt7A5/hij//LS7b/Yt+KMP961rPi3tDn+BKP/8tPpvz2/NWf8yeSyGlOwOf5TRv8VpMl/DWtS4ow/5fF9l0i/s0vVf9E0+S+W2hFn/J4t/jmj/wod8R/j90TxLxn9V+SI/xi/54jTa/5U/VfsiP8Yr9PjEUb/lTjiP8brzHg2o/96OOI/xuukeC6j/0od8R/jOj+ez+i/Mkf8x7hOjUcZ/VfuiP8Y11nxIkb/VTjiP8Z1QryE0X+VjviPcZ6LlzL6r8oR/zHG6Xg5o/+qHfEfY5yJVzL6r8YR/zGOkzhjn4lz+k/vZ9P3Qpv7g7H8Ad7mfW4DQQ8CPRj0ENBDQQ8DPRz0CNAjQY8CPRr0GNAx0HHQDaAbQTeBbgY9FnQL6FbQbaDHgR4PegLoiaAngZ4MOgF6CuipoKeB3g70dNAzQM8EvT3oWaB3AL0j6J1Azwa9M+g5oOeCngd6PugFoHcBvRD0rqAXgd4N9GLQu4NeAnop6GWg9wC9HPQK0CtBrwJd720+cL8j7oPE/ZFPgMb9lI+Bxv2Xj4DG/Zq4jxP3d+K+T9wPivtEcf8o7ivF/aa4DxX3p+K+VdzPivtccf8r7ovF/bK4jxb31+K+W9yPi/t0cf/uNaB/5iUfYdAJ0LHUjvjPPL74+jRjWem6Cehpjzem4fFzkg5uAkqxzKfBodzlPuPxdVhbdj/D30ZW7wTk9Gm6gkCdZycI/IKkgyCQYpl14FDucp/1ZAcBbfez/G3UMbjMf2y0xc/FbJOzpyOcVR5/sAqRMp9T8rySF5S8qOQlJS8reUXJq0peU/JLJb9S8rqSN5S8qeQtJW8reUfJu0reU/K+kg+UfKjk10p+o+S3Sn6n5PdK/qDkj0r+pOTPSj5S8hclf1XyNyV/V/IPJf9U8i8lHyv5t5L/KPlEyadK/qvkMyX/U/K5t/kq8kswKqQkrCSiJEtJtpIcJblK8pTkKylQElVSqKSIRET6lGIzeNMnAoZIHg3u+sgh6QToWIqHhckipq/E84gdnmFvsWfjH7yakp7U6Bn+NP1G/alZ8emiq1euWzf3wLUHr9zYPmPT+tUb125YT7t1tlFMxMc8M58+ENT801LazPTBjyGTPwE61TmFzk+x1I54umL+C56dWOrxcjZYLDtOO1cxOLiEdG4cZ2Gv6z/XhUg76c74pde1rUIkHYb3RLp5T2gL5dDxTv/FxZXYZXUhi7fd6gb83Ou8Dbck1LVS7q+B6SBK7ZbUNWs0f6plfbUNJeTeIvRFLwhINCD1AAeXBgHJzYDUwwhIpWkISHQQpRqQejAGpFIHA9JLXhCQaEAqAweXBwHJzYBUZgSk8jQEJDqIUg1IZYwBqdzBgPSaFwQkGpAqwMGVQUByMyBVGAGpMg0BiQ6iVANSBWNAqnQwIP3SCwISDUhV4ODqICC5GZCqjIBUnYaARAdRqgGpijEgVTsYkH7lBQGJBqQacHBtEJDcDEg1RkCqTUNAooMo1YBUwxiQah0MSEWhICDRgNQTHNwrCEhuBqSeRkDqlYaAVBTiC0g9GQNSL0uDm9t/dHtXqjY/x1hWb+aA3qXze/wBnZOZ8vYhJ8E+1BTL1I3UJ2RhnyRj8LBld12IvY26/Z8rzr1TqZbVNyS7X+q26Rvi33/W4shdk5xtXc/Y1i2Md7CmayKqtzQR9QsmIt5G6mdhIuovfCLSdve3PBFJ96lHOjInJ70JIlXO5xnLGuDgan6ApSA6MAiivI000EIQHSQ8iGq7B2Xwan6w8NW8bpvBFlbzbRm4mh/C2NZtDq7mh1iaiIYGExFvIw21MBENEz4RabuHObaa5/apRzoyJye9VThVztcZyxru4Gp+uKUgOiIIoryNNMJCEB0pPIhqu0dm8Gp+lPDVvG6bURZW8+MzcDU/mrGtxzu4mh9taSIaE0xEvI00xsJEFBM+EWm7Y46t5jl9mq4g0MtSEIgHQYC3keIWgkCD8CCg7W7I4NVoo/DVqG6bRgur0YkZuBptYmzriQ6uRpssTUTNwUTE20jNFiaiscInIm33WMdWo5w+TVcQqLQUBFqCIMDbSC0WgkCr8CCg7W7N4NVom/DVqG6bNgur0ckZuBodx9jWkx1cjY6zNBGNDyYi3kYab2EimiB8ItJ2T3BsNcrp03QFgWpLQWBiEAR4G2mihSAwSXgQ0HZPyuDV6GThq1HdNpMtrEanZOBqNMHY1lMcXI0mLE1EU4KJiLeRpliYiKYKn4i03VMdW41y+jRdQaDWUhCYFgQB3kaaZiEIbCc8CGi7t8vg1eh04atR3TbTLaxGp2XganQGY1tPc3A1OsPSRDQzmIh4G2mmhYloe+ETkbZ7e8dWo9w+9UhHppyplh1mtPllRq5ZjAEpXUF0lqUgukMQRHkbaQcLQXRH4UFU271jBq/mdxK+mtdts5OF1fz0DFzNz2Zs6+kOruZnW5qIdg4mIt5G2tnCRDRH+ESk7Z7j2Gqe26ce6ciUM9Wy6xhtfoWRa66Dq/m5loLovCCI8jbSPAtBdL7wIKrtnp/Bq/kFwlfzum0WWFjNz8zA1fwujG0908HV/C6WJqKFwUTE20gLLUxEuwqfiLTduzq2muf0qWbTAwQHkH6u8RdKSkKbdSnoctAFShap9G7QV3K8zr/5eRk++wroV0FXwmerQddi2UoWq/TuPmVlw3tyQOeCzgOdjzygC5UsUemlpCxshMXwnteB5w3Qb4J+C/TboN8B/S7o90C/D/oD0B+C/jXo34D+Lejfgf496D+A/iPoP4H+M+iPQP8F9F9B/w3030H/A/Q/Qf8L9Meg/w36P6A/Af0p6P+C/gz0/0B/DhrlS9Ae+C8EOgw6AjoL9BLQUWwT0MOVLFPpPUjbYHB+DupYBO9dBrpMyXKVXmFEUcmLupWME326Jue+np3JeVUwOfM20ioLk/Nq4ZOztnu1hck5Xf9hyDm4bHL2coSz2uMPViFS5p7qpF3JGiV7KdlbyVol+yjZV8k6JfspWa9kg5L9lRyg5EAlBynZqGSTkoOVHKLkUCWHKTlcyRFKjlRylJLvKDlayTFKjlVynJLjlZyg5EQlJyk5WckpSk5V8l0lpyn5npLvKzldyRlKzlRylpKzlZyj5FwlP1BynpIfKjlfyQVKfqTkQiUXKblYySVKLlXyYyWXKblcyRVknJWA1v/raAbvfK/rf0Tme8nBXR+u/Pdjtiojj9jhGfbi/1jmsNbbFNN1ZXvJhzkpJXz8qVnLIb165bp1cw9ce/DKje0zNq1fvXHthvW0W2cbxUR8zDPzs4grciGdTfLwc7lEh0z+BOhU55TVzAuqdMT8NSE7sdTj5Uzb/9b+BBx8Jencwf/W8pSZlv+t1Q1I/7f2ylDXSrm/fl3DsDDF/639CeMi90rGwZ2ugLRXEJCSAtJV4OCrg4DkZkC6yghIV6chIO3FGJCuYgxIVzsYkPYOAlJSQLoGHHxtEJDcDEjXGAHp2jQEpL0ZA9I1jAHpWgcD0rogICUFpOvAwdcHAcnNgHSdEZCuT0NAWscYkK5jDEjXOxiQ9gsCUlJAugEcfGMQkNwMSDcYAenGNASk/RgD0g2MAelGBwPS+iAgJQWkm8DBNwcByc2AdJMRkG5OQ0BazxiQbmIMSDc7GJCuCAJSUkC6BRx8axCQ3AxItxgB6dY0BKQrGAPSLYwB6VZLg5vbf3R7V6o278nov9uYA3qXzu/xB3ROZsp7OzkJ9qGmWKZupNtD/OXewdj5bdl9R4i9jazerci5t/fOkOx+qdvmzhD//rNZjtytyNnWdzG29SwH71a8y9JEdHcwEfE20t0WJqJ7hE9E2u57LE9E0n3qkY7MyUlvgkiVs53R5nsdXM3faymI3hcEUd5Gus9CEL1feBDVdt+fwav5B4Sv5nXbPGBhNb9jBq7mH2Rs6x0dXM0/aGkieiiYiHgb6SELE9HDwicibffDjq3muX3qkY7MyUlvFU6VcwOjzY84uJp/xFIQfTQIoryN9KiFIPqY8CCq7X4sg1fzjwtfzeu2edzCan52Bq7mn2Bs69kOruafsDQRPRlMRLyN9KSFieinwicibfdPHVvNc/o0XUHgVktB4KkgCPA20lMWgsDPhAcBbffPMng1+rTw1ahum6ctrEbnZOBq9OeMbT3HwdXozy1NRM8EExFvIz1jYSL6hfCJSNv9C8dWo5w+TVcQuN5SEHg2CAK8jfSshSDwnPAgoO1+LoNXo88LX43qtnnewmp0XgauRl9gbOt5Dq5GX7A0Eb0YTES8jfSihYnoJeETkbb7JcdWo5w+TVcQuNFSEHg5CAK8jfSyhSDwivAgoO1+JYNXo68KX43qtnnVwmp0QQauRl9jbOsFDq5GX7M0Ef0ymIh4G+mXFiaiXwmfiLTdv3JsNcrp03QFgZstBYHXgyDA20ivWwgCbwgPAtruNzJ4Nfqm8NWobps3LaxGF2bgavQtxrZe6OBq9C1LE9HbwUTE20hvW5iI3hE+EWm733FsNcrtU490ZMqZatlhRpvXMtr8LmNASlcQfddSEH0vCKK8jfSehSD6vvAgqu1+P4NX8x8IX83rtvnAwmp+UQau5j9kbOtFDq7mP7Q0Ef06mIh4G+nXFiai3wifiLTdv3FsNc/tU490ZMqZatl9GW3eh9Hm3zq4mv+tpSD6uyCI8jbS7ywE0d8LD6La7t9n8Gr+D8JX87pt/mBhNb84A1fzf2Rs68UOrub/aGki+lMwEfE20p8sTER/Fj4Rabv/7NhqntOnmk0PEBxA+rnGXyh9JeirQV8LukDJRyr9F+grOV7n3/yshffsA3pf0NeDvhH0zaBLlfxVpf/mU9aF8J6LQF8M+hLQl4L+MehCJX9X6X+QsrAR/grv2QB6f9AHgD4Q9EGgN4LeBPpg0IeAPhT0YaAPB30E6CNBHwX6O6CPBn0M6GNBHwf6eNAngD4R9EmgTwZ9CuhTQX8X9Gmgvwf6+6BPB30G6DNBnwX6bNDngD4X9A9Anwf6h6DPB30B6B+B/jvoy0BfDnq4kn+q9L9I22Bw3hPe8xHof4IuU/KxSv87tPm93+Qvx1IdC896diYIz+CMbd0RNzMYy+5SF51A/wMO/oTEx+Avx3jKTMtfjukGfAgq0uefkInDdB7mcw6irSwrZpQV/w/jRPcJ4yo8Xf+BmArzmuRjtQ+ulYDEHZRXh+wEt08B9L/fMrhN9bHZDG5Tva8Pbn7l/L8KbpI7BAbGT0OdDaPPdaeY4iUf3IGS047/MgbKz0J8gQH9+Rnxp43+8Eko5fYxJ59mzvb5hLF9ljB/hZbi4O/S5tpvOJ4423mpLLvNo+Mrw/9asHtZmr4yTXWx9iljH+eMZ3s48pUz47iOL2X8mni5I/5jHCdxxj4TT8V/3S3iuX/e4hy//2OcO23azPkzz+fMNnPPT7pNPrcwP7Vn4E96XzC2dbuDP+kx2p/0k96X5CT4SS/FMnUjfRmy4Kiw7J/0vsCrTt5yrf6kJ92ny1WBKy1MHqFweton5duMHOGMOMKZxciZ7W2eLHDC0H1Kt5f2RRadPTz+BeSzjGVl8/kkTv1BD67yt9QvYqkd8WwL/Zeb8eOQG2Msh9GXlvuTtbbKcaA/5VqK2ZIvlvPCvLHIlfVOviPzc4E7c5G1cVngQOyIZmDsKGSOHVtqm1Q5i/g4G1wdQ0UOjKHiDBxDJY6MoR58nI2ujqEeDoyh0gwcQ2WMYyhdX9zX85WV9MV9ebgzHXxxn2KZ9eBQ7nIrhH/JrO2usPDFfbq269Z7doIgN2dvRzhrPP5gpXUhpCtVX6tSUq2kRkmtkp5KeinpraSPkjolfZXUk35ZAlpv0zWDXb7XdctvvpccDPXhylZe/eV6HrHDM+zFbck5vPWu1nVle8mHGcQTPv7UrLWQbl9/wKb2Te1zN61at3b1jE3rV29cu2H9tJXr1tHOgJVgp4j4GGnmZxGH5EI6m+Th53KJtrYfuoJ5GZKOSFltabno8XI2WCw76WaEfnDSn2QGd1rxlJmWO610A37udd5A0D/ctVLuDU3VDMu5dthZ2I9xadifcXCnKyDVBAEpKSANgJOBQUByMyANMALSwDQEpBrGgDSAMSANdDAg1QYBKSkgDYKTwUFAcjMgDTIC0uA0BKRaxoA0iDEgDXYwIPUJAlJSQBoCJ0ODgORmQBpiBKShaQhIfRgD0hDGgDTUwYBUFwSkpIA0DE6GBwHJzYA0zAhIw9MQkOoYA9IwxoA03MGA1DcISEkBaQScjAwCkpsBaYQRkEamISD1ZQxIIxgD0khLg5vbf/Uen82VjP4bxRzQu3R+jz+gczJT3tEkIAabpVIsUzfS6DB/uWMYO78tu8eE2dvI6u5Lzg1osbDsfqnbJhbm3+6xlyOP2+Bs6zhjW+/l4OM2GO1PmogagomIt5EaLExEjcInIm13o+WJSLpP8eAOonSnbqqcVYw2Nzm4mm+yFESbgyDK20jNFoLoWOFBVNs9NoNX8y3CV/O6bVosrObXZuBqvpWxrdc6uJpntD9pImoLJiLeRmqzMBGNEz4RabvHObaa5/apRzoyJye9ny1VznpGm8c7uJofbymITgiCKG8jTbAQRCcKD6La7okZvJqfJHw1r9tmkoXV/L4ZuJqfzNjW+zq4mme0P2kiSgQTEXMjWZiIpgifiLTdUxxbzXP6NF1BYKilIDA1CAK8jTTVQhCYJjwIaLunZfBqdDvhq1HdNttZWI3ul4Gr0emMbb2fg6tRRvuTJqIZwUTE20gzLExEM4VPRNrumY6tRjl9mq4gMNxSENg+CAK8jbS9hSAwS3gQ0HbPyuDV6A7CV6O6bXawsBrdkIGr0R0Z23qDg6tRRvuTJqKdgomIt5F2sjARzRY+EWm7Zzu2GuX0abqCwEhLQWDnIAjwNtLOFoLAHOFBQNs9J4NXo3OFr0Z128y1sBo9IANXo/MY2/oAB1ejjPYnTUTzg4mIt5HmW5iIFgifiLTdCxxbjXL71CMdmXKm/OfNjDb3ZLR5F8aAlK4guoulILowCKK8jbTQQhDdVXgQ1XbvmsGr+UXCV/O6bRZZWM0flIGr+d0Y2/ogB1fzjPYnTUSLg4mIt5EWW5iIdhc+EWm7d3dsNc/tU490ZMqZ8p1vjDb3YrR5iYOr+SWWgujSIIjyNtJSC0F0mfAgqu1elsGr+T2Er+Z12+xhYTW/KQNX88sZ23qTg6t5RvuTJqIVwUTE20grLExEK4VPRNrulY6t5jl9qtn0AMEBpJ8k94W3+U8utR4IejDoAiWrVHo19BX6/8A94T29QPcGPRT0cNAjQZcq2VOl2+mo9fgnnTXh9LRryo9/dYRzb+aArvsPBus10Df2Ar03aP1Q/7UqvY/lvrKvI22wzhHO/Sz2lX2hb6wDvR/pK+tVeoPlvrK/I21wgCOcB1rsK/tD3zgA9IGkrxyk0hst95VNjrTBwY5wHmKxr2yCvnEw6ENIXzlUpQ+z3FcOd6QNjnCE80iLfeVw6BtHgD6S9JWjVPo7lvvK0Y60wTGOcB5rsa8cDX3jGNDHkr5ynEofb7mvnOBIG5zoCOdJFvvKCdA3TgR9EukrJ6v0KZb7yqmOtMF3HeE8zWJfORX6xndBn0b6yvdU+vuW+8rpjrTBGRbaAF17Ovj8DNB5Ss5U6bMs+/5sR3x/jkXfnw0+P4f4/lyV/oFl35/niO9/aNH354HPf0h8f75KX2DZ9z9yxPcXWvT9j8DnFxLfX6TSF1v2/SWO+P5Si76/BHx+KfH9j1X6Msu+v9wR319h0feXg8+vIL7/iUpfadn3Vzni+6st+v4q8PnVxPfXqPS1ln1/nSO+v96i768Dn19PfH+DSt9o2fc3OeL7mx3hvMURzlsd4bzNEc7bHeG8wxHOOx3hvMsRzrsd4bzHEc57HeG8zxHO+x3hfMARzgcd4XzIEc6HHeF8xBHORx3hfMwRzscd4XzCwjX0MChvT7h2rgd9E+ibQd8C+lbQa0GvB30Q6ENBHwX6ONAng/4e6DNBnwv6fNAXgf4x6J+Avgb0DaBvA3076DtA3wn6LtB3g74H9L2g7wN9P+gHQD8I+iHQD4N+BPSjoB8D/TjoJ0CPUPKkSv803LkPHH+PrIT3rAL9JOgyJU+p9M/CXtIRZu4/nDfvPM3XF+PpuuGmn8c7fvD4OWm34IabFMvsBw7lLvcZxs5vy+5nwuxt1HE3W8TrekgeXDY5+zjCWevxByutCyH9C9XXnlXynJLnlbyg5EUlLyl5WckrSl5V8pqSX5J+WQJab6Ixg10+6WshkmfMa1/dGMXor5iF4BrL9jb/mIB2eIa9xV7yjV5M9a7WdWV7yYcZxBM+/tSstZBuX3/ApvZN7XM3rVq3dvWMTetXb1y7Yf20levW0c6AlWCniPgYaeZnEYfkQjqb5OHncokOmVYkQKcaiZ9hXoakI1I+Z+lyw+PlbLBYdpx2rl/ByeskE0db2OvsUDmkPbCddGf80uvaViGSDsN7It28J7SFcuiox8/jqGf2iZUIZnX5FwLn6gb8HCrS56+Hu1bK/SCC5xiWc+1rNh+/Ylwavs44uNMVkJ4PAlJSQHoDTt4MApKbAekNIyC9mYaA9DxjQHqDMSC96WBAeiEISEkB6S04eTsISG4GpLeMgPR2GgLSC4wB6S3GgPS2gwHplSAgJQWkd+Dk3SAguRmQ3jEC0rtpCEivMAakdxgD0rsOBqRXg4CUFJDeg5P3g4DkZkB6zwhI76chIL3KGJDeYwxI7zsYkF4LAlJSQPoATj4MApKbAekDIyB9mIaA9BpjQPqAMSB9aGlwc/uvn8dn8y8Y/fdr5oDepfN7/AGdk5ny/oYExGCzVIpl6kb6TZi/3N8ydn5bdv82zN5GVh+Tz7kB7Xdh2f1St83vwvzbPQ5x5DH5nG39e8a2PsTBx+Qz2p80Ef0hmIh4G+kPFiaiPwqfiLTdf7Q8EUn3qUc6Micn3ambKuezjDb/ycHV/J8sBdE/B0GUt5H+bCGIfiQ8iGq7P8rg1fxfhK/mddv8xcJq/rAMXM3/lbGtD3NwNc9of9JE9LdgIuJtpL9ZmIj+Lnwi0nb/3bHVPLdPPdKROTnp/Wypcv6S0eZ/OLia/4elIPrPIIjyNtI/LQTRfwkPotruf2Xwav5j4at53TYfW1jNH5GBq/l/M7b1EQ6u5hntT5qI/hNMRLyN9B8LE9Enwicibfcnjq3mOX2ariDwrqUg8GkQBHgb6VMLQeC/woOAtvu/Gbwa/Uz4alS3zWcWVqNHZeBq9H+MbX2Ug6tRRvuTJqLPg4mIt5E+tzARfSF8ItJ2f+HYapTTp+kKAu9bCgJfBkGAt5G+tBAEtHewLIlBoOP2xAh7GzmzGg1FZPdL3TaakXs1enQGrkbDjG19tIOrUUb7kyaiCIkfwUSUYpm6kSIR/nKzhE9E2u4syxORZJ+mKwhw3jlJebODIMDbSNkWgkCO8CCg7c7J4NVorvDVqG6bXAur0WMzcDWax9jWxzq4Gs2ztBrNDyYi3kbKtzARFQifiLTdBY6tRrl96pGOTDlTvgxntPlFxoAcZQxI6QqiUUtBtDAIoryNVGghiBYJD6La7qIMXs0XC1/N67YptrCaPz4DV/MljG19vIOr+RJLE1GPYCLibaQeFiaiUuETkba71LHVfKkjq/l+jDa/xBiQyxxczZdZCqLlQRDlbaRyC0G0QngQ1XZXZPBqvlL4al63TaWF1fyJGbiar2Js6xMdXM1XWZqIqoOJiLeRqi1MRDXCJyJtd41jq3lOn2o2PUBwAOknyX3hbf6TS63fBP026AIltar+ntBX6P8DvwjveQn0y6DfBf0+6A9BlyrppcrpHfG87vyVqo19Iulp11Q56xzh7Msc0HX/wS6g20r3jTrQfUHrh/rXq3Q/y32lvyNtMMARzoEW+0p/6BsDQA8kfWWQSg+23FeGONIGQx3hHGaxrwyBvjEU9DDSV4ar9AjLfWWkI20wyhHO0Rb7ykjoG6NAjyZ9ZYxKxyz3lbgjbdDgCGejxb4Sh77RALqR9JUmlW623FfGOtIGLY5wtlrsK2Ohb7SAbiV9pU2lx1nuK+MdaYMJjnBOtNhXxkPfmAB6Iukrk1R6suW+knCkDaY4wjnVYl9JQN+YAnoq6SvTVHo7y31luiNtMMNCG+AXztPB5zNA5ymZqdLbW/b9LEd8v4NF388Cn+9AfL+jSu9k2fezHfH9zhZ9Pxt8vjPx/RyVnmvZ9/Mc8f18i76fBz6fT3y/QKV3sez7hY74fleLvl8IPt+V+H6RSu9m2feLHfH97hZ9vxh8vjvx/RKVXmrZ98sc8f0eFn2/DHy+B/H9cpVeYdn3Kx3x/SqLvl8JPl9FfL9apfe07Pt2R3y/xhHOvRzh3NsRzrWOcO7jCOe+jnCuc4RzP0c41zvCucERzv0d4TzAEc4DHeE8yBHOjY5wbnKE82BHOA9xhPNQRzgPc4TzcEc4j7BwDT0MyusF1876P/a0bofzNaD3Ar036HrQg0APBz0GdBPoNtCTQE8DPRP0jqDngF4AehHoJaCXg14Nei3ofUDvC3od6P1Arwe9AfT+oA8AfSDog0BvBL0J9MGgDwF9KOjDQB8O+gjQI5QcqdJHRTr3gePXEL8A39bCe48EXabkOyp9dGTze42vLaz0pYowW1+K++B+27LjZgZj2V3qCpMyjwGnH0ucnw867HV+15RD2gPfqu8R+NLr2lYhkg7DeyLdvCe0hXLySR5+vpiwMPokZuGmoJjVm35C4FzdgA9BRfr8WBIsTedhPucg2sqyYkZZ8WMifFzH8k0U8W8akGKpHfFUmNckH6t9cK0EJO6g/EzYTnA7Dhrw+G8Z3Kb62GwGt6ne1wc3v3L+XwU3yR0CA+Nxkc6G0ee6U0zxkg/uQMlpx/GMgfKECF9gQH+eQPxpoz8cG0m5fczJp5mzfY5lbJ+TmW+LT3Hwd2lz7TccT5ztfIosu82j4zEAx1uw+9Q0PQYh1cXacYx9nDOefdeRx0gwjuv4KYyPfjjNEf8xjpM4Y5+Jp+K/7hbx4dTGb5d25hy/JzJebNm0mfPRLScx28w9P+k2OcnC/HRWBj6m52TGtj7Lwcf0MNqf9JieU8jFePCYnhTL1I10SoS/3FMZJwpbdp8aYW8jq4/pke7Tp9QofDrMP3l815GfGU9zhPN7jnB+n5EzW5WhBScM3ad0e2lffN/4mp57AVnBuKg4nXFRkQU+MQ+u8rfUL2KpHfHTLfRfbsbvODLGzmDktNyfrLXVGQ70pzMt9SfJF8tnCb9YtrXeOduR2HGOO3ORtXF5jgOx49wMjB0/sPTlIvcYOo+Ps8HVMXSeA2Pohxk4hs53ZAxdwMfZ6OoYusCBMfSjDBxDFzoyhi5yZM15sSOclzjCeSkzJ3fMOF+VcaEFu88RvlHoClXGlRbsPlfmRqEunD9mjJuMbR235T/udr7MkfhzuSOcVzjC+RNHOK90hPMqRzivdoTzGkc4r3WE8zpHOK93hPMGRzhvdITzJkc4bxZ+HbRaFZhv4bemHwq/DspVNudZsPt8R66DbmG8DmJs6/j5wvtNVPWZQgv95lbhcaJY2Vxiwe7bhNtdqmwus2D37cLt1t9Vn21hw/6Fwse33g9zlgW7L3JkXriDcV5gbOv4RcL7jd4L8QML/eZO4XFC/359vgW77xJut/7N8UILdt/tyHXNPY5w3usI532OcN7vCOcDjnA+6AjnQ45wPpymvSCx1I6Oh79w2fyIIzaHGW1+1BGbI4w2P+aIzVmMNj/uiM3ZjDY/4YjNOYw2P+mIzacy2vxTR2y+iPH+4KccsfliRpt/5ojNlzDa/LQjNl/KaPPPHbH5x4w2P+OIzZcx2vwLR2y+nNHmZx2x+QpGm59zxOafMNr8vCM2X8lo8wuO2HwVo80vOmLz1Yw2v+SIzdcw2vyyIzZfy2jzK47YfB2jza86YvP1jDa/5ojNNzDa/EtHbL6R0eZfOWLzTYw2v+6IzTcz2vyGIzbfwmjzm47YfCujzW85YvNtjDa/7YjNtzPa/I4jNt/BaPO7jth8J6PN7zli812MNr/viM13M9r8gSM238No84eO2Hwvo82/dsTm+xht/o0jNt/PaPNvHbH5AUabf+eIzQ8y2vx7R2x+iNHmPzhi88OMNv/REZtzPT6b/+SIzXmMNv/ZEZvzGW3+yBGbCxht/osjNkcZbf6rIzYXMtr8N0dsLmK0+e+O2FzMaPM/HLG5hNHmfzpicw9Gm//liM2ljDZ/7IjNZYw2/9sRm8sZbf6PIzZXMNr8iSM2VzLa/KkFm1eBxj/m1vdG4XOx9b0k+rpQXyfp6wa9jtbrSr3O0usOPQ/reUnHaR239DjW/Vq3s7a7Skm1kholtUp6KumlpLeSPkrqlPRVUq+kn5L+SgYoGahkkJLBSoYoGapkmJLhSkYoGalklJLRSsZoXyjRD0xu0D5W0qSkWclYJS1KWpW0KRmnZLySCUomKpmkZDK0zxQlU5VMU7KdkulKZiiZqWR7JbOU7KBkRyU7KZmtZGclc5TMVTJPyXwlC5TsomShkl2VLFKym5LFSnZXskTJUiXLlOyhZLmSFUpWQluMg/bQ9w/q++n0/WX6fit9/5G+H0ffn6Lv19D3L+j9/Hp/u97vrfc/6/3Aen+s3i+q90/q/YR6f53eb6b3X+n9SHp/jt6vovdv6P0M+vd9/Xu3/v1X/x6qfx/Uv5fp34/07yn69wX9fbv+/ll/H6u/n9Tf1+nvr/T3Ofr7DX29r69/9fWgvj7S1wt6/azXk3p9pdcbev7V85GOzzpe6fGr+/P/Aad12+oltAUA", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json index a400d9a909b..23c2a5e18d0 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json @@ -95,7 +95,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts b/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts index 0f090c4effd..63276c8c442 100644 --- a/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/constant_historic_block_data.ts @@ -43,24 +43,22 @@ export class ConstantHistoricBlockData { public readonly prevGlobalVariablesHash: Fr, ) {} - static from(fields: FieldsOf) { - return new ConstantHistoricBlockData(...ConstantHistoricBlockData.getFields(fields)); - } + static from(fields: FieldsOf) { + return new ConstantHistoricBlockData(...ConstantHistoricBlockData.getFields(fields)); + } - static getFields(fields: FieldsOf) { - return [ + static getFields(fields: FieldsOf) { + return [ fields.privateDataTreeRoot, fields.nullifierTreeRoot, fields.contractTreeRoot, fields.l1ToL2MessagesTreeRoot, fields.blocksTreeRoot, fields.privateKernelVkTreeRoot, - fields.publicDataTreeRoot, - fields.prevGlobalVariablesHash - ] as const; - - } - + fields.publicDataTreeRoot, + fields.prevGlobalVariablesHash, + ] as const; + } toBuffer() { return serializeToBuffer(...ConstantHistoricBlockData.getFields(this)); @@ -79,7 +77,9 @@ export class ConstantHistoricBlockData { reader.readFr(), reader.readFr(), reader.readFr(), - reader.readFr(), reader.readFr()); + reader.readFr(), + reader.readFr(), + ); } isEmpty() { @@ -96,13 +96,6 @@ export class ConstantHistoricBlockData { } static empty() { - return new ConstantHistoricBlockData( - Fr.ZERO, - Fr.ZERO, - Fr.ZERO, - Fr.ZERO, - Fr.ZERO, - Fr.ZERO, - Fr.ZERO, Fr.ZERO); + return new ConstantHistoricBlockData(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index a7c4b199286..e8b6f51e634 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -109,7 +109,16 @@ export function makeTxContext(seed: number): TxContext { * @returns A combined historic tree roots object. */ export function makeConstantHistoricBlockData(seed: number): ConstantHistoricBlockData { - return new ConstantHistoricBlockData(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3), fr(seed + 4), fr(seed + 5), fr(seed + 6), fr(seed + 7)); + return new ConstantHistoricBlockData( + fr(seed), + fr(seed + 1), + fr(seed + 2), + fr(seed + 3), + fr(seed + 4), + fr(seed + 5), + fr(seed + 6), + fr(seed + 7), + ); } /** diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 3b937053afb..0c0248af6d2 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -25,9 +25,9 @@ import { L1Publisher, SoloBlockBuilder, WasmRollupCircuitSimulator, - getconstantHistoricBlockData, getL1Publisher, getVerificationKeys, + getconstantHistoricBlockData, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '@aztec/sequencer-client'; diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 0b8e51ca339..13801d9225a 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -512,8 +512,7 @@ export class SoloBlockBuilder implements BlockBuilder { const wasm = await CircuitsWasm.get(); const blockData = tx.data.constants.blockData; - const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = - blockData; + const { privateDataTreeRoot, nullifierTreeRoot, contractTreeRoot, l1ToL2MessagesTreeRoot } = blockData; const blockHash = computeBlockHash( wasm, blockData.prevGlobalVariablesHash, diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 17f102466ee..9465b81f8da 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -14,12 +14,12 @@ export async function getconstantHistoricBlockData( const roots = db.getTreeRoots(); return new ConstantHistoricBlockData( - Fr.fromBuffer(roots.privateDataTreeRoot), - Fr.fromBuffer(roots.nullifierTreeRoot), - Fr.fromBuffer(roots.contractDataTreeRoot), - Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), - Fr.fromBuffer(roots.blocksTreeRoot), - Fr.ZERO, + Fr.fromBuffer(roots.privateDataTreeRoot), + Fr.fromBuffer(roots.nullifierTreeRoot), + Fr.fromBuffer(roots.contractDataTreeRoot), + Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), + Fr.fromBuffer(roots.blocksTreeRoot), + Fr.ZERO, Fr.fromBuffer(roots.publicDataTreeRoot), prevGlobalsHash, ); diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 0b5d23f97df..0568d699290 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -6,13 +6,7 @@ import { PublicExecutor, PublicStateDB, } from '@aztec/acir-simulator'; -import { - AztecAddress, - CircuitsWasm, - ConstantHistoricBlockData, - EthAddress, - Fr, -} from '@aztec/circuits.js'; +import { AztecAddress, CircuitsWasm, ConstantHistoricBlockData, EthAddress, Fr } from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { ContractDataSource, L1ToL2MessageSource, MerkleTreeId } from '@aztec/types'; import { MerkleTreeOperations, computePublicDataTreeLeafIndex } from '@aztec/world-state'; From c0c552612762466716ed7295372ed3e4e7c34fc3 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 7 Aug 2023 19:03:26 +0000 Subject: [PATCH 52/58] chore: update snapshot --- .../src/aztec3/circuits/rollup/test_utils/utils.cpp | 1 - .../structs/kernel/__snapshots__/index.test.ts.snap | 12 ++++-------- .../rollup/__snapshots__/base_rollup.test.ts.snap | 6 ++---- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index e0e5196f3a8..cbef4d5432b 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -155,7 +155,6 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne baseRollupInputs.start_public_data_tree_root = public_data_tree.root(); // create the original historic blocks tree leaf - info("block hash base inputs"); auto block_hash = compute_block_hash(prev_global_variables_hash, private_data_tree.root(), nullifier_tree.root(), diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index 55952adc700..d08c5e13a80 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -412,13 +412,12 @@ value: 0xd09 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 +block_data: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 - public_data_tree_root: 0x107 prev_global_variables_hash: 0x108 @@ -961,13 +960,12 @@ value: 0xd09 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 +block_data: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 - public_data_tree_root: 0x107 prev_global_variables_hash: 0x108 @@ -1482,13 +1480,12 @@ value: 0xd09 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 +block_data: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 - public_data_tree_root: 0x107 prev_global_variables_hash: 0x108 @@ -1718,13 +1715,12 @@ value: 0xd09 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x101 +block_data: private_data_tree_root: 0x101 nullifier_tree_root: 0x102 contract_tree_root: 0x103 l1_to_l2_messages_tree_root: 0x104 blocks_tree_root: 0x105 private_kernel_vk_tree_root: 0x106 - public_data_tree_root: 0x107 prev_global_variables_hash: 0x108 diff --git a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap index ee539a1a260..b7eee527d74 100644 --- a/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/rollup/__snapshots__/base_rollup.test.ts.snap @@ -206,13 +206,12 @@ value: 0xe08 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x200 +block_data: private_data_tree_root: 0x200 nullifier_tree_root: 0x201 contract_tree_root: 0x202 l1_to_l2_messages_tree_root: 0x203 blocks_tree_root: 0x204 private_kernel_vk_tree_root: 0x205 - public_data_tree_root: 0x206 prev_global_variables_hash: 0x207 @@ -451,13 +450,12 @@ value: 0xf08 ] constants: -block_hash_values: private_historic_tree_roots: private_data_tree_root: 0x300 +block_data: private_data_tree_root: 0x300 nullifier_tree_root: 0x301 contract_tree_root: 0x302 l1_to_l2_messages_tree_root: 0x303 blocks_tree_root: 0x304 private_kernel_vk_tree_root: 0x305 - public_data_tree_root: 0x306 prev_global_variables_hash: 0x307 From 1f102a50bc58a02551a801f05187ebd4ac003dc4 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:07:17 +0000 Subject: [PATCH 53/58] minor rename --- .../cpp/src/aztec3/circuits/abis/packers.hpp | 2 +- circuits/cpp/src/aztec3/constants.hpp | 8 ++--- .../src/core/libraries/ConstantsGen.sol | 2 +- .../src/client/private_execution.test.ts | 8 ++--- .../acir-simulator/src/public/executor.ts | 8 ++--- .../acir-simulator/src/public/index.test.ts | 6 ++-- .../circuits.js/src/cbind/constants.gen.ts | 2 +- yarn-project/noir-libs/noir-aztec/src/abi.nr | 30 +++++++++---------- .../noir-libs/noir-aztec/src/constants_gen.nr | 2 +- .../noir-libs/noir-aztec/src/context.nr | 12 ++++---- .../noir-libs/noir-aztec/src/messaging.nr | 2 +- .../src/sequencer/public_processor.ts | 10 +++---- .../src/simulator/public_executor.ts | 4 +-- 13 files changed, 48 insertions(+), 48 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp index 980460aecf5..c739a6b8767 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp @@ -68,7 +68,7 @@ struct ConstantsPacker { MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH, CALL_CONTEXT_LENGTH, - BLOCK_HASH_DATA_LENGTH, + BLOCK_DATA_LENGTH, FUNCTION_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 70734faf1b3..976a0e91756 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -220,7 +220,7 @@ constexpr size_t MAX_NOTES_PER_PAGE = 10; constexpr size_t VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2; constexpr size_t CALL_CONTEXT_LENGTH = 6; -constexpr size_t BLOCK_HASH_DATA_LENGTH = 7; +constexpr size_t BLOCK_DATA_LENGTH = 7; constexpr size_t FUNCTION_DATA_LENGTH = 4; constexpr size_t CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; @@ -232,14 +232,14 @@ constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + BLOCK_HASH_DATA_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version + + BLOCK_DATA_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 1 + 1 // call_context_hash + args_hash + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + BLOCK_HASH_DATA_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version + + BLOCK_DATA_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version constexpr size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; constexpr size_t CONTRACT_STORAGE_READ_LENGTH = 2; @@ -251,7 +251,7 @@ constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = MAX_PUBLIC_DATA_READS_PER_CALL * CONTRACT_STORAGE_READ_LENGTH + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + MAX_NEW_NULLIFIERS_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + 1 + // + 1 for unencrypted logs preimage length - BLOCK_HASH_DATA_LENGTH + 2; // + 2 for chain_id and version + BLOCK_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 2 + RETURN_VALUES_LENGTH + // + 1 for args_hash + 1 call_context.hash diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 0dc35f361f4..41f316737f9 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -65,7 +65,7 @@ library Constants { uint256 internal constant MAX_NOTES_PER_PAGE = 10; uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; uint256 internal constant CALL_CONTEXT_LENGTH = 6; - uint256 internal constant BLOCK_HASH_DATA_LENGTH = 7; + uint256 internal constant BLOCK_DATA_LENGTH = 7; uint256 internal constant FUNCTION_DATA_LENGTH = 4; uint256 internal constant CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index dfc68f9eaf6..5219567e4a5 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -58,7 +58,7 @@ describe('Private Execution test suite', () => { let circuitsWasm: CircuitsWasm; let oracle: MockProxy; let acirSimulator: AcirSimulator; - let blockHashData = ConstantHistoricBlockData.empty(); + let blockData = ConstantHistoricBlockData.empty(); let logger: DebugLogger; const defaultContractAddress = AztecAddress.random(); @@ -107,7 +107,7 @@ describe('Private Execution test suite', () => { abi, functionData.isConstructor ? AztecAddress.ZERO : contractAddress, EthAddress.ZERO, - blockHashData, + blockData, ); }; @@ -124,10 +124,10 @@ describe('Private Execution test suite', () => { // Update root. const newRoot = trees[name].getRoot(false); - const prevRoots = blockHashData.toBuffer(); + const prevRoots = blockData.toBuffer(); const rootIndex = name === 'privateData' ? 0 : 32 * 3; const newRoots = Buffer.concat([prevRoots.subarray(0, rootIndex), newRoot, prevRoots.subarray(rootIndex + 32)]); - blockHashData = ConstantHistoricBlockData.fromBuffer(newRoots); + blockData = ConstantHistoricBlockData.fromBuffer(newRoots); return trees[name]; }; diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index 3fcb3d71f11..083f46cca02 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -41,7 +41,7 @@ export class PublicExecutor { private readonly stateDb: PublicStateDB, private readonly contractsDb: PublicContractsDB, private readonly commitmentsDb: CommitmentsDB, - private readonly blockHashData: ConstantHistoricBlockData, + private readonly blockData: ConstantHistoricBlockData, private log = createDebugLogger('aztec:simulator:public-executor'), ) {} @@ -63,7 +63,7 @@ export class PublicExecutor { const initialWitness = getInitialWitness( execution.args, execution.callContext, - this.blockHashData, + this.blockData, globalVariables, ); const storageActions = new ContractStorageActionsCollector(this.stateDb, execution.contractAddress); @@ -87,14 +87,14 @@ export class PublicExecutor { }, getL1ToL2Message: async ([msgKey]) => { const messageInputs = await this.commitmentsDb.getL1ToL2Message(fromACVMField(msgKey)); - return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.blockHashData.l1ToL2MessagesTreeRoot); + return toAcvmL1ToL2MessageLoadOracleInputs(messageInputs, this.blockData.l1ToL2MessagesTreeRoot); }, // l1 to l2 messages in public contexts TODO: https://github.com/AztecProtocol/aztec-packages/issues/616 getCommitment: async ([commitment]) => { const commitmentInputs = await this.commitmentsDb.getCommitmentOracle( execution.contractAddress, fromACVMField(commitment), ); - return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.blockHashData.privateDataTreeRoot); + return toAcvmCommitmentLoadOracleInputs(commitmentInputs, this.blockData.privateDataTreeRoot); }, storageRead: async ([slot], [numberOfElements]) => { const startStorageSlot = fromACVMField(slot); diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/acir-simulator/src/public/index.test.ts index e321fe448ad..eb5603d1dd4 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/acir-simulator/src/public/index.test.ts @@ -37,7 +37,7 @@ describe('ACIR public execution simulator', () => { let publicContracts: MockProxy; let commitmentsDb: MockProxy; let executor: PublicExecutor; - let blockHashData: ConstantHistoricBlockData; + let blockData: ConstantHistoricBlockData; beforeAll(async () => { circuitsWasm = await CircuitsWasm.get(); @@ -48,8 +48,8 @@ describe('ACIR public execution simulator', () => { publicContracts = mock(); commitmentsDb = mock(); - blockHashData = ConstantHistoricBlockData.empty(); - executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, blockHashData); + blockData = ConstantHistoricBlockData.empty(); + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, blockData); }, 10000); describe('PublicToken contract', () => { diff --git a/yarn-project/circuits.js/src/cbind/constants.gen.ts b/yarn-project/circuits.js/src/cbind/constants.gen.ts index 0009fe2bc65..21579add518 100644 --- a/yarn-project/circuits.js/src/cbind/constants.gen.ts +++ b/yarn-project/circuits.js/src/cbind/constants.gen.ts @@ -51,7 +51,7 @@ export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; export const CALL_CONTEXT_LENGTH = 6; -export const BLOCK_HASH_DATA_LENGTH = 7; +export const BLOCK_DATA_LENGTH = 7; export const FUNCTION_DATA_LENGTH = 4; export const CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; diff --git a/yarn-project/noir-libs/noir-aztec/src/abi.nr b/yarn-project/noir-libs/noir-aztec/src/abi.nr index 428eb913b1b..f1b8df05536 100644 --- a/yarn-project/noir-libs/noir-aztec/src/abi.nr +++ b/yarn-project/noir-libs/noir-aztec/src/abi.nr @@ -10,7 +10,7 @@ use crate::constants_gen::{ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, GENERATOR_INDEX__FUNCTION_ARGS, - BLOCK_HASH_DATA_LENGTH, + BLOCK_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, CALL_CONTEXT_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, @@ -35,7 +35,7 @@ use crate::types::point::Point; // PrivateContextInputs are expected to be provided to each private function struct PrivateContextInputs { call_context : CallContext, - block_hash_data: BlockHashData, + block_data: ConstantBlockData, contract_deployment_data: ContractDeploymentData, @@ -45,7 +45,7 @@ struct PrivateContextInputs { // PublicContextInputs are expected to be provided to each public function struct PublicContextInputs { call_context: CallContext, - block_hash_data: BlockHashData, + block_data: ConstantBlockData, public_global_variables: PublicGlobalVariables, } @@ -77,7 +77,7 @@ impl CallContext { } } -struct BlockHashData { +struct ConstantBlockData { private_data_tree_root : Field, nullifier_tree_root : Field, contract_tree_root : Field, @@ -87,9 +87,9 @@ struct BlockHashData { public_data_tree_root: Field, } -impl BlockHashData { +impl ConstantBlockData { // NOTE: this order must match the order in `private_circuit_public_inputs.hpp` - fn serialize(self) -> [Field; BLOCK_HASH_DATA_LENGTH] { + fn serialize(self) -> [Field; Block_DATA_LENGTH] { [ self.private_data_tree_root, self.nullifier_tree_root, @@ -102,8 +102,8 @@ impl BlockHashData { } } -fn empty_block_hash_data() -> BlockHashData { - BlockHashData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } +fn empty_block_data() -> ConstantBlockData { + ConstantBlockData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } } struct ContractDeploymentData { @@ -190,7 +190,7 @@ struct PrivateCircuitPublicInputs { unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, - block_hash_data: BlockHashData, + block_data: ConstantBlockData, contract_deployment_data: ContractDeploymentData, chain_id: Field, version: Field, @@ -213,7 +213,7 @@ impl PrivateCircuitPublicInputs { fields.push_array(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.block_hash_data.serialize()); + fields.push_array(self.block_data.serialize()); fields.push(self.contract_deployment_data.hash()); fields.push(self.chain_id); fields.push(self.version); @@ -236,7 +236,7 @@ impl PrivateCircuitPublicInputs { fields.push_array(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.block_hash_data.serialize()); + fields.push_array(self.block_data.serialize()); fields.push_array(self.contract_deployment_data.serialize()); fields.push(self.chain_id); fields.push(self.version); @@ -296,7 +296,7 @@ struct PublicCircuitPublicInputs { new_l2_to_l1_msgs: [Field; crate::abi::MAX_NEW_L2_TO_L1_MSGS_PER_CALL], unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: Field, - block_hash_data: BlockHashData, // TODO: This is not present in cpp or ts, do we need to include it? + block_data: ConstantBlockData, // TODO: This is not present in cpp or ts, do we need to include it? historic_public_data_tree_root: Field, prover_address: Field, } @@ -319,8 +319,8 @@ impl PublicCircuitPublicInputs { inputs.push_array(self.new_nullifiers); inputs.push_array(self.new_l2_to_l1_msgs); - // We do not include block_hash_data since it's not in the cpp hash - // inputs.push(self.block_hash_data.hash()); + // We do not include block_data since it's not in the cpp hash + // inputs.push(self.block_data.hash()); inputs.push_array(self.unencrypted_logs_hash); inputs.push(self.unencrypted_log_preimages_length); @@ -347,7 +347,7 @@ impl PublicCircuitPublicInputs { fields.push_array(self.new_l2_to_l1_msgs); fields.push_array(self.unencrypted_logs_hash); fields.push(self.unencrypted_log_preimages_length); - fields.push_array(self.block_hash_data.serialize()); + fields.push_array(self.block_data.serialize()); fields.push(self.historic_public_data_tree_root); fields.push(self.prover_address); fields.storage diff --git a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr index 520d8268fa5..4d17e9c6361 100644 --- a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr +++ b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr @@ -50,7 +50,7 @@ global GET_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 23; global MAX_NOTES_PER_PAGE: comptime Field = 10; global VIEW_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 212; global CALL_CONTEXT_LENGTH: comptime Field = 6; -global BLOCK_HASH_DATA_LENGTH: comptime Field = 7; +global BLOCK_DATA_LENGTH: comptime Field = 7; global FUNCTION_DATA_LENGTH: comptime Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: comptime Field = 6; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 58; diff --git a/yarn-project/noir-libs/noir-aztec/src/context.nr b/yarn-project/noir-libs/noir-aztec/src/context.nr index 0e5c9161335..81eb39cdd50 100644 --- a/yarn-project/noir-libs/noir-aztec/src/context.nr +++ b/yarn-project/noir-libs/noir-aztec/src/context.nr @@ -15,13 +15,13 @@ use crate::constants_gen::{ use crate::abi; use crate::abi::{ - empty_block_hash_data, + empty_block_data, empty_contract_storage_read, empty_contract_storage_update_request, hash_args, CallContext, ContractDeploymentData, - BlockHashData, + ConstantBlockData, FunctionData, PrivateCircuitPublicInputs, PublicCircuitPublicInputs, @@ -118,7 +118,7 @@ impl Context { unencrypted_logs_hash: unencrypted_logs_hash, encrypted_log_preimages_length: encrypted_log_preimages_length, unencrypted_log_preimages_length: unencrypted_log_preimages_length, - block_hash_data: self.inputs.block_hash_data, + block_data: self.inputs.block_data, contract_deployment_data: self.inputs.contract_deployment_data, chain_id: self.inputs.private_global_variables.chain_id, version: self.inputs.private_global_variables.version, @@ -146,7 +146,7 @@ impl Context { // PrivateContextInputs must be temporarily passed in to prevent too many unknowns // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned fn consume_l1_to_l2_message(&mut self, inputs: abi::PrivateContextInputs, msg_key: Field, content: Field, secret: Field) { - let nullifier = process_l1_to_l2_message(inputs.block_hash_data.l1_to_l2_messages_tree_root, inputs.call_context.storage_contract_address, msg_key, content, secret); + let nullifier = process_l1_to_l2_message(inputs.block_data.l1_to_l2_messages_tree_root, inputs.call_context.storage_contract_address, msg_key, content, secret); // Push nullifier (and the "commitment" corresponding to this can be "empty") self.push_new_nullifier(nullifier, EMPTY_NULLIFIED_COMMITMENT) @@ -214,7 +214,7 @@ impl Context { unencrypted_logs_hash: arr_copy_slice(fields, [0; NUM_FIELDS_PER_SHA256], 44), encrypted_log_preimages_length: fields[46], unencrypted_log_preimages_length: fields[47], - block_hash_data: BlockHashData { + block_data: ConstantBlockData { // Must match order in `private_circuit_public_inputs.hpp` private_data_tree_root : fields[48], nullifier_tree_root : fields[49], @@ -308,7 +308,7 @@ impl Context { new_l2_to_l1_msgs:[0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], unencrypted_logs_hash:[0; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: 0, - block_hash_data: empty_block_hash_data(), + block_data: empty_block_data(), historic_public_data_tree_root: 0, prover_address: 0, }, diff --git a/yarn-project/noir-libs/noir-aztec/src/messaging.nr b/yarn-project/noir-libs/noir-aztec/src/messaging.nr index d74a8f31ff1..d3e5185de1f 100644 --- a/yarn-project/noir-libs/noir-aztec/src/messaging.nr +++ b/yarn-project/noir-libs/noir-aztec/src/messaging.nr @@ -10,7 +10,7 @@ use crate::oracle::get_l1_to_l2_message::get_l1_to_l2_message_call; // TODO(Maddiaa): Where to put this code?, a context would make sense but public calls dont _really_ have one? - come back to. fn consume_l1_to_l2_message_public(pub_context: PublicContextInputs, msg_key: Field, content: Field, secret: Field) { - let nullifier = process_l1_to_l2_message(pub_context.block_hash_data.l1_to_l2_messages_tree_root, pub_context.call_context.storage_contract_address, msg_key, content, secret); + let nullifier = process_l1_to_l2_message(pub_context.block_data.l1_to_l2_messages_tree_root, pub_context.call_context.storage_contract_address, msg_key, content, secret); // Push nullifier create_nullifier(nullifier); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index e01459b5b14..4b6fd6d5b39 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -61,15 +61,15 @@ export class PublicProcessorFactory { prevGlobalVariables: GlobalVariables, globalVariables: GlobalVariables, ): Promise { - const blockHashData = await getconstantHistoricBlockData(this.merkleTree, prevGlobalVariables); + const blockData = await getconstantHistoricBlockData(this.merkleTree, prevGlobalVariables); return new PublicProcessor( this.merkleTree, - getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource, blockHashData), + getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource, blockData), new WasmPublicKernelCircuitSimulator(), new EmptyPublicProver(), this.contractDataSource, globalVariables, - blockHashData, + blockData, ); } } @@ -86,7 +86,7 @@ export class PublicProcessor { protected publicProver: PublicProver, protected contractDataSource: ContractDataSource, protected globalVariables: GlobalVariables, - protected blockHashData: ConstantHistoricBlockData, + protected blockData: ConstantHistoricBlockData, private log = createDebugLogger('aztec:sequencer:public-processor'), ) {} @@ -118,7 +118,7 @@ export class PublicProcessor { */ public makeEmptyProcessedTx(): Promise { const { chainId, version } = this.globalVariables; - return makeEmptyProcessedTx(this.blockHashData, chainId, version); + return makeEmptyProcessedTx(this.blockData, chainId, version); } protected async processTx(tx: Tx): Promise { diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index e5f23d0c80e..6a397b79bc8 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -21,13 +21,13 @@ export function getPublicExecutor( merkleTree: MerkleTreeOperations, contractDataSource: ContractDataSource, l1toL2MessageSource: L1ToL2MessageSource, - blockHashData: ConstantHistoricBlockData, + blockData: ConstantHistoricBlockData, ) { return new PublicExecutor( new WorldStatePublicDB(merkleTree), new ContractsDataSourcePublicDB(contractDataSource), new WorldStateDB(merkleTree, l1toL2MessageSource), - blockHashData, + blockData, ); } From 02d4e8518f9d8d55de2e60fa2263dee1725196fb Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:44:25 +0000 Subject: [PATCH 54/58] review fixes --- yarn-project/acir-simulator/src/public/db.ts | 6 ------ .../aztec-rpc/src/simulator_oracle/index.ts | 15 --------------- .../src/abis/ecdsa_account_contract.json | 2 +- .../schnorr_multi_key_account_contract.json | 2 +- .../schnorr_single_key_account_contract.json | 2 +- .../src/integration_l1_publisher.test.ts | 6 +++--- yarn-project/noir-libs/noir-aztec/src/abi.nr | 2 +- .../block_builder/solo_block_builder.test.ts | 8 ++++---- .../src/sequencer/public_processor.ts | 4 ++-- .../sequencer-client/src/sequencer/utils.ts | 2 +- .../src/simulator/public_executor.ts | 17 ----------------- 11 files changed, 14 insertions(+), 52 deletions(-) diff --git a/yarn-project/acir-simulator/src/public/db.ts b/yarn-project/acir-simulator/src/public/db.ts index 3cb190e3e3a..13c5682d056 100644 --- a/yarn-project/acir-simulator/src/public/db.ts +++ b/yarn-project/acir-simulator/src/public/db.ts @@ -71,10 +71,4 @@ export interface CommitmentsDB { * @returns - The Commitment data oracle object */ getCommitmentOracle(address: AztecAddress, commitment: Fr): Promise; - - /** - * Gets the current historic block data from the merkle db. - * @returns the previous blocks roots and global variables hash. - */ - getHistoricBlockData(): ConstantHistoricBlockData; } diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 2874ea7c0ac..52d5f833cc9 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -102,19 +102,4 @@ export class SimulatorOracle implements DBOracle { }); } - getHistoricBlockData(): ConstantHistoricBlockData { - const roots = this.db.getTreeRoots(); - - return ConstantHistoricBlockData.from({ - privateKernelVkTreeRoot: Fr.ZERO, - // TODO: work out how to get the previous globals hash in here - prevGlobalVariablesHash: Fr.ZERO, - privateDataTreeRoot: roots[MerkleTreeId.PRIVATE_DATA_TREE], - contractTreeRoot: roots[MerkleTreeId.CONTRACT_TREE], - nullifierTreeRoot: roots[MerkleTreeId.NULLIFIER_TREE], - l1ToL2MessagesTreeRoot: roots[MerkleTreeId.L1_TO_L2_MESSAGES_TREE], - blocksTreeRoot: roots[MerkleTreeId.BLOCKS_TREE], - publicDataTreeRoot: roots[MerkleTreeId.PUBLIC_DATA_TREE], - }); - } } diff --git a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json index 40ba33f0262..6b9d14f4b01 100644 --- a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json @@ -152,7 +152,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json index 2c7efe755ec..585a7198c47 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_multi_key_account_contract.json @@ -140,7 +140,7 @@ } ], "returnTypes": [], - "bytecode": "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", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json index 23c2a5e18d0..7c6243b45be 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json @@ -95,7 +95,7 @@ } ], "returnTypes": [], - "bytecode": "H4sIAAAAAAAA/+1dB3gU5dPfuxSKFAGV3kSkw20IEHroTXrvQkhoIfTeu4iI9N4VEVEBETv23lCkdwEBEXv5KwLfDJmVvTeh3rznznd7zzPPbycc7017fzO3t3dbM8IwJoUbVx4eEC9IOB1beoSiR9JxRPJ/M+i/G/eAZAfJAZLT9v+sf88FkhskD0he+nev7d/zgeQHKQBS0PZ6hUDS2vT7FL2wot+v6EUUvaiiF1P04opeQtFLKnopRS+t6GUU3afopqJHKXpZRY9W9HKKXl7RKyh6jKJXVPRKil5Z0asoelVFr6bo1RU9VtFrKHpNRa+l6LUVvY6i11X0eopeX9EbKHpDRW+k6A8oemNFb6LoTRW9maI3V/QWit5S0VspemtFb6PobRW9naK3V/QOit5R0TspemdF76LoXRX9QUXvpujdSUd+CDOS6wUfyAO493G/4x7HfV3USN6/uGdxn+LexP2IexD3He413F+4p3Af4d7B/YJ7BPcF7gWsf6x5rHOsbaxnrOHq9NpYn1iTWIdYe1hvWGNYV1hLWD9YM1gnWBtYD1gDTSnXzSmnLSl3rSlHbSkX7SnmHSm2nSmGXSlW3SgmVnzilHj1UPR4RU9Q9J6K3kvReyt6H0Xvq+iJit5P0ZMUvb+iD1D0gYo+SNEHK/oQRR+q6MMUfbiij1D0kYo+StFHK/oYRR+r6OMUfbyiT1D0iYo+SdEnK/oURZ+q6NMUfbqiP6ToMxT9YUWfqeiPKPosRX9U0Wcr+mOKPkfR5yr6PEWfr+gLFH2hoi9S9MWKvkTRlyr6MkVfrugrFH2loq9S9NWKvkbR1xpX+RBnpVgj+YE8gHsf9zvucdzXvYzk/Yt7Fvcp7k3cj7gHcd/hXsP9hXsK9xHuHdwvuEdwX+BewPrHmsc6x9rGesYaxrqdYCTXJ9Yk1iHWHtYb1hjWFdYS1g/WDNYJ1gbWA9bAbMr1HMrpPMrdAsrRIsrFEor5MortCorhKorVGooJxgdn0QIUD5w/LxnJMyhiDsKchLkIcxPmIcxLmI8wP2EBwoKE9xIWIryPsDDh/YRFCIsSFiMsTliCsCRhKcLShGUIfYQmYRRhWcJownK29R4HeSKV2JSn51QgjCGsSFiJsDJhFcKqhNUIqxPGEtYgrElYi7A2YR3CuoT1COsTNiBsSNiI8AHCxoRNCJsSNiNsTtiCsCVhK8LWttisB3kyldi0oee0JWxH2J6wA2FHwk6EnQm7EHYlfJCwG2F3wjjCHoTxhAmEPQl7EfYm7EPYlzCRsB9hEmF/wgGEAwkHEQ4mHEI41BabDSBPpRKbYfSc4YQjCEcSjiIcTTiGcCzhOMLxhBMIJxJOIpxMOIVwKuE0wumEDxHOIHyYcCbhI4SzCB8lnE34GOEcwrmE8wjnEy6wxWYjyNOG/8NDGEtY1lc+Ojq+QlS8Wdbs5ouq2D2mnC+6XPfyMWaMWS6mXI+omLJl42OiYypU7F6xgq+iGV023kwoV7Fsgi/5scm2li/Ah047nxFi57NC7HxOiJ2bhdi5RYidW4XY+bwQO7cJsfMFIXZuF2Lni0LsfEmInS8LsfMVIXa+KsTO14TY+Tqjnep7HTwHgTP/IsLFhEsIlxIuI1xOuIJwJeEqwtWEawjXEq4j3ET4DOGzhM8RbibcQriV8HnCbYQvEG4nfJHwJcKXCV8hfJXwNcLXjavvdXaAvGH4P7hz+KYho9beEmLn20LsfEeIne8KsfM9IXa+L8TOD4TY+aEQOz8SYufHBv9McSeth+fjsbeuJ9xAuJFwB+GbhG8Rvk34DuG7hO8Rvk/4AeGHhB8Rfmxc7emfgHxqXD23m5FsC9bnJYifgXxuJH+e5TWunUtfYA/zM761fAVonS9AdoJ8CfIVyC6Qr0F2g+wB2QuyD2Q/yAGQgyCHQA6DHAE5CnIM5DjINyAnQE6CnAL5FuQ0yBmQsyDfgZwD+R7kPMgPFCTrs0C0xf7Z4E5F/1LRv1L0XYr+taLvVvQ9ir5X0fcp+n5FP6DoBxX9kKIfVvQjin5U0Y8p+nFF/0bRTyj6SUU/pejfKvppRT+j6GcV/TtFP6fo3yv6eUX/gXT7I4wwltAX2MNvzwTKpV8wrlUiXE//UON3u3bGJ+DDZ+5kWgtz8SVj/Eo6Pn5Xlja/CnytKPLZ3MUYv1JOjl/0v3aaXwe2ls/ms7mbMX6lnRq/KD87zT23v5ZP8dncyxi/Mg6MX/mEFHaa+25vrZhUfDb3M8bP57T4xaRqp3ng1teqcA2fzYOM8TOdFL8K17TTPHRra0Vdx2fzMGP8opwSvwrXtdM8cvNrxd3AZ/MoY/zKOiF+FW5op3ns5tby3YTP5nHG+EX/1/Hz3ZSd5jc3XqvcTfpsnmCMX7n/Mn7RN22nefK6a0Un3ILP5inG+JX/r+JX4ZbsNL+99loxt+izeZoxfhX+g/hVTLhlO80zqa/luw2fzbOM8YsJdvx8t2Wn+V3Ktczb9Nk8xxi/isGMX4/bttP83n+tsgH4bJ5njF+lIMUvKiEgO80fDL5zifZzdoHGr3KQ4ucL7GEynmczSzHGr4qQ+DGeJzLLMMavqpD4MZ7nME3G+FUTEj/G9+lmWcb4VRcSP8b3mWY5xvjFCokf4/skswJj/GoIiR/jnG9WZIxfTSHxY5xTzcqM8aslJH6Mc5ZZlTF+tYXEj3FOMKszxq+OkPgx9jmzBmP86gqJHyNPm7UY41dPSPwYecaswxi/+kLix7hPTMaaMYMWP9MX0KOQfy4CWu0+g6/+egaz/gLwurCRws7bXu1+xvj1Cvb+vU2vixip2nlbqxVljF/v/4L/bsPrYsY17bzl1Yozxq/Pf9U/btHrEsZ17byl1Uoyxq/vf9l/b8HrUsYN7bzp1Uozxi/xv55fbtLrMsZN2XlzqzHGr58T5r+b8No0btrOG64WxRi/JKfMzzfwuqxxS3Zed7Voxvj1d9L7j+t4Xc64ZTuvuVp5xvgNcNr7t2t4XcG4LTtTXS2GMX4Dnfj+NxWvKxq3bWeK1Soxxm+QU88fKF5XNgKy02+1KozxG+zk8y82r6saAdv572rVGOM3xOnnr8jr6gaLnVdWi2WM31AJ5//A6xoGm51mTcb4DRNy/pTxPJvZi/H883Ah8WM8T2T2YYzfCCHxYzzPYSYyxm+kkPgxvk83kxjjN0pI/BjfZ5oDGOM3Wkj8GN8nmYMY4zdGSPwY53xzCGP8xgqJH+Ocag5jjN84IfFjnLPMEYzxGy8kfoxzgjmKMX4ThMSPsc+ZYxjjN1FI/Bh52hzHGL9JQuLHyDPmBMb4TRYSP8Z9Yk5ijN8UJ/z+wU3Y+SNjLhhrxgxW/AK9fq2WwXf9Wm3GvK4Tcv1aHYPv+rW6jPF7XMj1a/UMvuvX6jPG7wkh1681MPiuX2vIGL/1Qq5fa2TwXb/2AGP8nhRy/Vpj44Z23vRqTRjjt0HI9WtNjZuy86ZWa8YYv6eEXL/W3LhpO2+4WgvG+G0Ucv1aS+OW7Lzuaq0Y4/e0kOvXWhu3bOc1V2vDGL9NQq5fa2vclp2prtaOMX7PCLl+rb1x23amWK0DY/yeFXL9WkcjIDv9VuvEGL/nhFy/1tkI2M5/V+vCGL/NQq5f62qw2HlltQcZ47dFyPVr3Qw2O83ujPHbKuT8M+N5NvNxxvPPzwuJH+N5InM9Y/y2CYkf43kOcwNj/F4QEj/G9+nmRsb4bRcSP8b3meYmxvi9KCR+jO+TzGcZ4/eSkPgxzvnmZsb4vSwkfoxzqrmVMX6vCIkf45xlbmOM36tC4sc4J5jbGeP3mpD4MfY58yXG+L0uJH6MPG2+whi/HULix8gz5muM8XtDSPwY94m5gzF+bwq5fu0nxlww1ozJGT+8n2gECF6rh/fk/YnQWj/OSL7PaA/CeMIEwp6EvQh7E/Yh7EuYSNiPMImwP+EAwoGEgwgHEw4hHEo4jHA44QjCkYSjCEcTjiEcSziOcDzhBMKJhJMIJxNOIZxKOI1wOuFDhDMIHyacSfgI4SzCRwlnEz5GOIdwLuE8wvmECwgXEi4iXEy4hHAp4TLC5YQrCFcSriJcTbiGcC1hASP5Yd1v1roPrXV/Wuu+tdb9bK373J4htO6La90v17qP7knCE4TfEFr36T1GaN3X17rfr3UfYOv+wNZ9g637CVv3GbbuP2zdl9i6X7F1H2Pr/sbWfY+t+yFb90neSWjdV/lnw//hJYwl9AX2MH82+HjrF8a1kFM9RsoH9/25fzF4Oc16/Go7Dldyhw+rZ0Rq8MlQXkeNY6ZU/sb64jqS9KuGdX8z+ApWl9+/8efIb3hxekytB/eQ9TujzxK/JBBo/P4wQmNIjbTFDmsGh9Q/CNcRZgb5E+R/hv+DO+Zexpj/yWjXX3x2Ba3xc9pst/dv27Hb+ANc8y8KKPe6FwxnN370+wJ/jrQ2fs6YBosE8hl6SOAf27FLAgGumY8Cyr3uRcPZJIB+X+TP0ZXNFWakfDh5c+m0M5cQO+8x+MnKY1sTJ9nL9EcPiBckDCQcJAIkEiQNSFqQdCDpQe4AyQCSESQTSGaQO0GygGQFyQZyF8jdIPeAZAfJAZITJBdIbpA8IHlB8oHkBykAUhDkXpBCIPeBFAa5H6QISFGQYiDFQUqAlAQpBVIapAwIOmeCRIGUBYkGKQdSHqQCSAxIRZBKIJVBqoBUtTFiZsJ0Rkryxr+FKflNZ/iTOz4ibcexTDnT0Cx8eAo+rc0PQ/E3E/kSyfq60T58rQjD/6E2pdhU4om2ZqPjuG6Jic0G9R7WbUh83aFJcUN690+yl3WEskxYKu6pfw+3hSINHUfY/mb9vzQ29Kj2xxIG2lPs/ckX2MMMFufjgkxr+VIxl2vtKI1rm/biqkYBrm4rbmufeY2rBRVpy4eVJyzGy0bKXHlsx156Tth1nuO5xjr2/W79f2u/M8dEC3dpHWQ9FFxM4EV6IdQxkeqLcn9+bt9Et0si8QnJj2oePkKqzri5g0VIHpeQ/AgplgJcwyUkmYQUqxBSjSAQkoeRkGIZCamGQELyuoTkR0g1KcC1XEKSSUg1FUKqFQRC8jISUk1GQqolkJAiXULyI6TaFOA6LiHJJKTaCiHVCQIhRTISUm1GQqojkJDSuITkR0h1KcD1XEKSSUh1FUKqFwRCSsNISHUZCameQEJK6xKSHyHVpwA3cAlJJiHVVwipQRAIKS0jIdVnJKQGAgmpqktIfoTUkALcyCUkmYTUUCGkRkEgpKqMhNSQkZAaadrc3PGzX94VqM+XGNd6gJnQUxS/wU/onDbb7W1sU9zrUANcE5PU2MO/bhNG8tDldxMPe478yMmrrM157VSgazX1OLsuMTdNPfzXnx0V8nMTnLluxpjro4w/XRGsRtRMUyNq7jYi3iQ119CIWji8EaHfLTQ3IqfH1LAVMqed9i9BBGrnZca1Wgqc5ltqItFWLonyJqmVBhJt7XASRb9bh/A038bh0zzmpo2Gaf54CE7zbRlzfVzgNN9WUyNq5zYi3iS109CI2ju8EaHf7YVN89wxNWyFzGmn/avCgdqZjtHnDgKn+Q6aSLSjS6K8SeqogUQ7OZxE0e9OITzNd3b4NI+56axhmj8RgtN8F8ZcnxA4zXfR1Ii6uo2IN0ldNTSiBx3eiNDvB4VN85wxDRYJNNJEAt1cEuBNUjcNJNDd4SSAfncP4Wk0zuHTKOYmTsM0eioEp9EejLk+JXAa7aGpEcW7jYg3SfEaGlGCwxsR+p0gbBrljGmwSKCOJhLo6ZIAb5J6aiCBXg4nAfS7VwhPo70dPo1ibnprmEZPh+A02ocx16cFTqN9NDWivm4j4k1SXw2NKNHhjQj9ThQ2jXLGNFgkUE8TCfRzSYA3Sf00kECSw0kA/U4K4Wm0v8OnUcxNfw3T6NkQnEYHMOb6rMBpdICmRjTQbUS8SRqooRENcngjQr8HCZtGOWMaLBJooIkEBrskwJukwRpIYIjDSQD9HhLC0+hQh0+jmJuhGqbRcyE4jQ5jzPU5gdPoME2NaLjbiHiTNFxDIxrh8EaEfo8QNo1yx9SwFbLdTifdLjyM0eeRjIQULBIdqYlER7kkypukURpIdLTDSRT9Hh3C0/wYh0/zmJsxGqb58yE4zY9lzPV5gdP8WE2NaJzbiHiTNE5DIxrv8EaEfo8XNs1zx9SwFbLdzkDXzsfoczijzxMETvMTNJHoRJdEeZM0UQOJTnI4iaLfk0J4mp/s8GkeczNZwzT/YwhO81MYc/2jwGl+iqZGNNVtRLxJmqqhEU1zeCNCv6cJm+Y5Y4q24QaxNhD+rjHeqaS6JxlrENYiTA8yHY4folqJNK7e5ieMnhNOGEFYh7AeYQPCLCAz4PjhVNYqR88pT1iBMIawImElwgwgM+H4EdtaVhJm0HPSWT4Q3mH9X8KMhJkIMxPeadlLmJUwG+FdhHcT3kOYnTAHYU7CXIS5CfMQ5iXMR5ifsABhQcJ7CQsR3kdYmPB+wiKERQmLERYnLEFYkrAUYWnCMoQ+QpMwirAsYTThTMLKhFWs1wOZBceP2nJjkfMlkun03FlWjEFmw/FjCos6eaibw9jog9Wc8xt6mvNctznzJmmuhuY8z+HNGf2ep6E5B+sehpybS6eduYXYmd3gJyuPbc35oCwAWQiyCGQxyBKQpSDLQJaDrABZCbIKZDXIGpC1IOtAHgd5AmQ9yJMgG0CeAtkI8jTIJpBnQJ4FeQ5kM8gWkK0gz4NsA3kBZDvIiyAvgbwM8grIqyCvgbwOsgPkDZA3Qd4CeRvkHZB3Qd4DeR/kA5APQT4C+RjkE5BPQT4D+RzkC5CdIF+CfAWyy7bPMhPifR1V8k5npLxHZDrDn9zxIeXejxGwRlqbH4bir3Ufy0jW14324WtFGP4PtSnFphJPtDUbHcd1S0xsNqj3sG5D4usOTYob0rv/v9++8tiWt5YJS8U99e/htlCkoeMI29+s/5fGhh7V/ljCQHvKPOaBKhicv9Cjh0sNXjuDdt/arynAu23F7d63lmfNoNy3FhNov2/tbk/KF+U+/bqQYTC17lv7NeOQu5txcweLkBa5hORHSHsowHtdQpJJSHsUQtobBEJaxEhIexgJaa9AQlrsEpIfIe2jAO93CUkmIe1TCGl/EAhpMSMh7WMkpP0CCWm5S0h+hHSAAnzQJSSZhHRAIaSDQSCk5YyEdICRkA4KJKQVLiH5EdIhCvBhl5BkEtIhhZAOB4GQVjAS0iFGQjoskJBWuoTkR0hHKMBHXUKSSUhHFEI6GgRCWslISEcYCemoQELa5RKSHyEdowAfdwlJJiEdUwjpeBAIaRcjIR1jJKTjmjY3d/zsl3cF6vN8xvh9w0zoKYrf4Cd0Tpvt9p6wKe51qAGuiUk64eFf9yRj8evy+6SHPUdav63IeW3vKY+z6xJzc8rDf/3Zz0K+rciZ628Zc/2zwG8rfqupEZ12GxFvkk5raERnHN6I0O8zmhuR02Nq2AqZ0077lyACtXMBo89nBU7zZzWR6HcuifIm6TsNJHrO4SSKfp8L4Wn+e4dP85ib7zVM87+G4DR/njHXvwqc5s9rakQ/uI2IN0k/aGhEPzq8EaHfPwqb5rljatgKmdNO+1eFA7VzFaPPPwmc5n/SRKI/uyTKm6SfNZDoLw4nUfT7lxCe5n91+DSPuflVwzT/ewhO878x5vp3gdP8b5oa0e9uI+JN0u8aGtEfDm9E6PcfwqZ5zpgGiwSOayKBP10S4E3SnxpI4H8OJwH0+38hPI3+5fBpFHPzl4Zp9M8QnEb/Zsz1nwKn0b81NaILbiPiTdIFDY3oH4c3IvT7H2HTKGdMg0UCBzWRwEWXBHiTdFEDCVxyOAmg35dCeBq97PBpFHNzWcM0+lcITqNYiFx2/SVwGmX0368ReWxdx21Ega7pTQ4o97per7MbEfrt9bLnSOs0yhnTYJHAYU3TaJhLArxJCtNAAuEOJwH0O1wzCTh5Go3wOrsuMTcRXv5p9EIITqORjLm+IHAaZfTfrxGlcRsRb5LSaGhEaR3eiNDvtMKmUc6YBosEjmqaRtO5JMCbpHQaSCC9w0kA/U4fwtPoHQ6fRjE3d2iYRi+G4DSagTHXFwVOo4z++zWijG4j4k1SRg2NKJPDGxH6nUnYNModU8NWyHY7A13by+jzEkZCzsxISMEi0cyaSPROl0R5k3SnBhLN4nASRb+zhPA0n9Xh0zzmJquGaf5yCE7z2RhzfVngNJ9NUyO6y21EvEm6S0MjutvhjQj9vlvYNM8dU8NWyHY7A107P6PPSxkJ+R6B0/w9mkg0u0uivEnKroFEczicRNHvHCE8zed0+DSPucmpYZr3RITeNJ+LMdf2+EmZ5nNpakS53UbEm6TcGhpRHoc3IvQ7j7BpnjOmaBtuEGsD4e8aXwLcTbiXcD9hepC88Pr5qFYijau3+VlCz1lKuIzwIOFhwqOEWUDywzoFUlnrE3rOp4SfEX5O+AXhTsIMIAVhnXtta1lJwNfA56yi564mXEO4lnAd4eOETxCuJ3yScAPhU4QbCZ8m3ET4DOGzhM8RbibcQriV8HnCbYQvEG4nfJHwJcKXCV8hfJXwNcLXCXcQvkH4JuFbhG8TvkP4LuF7hO8TfkD4IeFHhB8TFqQ4f0n6V4TFQQrBv91ny41FzvPpOXnp/xYizApSGI7v9yY/92ZuORbwhQOGngZhKHb6bu1hqn9gXDvFa9kbaBFSitr+6N5yjGfNoNxyDBO4g14I9aK2xqEGz/o75ya6xbV8ylpmEcZGV5RxCg/WPRADsTnB/xGXirlaCImblO3vxHyBPfzIrRgpxW+T3Gqm4rNKbjWNG5Nbauv8vyI3JxeERYzFvFcTgzoWRQ3D/8FNlJx+FGckyhJePmKw4lnCFk8d9VDUG3B+1OZTjjM/RRnzE8Z8Ci3AzZ8i5xg3az9x5jncWX6rjyunDItr8DsiSKdMAx3WijHWOCefRQo55cy4r81wxtPEaYTEj3GfmIw1YwYSv+sN8d7A9m+KPHPu35KMb7Z0+sz5MU8pZp+5+xPmpJSG/pQxBD/SK82Y64wCP9Jj9N/vI70y3qvH7kd6Aa6JSSrj5V/Xx9godPnt87LnSOtHek6P6WxYcI6Hv3mY3uDkJ1A7o4TYWVaIndGMdkL/NFCshoE1hfnCWETbu4fBP0BeZFyrHONQEU4xUR9c61+rLnyBPcxyGuqX28bCQvZYeUY7NdeTtlyVF1BPFTTVk5PfLMc4/M2yrnmnohDuqCSnF2nbl5UEcEflEOSOKszcca3cBGpnVT47o6TuoaoC9lC1ENxD1YXsoVg+O8tK3UOxAvZQjRDcQzUZ91CwTtwX4FvL78R9Le/VY/fEfYBrFqCAcq9b2+EnmdHv2hpO3Afrct0Chh4S5LYzjxA7cxj8ZIWYgY7rQK3VBakHUh+kAUhDkEYgD4A0BmkC0hSkma0uMxPiZboq2aUzUl7ym87wJ0N8SLmUFwemtDY/DMVf67LkSN7XjcPXUoc1lcRjU4kn2pqTjuOTBg6NHxrfbGj3xN5xdYcmxQ3p3T+pVrfERHsxWC9iFUVYKk6qfw+3BSQNHUfY/mb9vzQ21HY9dG3mMSQYTFlP07ho8NoZpXFtvy8jNCelhe2P7jeteNYMyjetMIEXjatfIGjhTfmi3Bc01WMY5+LpysLmjKNhC8bNHSxCqu8Skh8htSSllUtIMgmppUJIrYJASPUZCaklIyG1EkhIDVxC8iOk1qS0cQlJJiG1VgipTRAIqQEjIbVmJKQ2AgmpsUtIfoTUlpR2LiHJJKS2CiG1CwIhNWYkpLaMhNROICE1cQnJj5Dak9LBJSSZhNReIaQOQSCkJoyE1J6RkDoIJKSmLiH5EVJHUjq5hCSTkDoqhNQpCITUlJGQOjISUidNm5s7fgUMPp/rMMavMzOhpyh+g5/QOW2229vFRojuxVIBrolJ6uLlX7crY/Hr8rurlz1HWq++5LwA7UGvs+sSc/Ogl/9yj8xCfm6DM9fdGHOdWeDPbTD679eIuruNiDdJ3TU0ojiHNyL0O05zI3J6TA1bIXPaab9SN1A76zL63EPgNN9DE4nGuyTKm6R4DSSa4HASRb8TQnia7+nwaR5z01PDNJ8lBKf5Xoy5ziJwmmf0368R9XYbEW+SemtoRH0c3ojQ7z7CpnnumBq2Qua00/59tkDtbMboc1+B03xfTSSa6JIob5ISNZBoP4eTKPrdL4Sn+SSHT/OYmyQN03y2EJzm+zPmOpvAaZ7Rf79GNMBtRLxJGqChEQ10eCNCvwcKm+Y5YxosEminiQQGuSTAm6RBGkhgsMNJAP0eHMLT6BCHT6OYmyEaptG7Q3AaHcqY67sFTqOM/vs1omFuI+JN0jANjWi4wxsR+j1c2DTKGdNgkUAHTSQwwiUB3iSN0EACIx1OAuj3yBCeRkc5fBrF3IzSMI1mD8FpdDRjrrMLnEYZ/fdrRGPcRsSbpDEaGtFYhzci9HussGmUM6bBIoFOmkhgnEsCvEkap4EExjucBNDv8SE8jU5w+DSKuZmgYRrNGYLT6ETGXOcUOI0y+u/XiCa5jYg3SZM0NKLJDm9E6PdkYdMod0wNWyHb7Qx0bS+jzw0ZfZ7CSEjBItEpmkh0qkuivEmaqoFEpzmcRNHvaSE8zU93+DSPuZmuYZrPHYLT/EOMuc4tcJpn9N+vEc1wGxFvkmZoaEQPO7wRod8PC5vmuWNq2ArZbmegaxdg9LkRo88zBU7zMzWR6CMuifIm6RENJDrL4SSKfs8K4Wn+UYdP85ibRzVM83lDcJqfzZjrvAKneUb//RrRY24j4k3SYxoa0RyHNyL0e46waZ4zpmgbbhBrA+EvyV0ykm9yidiKsA1hepC5cDyPasV+f+CG9JxGhA8QtiPsQNiJMAvIfDheYN+1Bn/TWegNTl4DtXOREDsXMxM61o9F1gupNhYRLibEH/VfAsdLNdfKMiE5WC7EzhUaa2UZ1cZywhW2WlkJx6s018pqITlYI8TOtRprZTXVxhrCtbZaWQfHj2uulSeE5GC9EDuf1FgrT1BtrCd80lYrG+D4Kc21slFIDp4WYucmjbWykWrjacJNtlp5Bo6f1VwrzwnJwWYhdm7RWCvPUW1sJtxiq5WtcPy85lrZJiQHLwixc7vGWtlGtfEC4XZbrbwIxy9prpWXheTgFSF2vqqxVl6m2niF8FVbrbwGx69rrpUdQnLwhoYcWKHdQTF/gzAtyJtw/Jbm2L8tJPbvaIz92xTzd2yxfxeO39Mc+/eFxP4DjbF/n2L+gS32H8LxR5pj/7GQ2H+iMfYfU8w/scX+Uzj+THPsPxcS+y80xv5zivkXttjvhOMvNcf+KyGx36Ux9l9RzHfZYv81HO/WHPs9QmK/V2Ps91DM99pivw+O92uO/QEhsT+oMfYHKOYHbbE/BMeHNcf+iJDYHxVi5zEhdh4XYuc3Quw8IcTOk0LsPCXEzm+F2HlaiJ1nhNh5Void3wmx85wQO78XYud5IXb+IMTOH4XY+ZMQO38WYucvQuz8VYidv2l4D12M1ptP752bER4hPEp4jPA44RLClYTrCDcQPkO4lfBFwtcI3yR8l/BDwk8JdxJ+TbiP8BDhN4QnCE8SniL8lvA04RnCs4TfEZ4j/J7wPOEPhD8S/kT4M+EvhL8S/kZYAuR3OP7De/U6cOvzyDr0nLmEvxNmBfkTjv/nNfweXub64fzyzl98tWgG6ws3BQ3e/WM9/rblzf3CTYBrFqSAcq97gbH4dfl9wcueoyvfZgszUj6cvLl02plXiJ05DX6yQsxAx/9ArV3EBgRy2ZtcJB4QL0gYSDhIBEgkSBpbAWUmxItoVLJLZ1ytNY/tb0pf+/eLUYzx8mkgV1+EkfxhguWHofibyfD/ohfT68bha0UY/g+VxGNTiSfampOO45MGDo0fGt9saPfE3nF1hybFDendP6lWt8REezFYL2IVRVgqTqp/D7cFJA0dR9j+Zv2/NDb0qF7EEgbKxBeYx5BgMOUlTW83DF47ozSubdqLKy0FPZ0t+NZu8xpXCyrSlg/rqViMl42UufLYjr30nLDrPMdzjXXsu976/9auZ46JFgbTOv55KLiYwIv0QqhjItUX5f4hgksM41x8QvID7Q90LYuQ0oXJG90uu4TkR0jpKeh3uIQkk5DSK4R0RxAI6TIjIaVnJKQ7BBKSEeYSkp2QMlDQM7qEJJOQMiiElDEIhGSE8RFSBkZCyiiQkMJdQvIjpEwU9MwuIckkpEwKIWUOAiGFMxJSJkZCyiyQkCJcQvIjpDsp6FlcQpJJSHcqhJQlCIQUwUhIdzISUhaBhBTpEpIfIWWloGdzCUkmIWVVCClbEAgpkpGQsjISUjZNm5s7fgUNPp//8fKtdRczoacofoOf0Dltttt7t40Q3YulAlwTk3R3GP+69zCShy6/7wljz5HWn8nnvAAte5iz6xJzkz2M/3KP/EJ+Jp8z1zkYc51f4M/k59DUiHK6jYg3STk1NKJcDm9E6HcuzY3I6TE1bIXMaaf9St1A7bzISMi5BU7zuTWRaB6XRHmTlEcDieZ1OImi33lDeJrP5/BpHnOTT8M0XzAEp/n8jLkuKHCaz6+pERVwGxFvkgpoaEQFHd6I0O+Cwqb5gkKmefv32QK1Mw2jz/cKnObv1USihVwS5U1SIQ0kep/DSRT9vi+Ep/nCDp/mMTeFNUzzhUJwmr+fMdeFBE7z92tqREXcRsSbpCIaGlFRhzci9LuosGmeM6bBIoHMmkigmEsCvEkqpoEEijucBNDv4iE8jZZw+DSKuSmhYRotHILTaEnGXBcWOI2W1NSISrmNiDdJpTQ0otIOb0Tod2lh02hpgdNoFk0kUMYlAd4kldFAAj6HkwD67QvhadR0+DSKuTE1TKNFQnAajWLMdRGB02iUpkZU1m1EvEkqq6ERRTu8EaHf0cKm0WiB02g2TSRQziUB3iSV00AC5R1OAuh3+RCeRis4fBrF3FTQMI0WC8FpNIYx18UETqMxmhpRRbcR8SapooZGVMnhjQj9riRsGuWOqWErZLudga7tZfTZw+hzZYHX3VbWRKJVXBLlTVIVDSRa1eEkin5XDeFpvprDp3nMTTUN03yJEJzmqzPmuoTAab66pkYU6zYi5iRpaEQ1HN6I0O8awqb5GkKm+YKMPnsZfa4pcJqvqYlEa7kkypukWhpItLbDSRT9rh3C03wdh0/zmJs6Gqb5UiE4zddlzHUpgdN8XU2NqJ7biHiTVE9DI6rv8EaEftcXNs1zxhRtww1ibaAr90w2km9yiXgHYUbC9CAN4Lgh1Yr9/sAeeo6XMIwwM2EWwmyWDtIIjh8IM4zrxStQHxuHBSevgdrZRIidTZkJHevHKoHGVBtNCJsS4o/6N4Pj5pprpYWQHLQUYmcrjbXSgmqjJWErW620huM2mmulrZActBNiZ3uNtdKWaqMdYXtbrXSA446aa6WTkBx0FmJnF4210olqozNhF1utdIXjBzXXSjchOeguxM44jbXSjWqjO2GcrVZ6wHG85lpJEJKDnkLs7KWxVhKoNnoS9rLVSm847qO5VvoKyUGiEDv7aayVvlQbiYT9bLWSBMf9NdfKACE5GCjEzkEaa2UA1cZAwkG2WhkMx0M018pQITkYpiEH1gnnoRTzYYRpQYbD8QjNsR8pJPajNMZ+JMV8lC32o+F4jObYjxUS+3EaYz+WYj7OFvvxcDxBc+wnCon9JI2xn0gxn2SL/WQ4nqI59lOFxH6axthPpZhPs8V+Ohw/pDn2M4TE/mGNsZ9BMX/YFvuZcPyI5tjPEhL7RzXGfhbF/FFb7GfD8WOaYz9HSOznaoz9HIr5XFvs58HxfM2xXyAk9guF2LlIiJ2Lhdi5RIidS4XYuUyIncuF2LlCiJ0rhdi5Soidq4XYuUaInWuF2LlOiJ2PC7HzCSF2rhdi55NC7NwgxM6nhNi5UYidT2t4D12M1mtE753TEC4gXEi4iHAxYTPC1oQdCLsS9iDsTZhEOJhwOOFowvGEkwmnE84knE04j3AJ4VLCZYTLCVcQriRcRbiacA3hWsJ1hI8TPkG4nvBJwg2ETxFuJHyasATIJjh+JuzqdeDWaYh/vMnPaUDP3USYFeRZOH4uLPm5ymkLLbVU28tWS2Yq5t7u2qb6B8a1U7yW17bmZgr6Flvw0xF6javnmv69pt+WJ/yOwGUjZa48tmMvPSfsOs/xXGOddLa/Wf8/k80Wxpj4NHwpyKf1Sz8eCi4mcAe9EOpbbGSpBs/6O+cmusW1fMpa5uYwPru28DUK82YJyRfYwwzE5gT/R1wq5mohJG5SvuDVQ25bKYHP3ya51UzFZ5Xcaho3JrfU1vl/RW5OLgiLGLeGXU0M6lgUNQz/BzdRcvrxPCNRbgvjIwYrntts8dRRD1vCAs6P2nzKceZnC2N+yjB/LT7AzZ8i5xg3az9x5tnnLL/Vx5WfAXheg99mkH4GIdBhbStjjXPyWZSQn5Fg3Nemj/GnH8oKiR/jPjEZa8YMJH7XG+K9ge3fFHnm3L8vML7Z0ukz50+3bGf2mbs/YU62a+hPFUPwZ3peZMx1RYE/08Pov9/P9LxkezPu/kxPgGtikl4K41/3ZcZGocvvl8PYc6T1Z3qcHtM/YRf+5eVvHq8I+ZjxVSF2vibEztcZ7YT+6fezVFhTmC+MxevKaXruAbI241Cxg3GoCDf8zxYbit++wB7mterCF9jD3KGhfrltfFbIHnuD0U7N9aQtV28IqKc3NdWTk98sv+XwN8u65p23hXDHO3J6kbZ9+Y4A7ng3BLnjPU0nF7n30Pt8dkZJ3UPvC9hDH4TgHvpQyB76iM/OslL30EcC9tDHIbiHPhGyhz4VMnN+JsTOz4XY+YUQO3cKsfNLIXZ+JcTOXULs/FqInbuF2LlHiJ17hdi5T4id+4XYeUCInQeF2HlIiJ2Hhdh5RIidR5nt5H7POg8WrKjhHH9lh1+oXgF8jtHgdxVnXqiews5jjO/bGXNtVnF43VSGmqmioW6OO5wnqoHP1TX4/Y3D/a4BPtfU4PcJh/uN5wjf1nChdHWH72+8DuEtDX7HCukLJxn7AmOuzViH1w1+Bv2ehro55XCewM8NP9Tg97cO9xs/6/lEg9+nhbyvOSPEzrNC7PxOiJ3nhNj5vRA7zwux8wchdv4YpM/gfYE9rvzoBpfPPwnx2cvo889CfA5j9PkXIT6HM/r8qxCfIxh9/k2Iz5GMPv8uxOdPGH3+Q4jPnzJ+L/NPIT5/xujz/4T4/Dmjz38J8fkLRp//FuLzTkafLwjx+UtGn/8R4vNXjD5fFOLzLkafLwnx+WtGny8L8Xk3o8/4pXkJPu9h9NkjxOe9jD57hfi8j9HnMCE+72f0OVyIzwcYfY4Q4vNBRp8jhfh8iNHnNEJ8Pszoc1ohPh9h9DmdEJ+PMvqcXojPxxh9vkOIz8cZfc4gxOdvGH3OKMTnE4w+ZxLi80lGnzML8fkUo893CvH5W0afswjx+TSjz1mF+HyG0edsQnw+y+jzXUJ8/o7R57uF+HyO0ed7hPj8PaPP2YX4fJ7R5xxCfP6B0eecQnz+kdHnXEJ8TmPw+ZxbiM9pGX3OI8TndIw+5xXic3pGn/MJ8fkORp/zC/E5A6PPBYT4nJHR54JCfM7E6PO9QnzOzOhzISE+38no831CfM7C6HNhIT5nZfT5fiE+Z2P0uYgQn+9i9LmoEJ/vZvS5mAaf1xFaN0TG70bhd4Wse9fg+0J8n4TvG3COxrkS5yycO7APY19Cnkbewn2MdY15Rr/vAckOkgMkJ0gukNwgeUDyguQDyQ9SAKQgyL0ghUDuAykMcj9IEZCiIMVAioOUACkJUgqkNEgZjAUI/lBtFMYYJBqkHEh5kAogMSAVQSqBVAapAlIVpBpIdcpPDSP5jue1QGqD1AGpC1IPpD5IA5CGII1AHgBpDNIEpClIM5DmIC1AWoK0AmkN0gakLUg7kPYgHUA6gnQC6QzSBaQryIMg3UC6g8SB9ACJB0kA6QnSC6Q3SB+QviCJIP1AkkD6gwwAGQgyCGQwyBCQoSDDQIaDjAAZCTIKZDTIGJCxIONAxoNMAJkIMglkMsgUkKkg00CmgzwEMgPkYZCZII+AzAJ5FGQ2yGMgc0DmgswDmQ+yAGQhyCKQxSBLQJaCLANZDrICZCXIKpDVIGtA1hrJ9Yh5wgd+hxK/U4jfscPvnOF3sPA7SfgdHfzOCn6HA7/TgNf44zXveA04XhON1whfpkLGayrxGkO85g6vQcNrsvAaJbxmB69hwWs68BoH/MwfPwPHz4TxM1L8zBA/Q8PPlPAzFvzMAc/B4zlpPEeL5yzxHB6e08JzPHjOA88B4HtifI+I75nwPQTO1Dhj4syFMwj2ZOxRyNnIYbin/w9wMumalt0DAA==", + "bytecode": "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", "verificationKey": "0000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f" } ] diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 0c0248af6d2..27d2141170d 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -27,7 +27,7 @@ import { WasmRollupCircuitSimulator, getL1Publisher, getVerificationKeys, - getconstantHistoricBlockData, + getConstantHistoricBlockData, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '@aztec/sequencer-client'; @@ -155,7 +155,7 @@ describe('L1Publisher integration', () => { }, 100_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getconstantHistoricBlockData(builderDb, prevGlobals); + const historicTreeRoots = await getConstantHistoricBlockData(builderDb, prevGlobals); const tx = await makeEmptyProcessedTxFromHistoricTreeRoots( historicTreeRoots, new Fr(config.chainId), @@ -169,7 +169,7 @@ describe('L1Publisher integration', () => { const kernelOutput = KernelCircuitPublicInputs.empty(); kernelOutput.constants.txContext.chainId = fr(config.chainId); kernelOutput.constants.txContext.version = fr(config.version); - kernelOutput.constants.blockData = await getconstantHistoricBlockData(builderDb, prevGlobals); + kernelOutput.constants.blockData = await getConstantHistoricBlockData(builderDb, prevGlobals); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/noir-libs/noir-aztec/src/abi.nr b/yarn-project/noir-libs/noir-aztec/src/abi.nr index f1b8df05536..6a6f2c6cc88 100644 --- a/yarn-project/noir-libs/noir-aztec/src/abi.nr +++ b/yarn-project/noir-libs/noir-aztec/src/abi.nr @@ -89,7 +89,7 @@ struct ConstantBlockData { impl ConstantBlockData { // NOTE: this order must match the order in `private_circuit_public_inputs.hpp` - fn serialize(self) -> [Field; Block_DATA_LENGTH] { + fn serialize(self) -> [Field; BLOCK_DATA_LENGTH] { [ self.private_data_tree_root, self.nullifier_tree_root, diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index bbbacfe15d7..22a50622995 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -57,7 +57,7 @@ import { makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '../sequencer/processed_tx.js'; -import { getconstantHistoricBlockData } from '../sequencer/utils.js'; +import { getConstantHistoricBlockData } from '../sequencer/utils.js'; import { RollupSimulator } from '../simulator/index.js'; import { WasmRollupCircuitSimulator } from '../simulator/rollup.js'; import { SoloBlockBuilder } from './solo_block_builder.js'; @@ -121,7 +121,7 @@ describe('sequencer/solo_block_builder', () => { }, 20_000); const makeEmptyProcessedTx = async () => { - const historicTreeRoots = await getconstantHistoricBlockData(builderDb); + const historicTreeRoots = await getConstantHistoricBlockData(builderDb); return makeEmptyProcessedTxFromHistoricTreeRoots(historicTreeRoots, chainId, version); }; @@ -169,7 +169,7 @@ describe('sequencer/solo_block_builder', () => { const buildMockSimulatorInputs = async () => { const kernelOutput = makeKernelPublicInputs(); - kernelOutput.constants.blockData = await getconstantHistoricBlockData(expectsDb); + kernelOutput.constants.blockData = await getConstantHistoricBlockData(expectsDb); const tx = await makeProcessedTx( new Tx( @@ -305,7 +305,7 @@ describe('sequencer/solo_block_builder', () => { const makeBloatedProcessedTx = async (seed = 0x1) => { const tx = mockTx(seed); const kernelOutput = KernelCircuitPublicInputs.empty(); - kernelOutput.constants.blockData = await getconstantHistoricBlockData(builderDb); + kernelOutput.constants.blockData = await getConstantHistoricBlockData(builderDb); kernelOutput.end.publicDataUpdateRequests = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, i => new PublicDataUpdateRequest(fr(i), fr(0), fr(i + 10)), diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 4b6fd6d5b39..335c6adcaf4 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -39,7 +39,7 @@ import { PublicKernelCircuitSimulator } from '../simulator/index.js'; import { getPublicExecutor } from '../simulator/public_executor.js'; import { WasmPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'; import { ProcessedTx, makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js'; -import { getconstantHistoricBlockData } from './utils.js'; +import { getConstantHistoricBlockData } from './utils.js'; /** * Creates new instances of PublicProcessor given the provided merkle tree db and contract data source. @@ -61,7 +61,7 @@ export class PublicProcessorFactory { prevGlobalVariables: GlobalVariables, globalVariables: GlobalVariables, ): Promise { - const blockData = await getconstantHistoricBlockData(this.merkleTree, prevGlobalVariables); + const blockData = await getConstantHistoricBlockData(this.merkleTree, prevGlobalVariables); return new PublicProcessor( this.merkleTree, getPublicExecutor(this.merkleTree, this.contractDataSource, this.l1Tol2MessagesDataSource, blockData), diff --git a/yarn-project/sequencer-client/src/sequencer/utils.ts b/yarn-project/sequencer-client/src/sequencer/utils.ts index 9465b81f8da..ce2464f7352 100644 --- a/yarn-project/sequencer-client/src/sequencer/utils.ts +++ b/yarn-project/sequencer-client/src/sequencer/utils.ts @@ -5,7 +5,7 @@ import { MerkleTreeOperations } from '@aztec/world-state'; /** * Fetches the private, nullifier, contract tree and l1 to l2 messages tree roots from a given db and assembles a CombinedHistoricTreeRoots object. */ -export async function getconstantHistoricBlockData( +export async function getConstantHistoricBlockData( db: MerkleTreeOperations, prevBlockGlobalVariables: GlobalVariables = GlobalVariables.empty(), ) { diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 6a397b79bc8..dac08744118 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -116,21 +116,4 @@ export class WorldStateDB implements CommitmentsDB { }; } - public getHistoricBlockData(): ConstantHistoricBlockData { - const roots = this.db.getTreeRoots(); - - return ConstantHistoricBlockData.from({ - privateKernelVkTreeRoot: Fr.ZERO, - - // TODO: work out how to get the previous globals hash in here - prevGlobalVariablesHash: Fr.ZERO, - - privateDataTreeRoot: Fr.fromBuffer(roots.privateDataTreeRoot), - contractTreeRoot: Fr.fromBuffer(roots.contractDataTreeRoot), - nullifierTreeRoot: Fr.fromBuffer(roots.nullifierTreeRoot), - l1ToL2MessagesTreeRoot: Fr.fromBuffer(roots.l1Tol2MessagesTreeRoot), - blocksTreeRoot: Fr.fromBuffer(roots.blocksTreeRoot), - publicDataTreeRoot: Fr.fromBuffer(roots.publicDataTreeRoot), - }); - } } From deefe177dac6a1df48dcd64619a1f852319430e1 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:49:32 +0000 Subject: [PATCH 55/58] fmt --- yarn-project/acir-simulator/src/client/simulator.ts | 2 +- yarn-project/acir-simulator/src/public/executor.ts | 7 +------ .../aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts | 2 +- yarn-project/aztec-rpc/src/simulator_oracle/index.ts | 1 - .../end-to-end/src/integration_l1_publisher.test.ts | 2 +- .../sequencer-client/src/simulator/public_executor.ts | 1 - 6 files changed, 4 insertions(+), 11 deletions(-) diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index e2eeb5f83ab..6c936a29994 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -102,7 +102,7 @@ export class AcirSimulator { portalContractAddress: EthAddress, constantHistoricBlockData: ConstantHistoricBlockData, aztecNode?: AztecNode, - ){ + ) { if (entryPointABI.functionType !== FunctionType.UNCONSTRAINED) { throw new Error(`Cannot run ${entryPointABI.functionType} function as constrained`); } diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/acir-simulator/src/public/executor.ts index 083f46cca02..94c8018686d 100644 --- a/yarn-project/acir-simulator/src/public/executor.ts +++ b/yarn-project/acir-simulator/src/public/executor.ts @@ -60,12 +60,7 @@ export class PublicExecutor { const acir = await this.contractsDb.getBytecode(execution.contractAddress, selector); if (!acir) throw new Error(`Bytecode not found for ${execution.contractAddress.toString()}:${selectorHex}`); - const initialWitness = getInitialWitness( - execution.args, - execution.callContext, - this.blockData, - globalVariables, - ); + const initialWitness = getInitialWitness(execution.args, execution.callContext, this.blockData, globalVariables); const storageActions = new ContractStorageActionsCollector(this.stateDb, execution.contractAddress); const newCommitments: Fr[] = []; const newL2ToL1Messages: Fr[] = []; diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 97176b37b50..1cd23c0667c 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -395,7 +395,7 @@ export class AztecRPCServer implements AztecRPC { portalContract, constantHistoricBlockData, this.node, - ); + ); this.log('Unconstrained simulation completed!'); return result; diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 52d5f833cc9..814916d7a6a 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -101,5 +101,4 @@ export class SimulatorOracle implements DBOracle { index, }); } - } diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index 27d2141170d..d57d6e23fcf 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -25,9 +25,9 @@ import { L1Publisher, SoloBlockBuilder, WasmRollupCircuitSimulator, + getConstantHistoricBlockData, getL1Publisher, getVerificationKeys, - getConstantHistoricBlockData, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricTreeRoots, makeProcessedTx, } from '@aztec/sequencer-client'; diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index dac08744118..6fdc09e90aa 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -115,5 +115,4 @@ export class WorldStateDB implements CommitmentsDB { index, }; } - } From 9210bf92b4e2c0c633f24a2c6e2c0172c0e5608f Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 8 Aug 2023 14:52:11 +0000 Subject: [PATCH 56/58] chore(fmt): formatting 2; electric boogaloo --- yarn-project/acir-simulator/src/public/db.ts | 2 +- yarn-project/aztec-rpc/src/simulator_oracle/index.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/yarn-project/acir-simulator/src/public/db.ts b/yarn-project/acir-simulator/src/public/db.ts index 13c5682d056..16f7bf412dc 100644 --- a/yarn-project/acir-simulator/src/public/db.ts +++ b/yarn-project/acir-simulator/src/public/db.ts @@ -1,4 +1,4 @@ -import { ConstantHistoricBlockData, EthAddress } from '@aztec/circuits.js'; +import { EthAddress } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 814916d7a6a..20fd0d9c2e2 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -2,7 +2,6 @@ import { CommitmentDataOracleInputs, DBOracle, MessageLoadOracleInputs } from '@ import { AztecAddress, CircuitsWasm, - ConstantHistoricBlockData, EthAddress, Fr, PartialContractAddress, @@ -11,7 +10,7 @@ import { } from '@aztec/circuits.js'; import { siloCommitment } from '@aztec/circuits.js/abis'; import { FunctionAbi } from '@aztec/foundation/abi'; -import { DataCommitmentProvider, KeyStore, L1ToL2MessageProvider, MerkleTreeId } from '@aztec/types'; +import { DataCommitmentProvider, KeyStore, L1ToL2MessageProvider } from '@aztec/types'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { Database } from '../database/index.js'; From 2cfa1eb75cc64916a66fe66b0da7a826d73a6cb3 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 9 Aug 2023 09:55:04 +0000 Subject: [PATCH 57/58] fix: final review comments --- .../cpp/src/aztec3/circuits/abis/packers.hpp | 2 +- circuits/cpp/src/aztec3/constants.hpp | 11 +++++----- .../src/core/libraries/ConstantsGen.sol | 2 +- .../circuits.js/src/cbind/constants.gen.ts | 2 +- yarn-project/noir-libs/noir-aztec/src/abi.nr | 22 +++++++++---------- .../noir-libs/noir-aztec/src/constants_gen.nr | 2 +- .../noir-libs/noir-aztec/src/context.nr | 4 ++-- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp index c739a6b8767..94d61deb0f6 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp @@ -68,7 +68,7 @@ struct ConstantsPacker { MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH, CALL_CONTEXT_LENGTH, - BLOCK_DATA_LENGTH, + CONSTANT_HISTORIC_BLOCK_DATA_LENGTH, FUNCTION_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 976a0e91756..d2acaa315f6 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -220,7 +220,8 @@ constexpr size_t MAX_NOTES_PER_PAGE = 10; constexpr size_t VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2; constexpr size_t CALL_CONTEXT_LENGTH = 6; -constexpr size_t BLOCK_DATA_LENGTH = 7; +// Must be updated if any data is added into the block hash calculation. +constexpr size_t CONSTANT_HISTORIC_BLOCK_DATA_LENGTH = 7; constexpr size_t FUNCTION_DATA_LENGTH = 4; constexpr size_t CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; @@ -232,14 +233,14 @@ constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + BLOCK_DATA_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version + + CONSTANT_HISTORIC_BLOCK_DATA_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 1 + 1 // call_context_hash + args_hash + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + BLOCK_DATA_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version + + CONSTANT_HISTORIC_BLOCK_DATA_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version constexpr size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; constexpr size_t CONTRACT_STORAGE_READ_LENGTH = 2; @@ -250,8 +251,8 @@ constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL * CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH + MAX_PUBLIC_DATA_READS_PER_CALL * CONTRACT_STORAGE_READ_LENGTH + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + MAX_NEW_NULLIFIERS_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + - NUM_FIELDS_PER_SHA256 + 1 + // + 1 for unencrypted logs preimage length - BLOCK_DATA_LENGTH + 2; // + 2 for chain_id and version + NUM_FIELDS_PER_SHA256 + 1 + // + 1 for unencrypted logs preimage length + CONSTANT_HISTORIC_BLOCK_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 2 + RETURN_VALUES_LENGTH + // + 1 for args_hash + 1 call_context.hash diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 41f316737f9..0c540095c66 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -65,7 +65,7 @@ library Constants { uint256 internal constant MAX_NOTES_PER_PAGE = 10; uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; uint256 internal constant CALL_CONTEXT_LENGTH = 6; - uint256 internal constant BLOCK_DATA_LENGTH = 7; + uint256 internal constant CONSTANT_HISTORIC_BLOCK_DATA_LENGTH = 7; uint256 internal constant FUNCTION_DATA_LENGTH = 4; uint256 internal constant CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; diff --git a/yarn-project/circuits.js/src/cbind/constants.gen.ts b/yarn-project/circuits.js/src/cbind/constants.gen.ts index 21579add518..73303170575 100644 --- a/yarn-project/circuits.js/src/cbind/constants.gen.ts +++ b/yarn-project/circuits.js/src/cbind/constants.gen.ts @@ -51,7 +51,7 @@ export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; export const CALL_CONTEXT_LENGTH = 6; -export const BLOCK_DATA_LENGTH = 7; +export const CONSTANT_HISTORIC_BLOCK_DATA_LENGTH = 7; export const FUNCTION_DATA_LENGTH = 4; export const CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 58; diff --git a/yarn-project/noir-libs/noir-aztec/src/abi.nr b/yarn-project/noir-libs/noir-aztec/src/abi.nr index 9954302bed6..b2a4240db29 100644 --- a/yarn-project/noir-libs/noir-aztec/src/abi.nr +++ b/yarn-project/noir-libs/noir-aztec/src/abi.nr @@ -10,7 +10,7 @@ use crate::constants_gen::{ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, GENERATOR_INDEX__FUNCTION_ARGS, - BLOCK_DATA_LENGTH, + CONSTANT_HISTORIC_BLOCK_DATA_LENGTH, CONTRACT_DEPLOYMENT_DATA_LENGTH, CALL_CONTEXT_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, @@ -84,7 +84,7 @@ impl ContractDeploymentData { // PrivateContextInputs are expected to be provided to each private function struct PrivateContextInputs { call_context : CallContext, - block_data: ConstantBlockData, + block_data: ConstantHistoricBlockData, contract_deployment_data: ContractDeploymentData, @@ -94,7 +94,7 @@ struct PrivateContextInputs { // PublicContextInputs are expected to be provided to each public function struct PublicContextInputs { call_context: CallContext, - block_data: ConstantBlockData, + block_data: ConstantHistoricBlockData, public_global_variables: PublicGlobalVariables, } @@ -126,7 +126,7 @@ impl CallContext { } } -struct ConstantBlockData { +struct ConstantHistoricBlockData { private_data_tree_root : Field, nullifier_tree_root : Field, contract_tree_root : Field, @@ -136,9 +136,9 @@ struct ConstantBlockData { public_data_tree_root: Field, } -impl ConstantBlockData { +impl ConstantHistoricBlockData { // NOTE: this order must match the order in `private_circuit_public_inputs.hpp` - fn serialize(self) -> [Field; BLOCK_DATA_LENGTH] { + fn serialize(self) -> [Field; CONSTANT_HISTORIC_BLOCK_DATA_LENGTH] { [ self.private_data_tree_root, self.nullifier_tree_root, @@ -151,8 +151,8 @@ impl ConstantBlockData { } } -fn empty_block_data() -> ConstantBlockData { - ConstantBlockData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } +fn empty_block_data() -> ConstantHistoricBlockData { + ConstantHistoricBlockData{ private_data_tree_root: 0, nullifier_tree_root: 0, contract_tree_root: 0, l1_to_l2_messages_tree_root: 0, blocks_tree_root: 0, prev_global_variables_hash: 0, public_data_tree_root: 0 } } struct FunctionData { @@ -190,7 +190,7 @@ struct PrivateCircuitPublicInputs { unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, - block_data: ConstantBlockData, + block_data: ConstantHistoricBlockData, contract_deployment_data: ContractDeploymentData, chain_id: Field, version: Field, @@ -296,7 +296,7 @@ struct PublicCircuitPublicInputs { new_l2_to_l1_msgs: [Field; crate::abi::MAX_NEW_L2_TO_L1_MSGS_PER_CALL], unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], unencrypted_log_preimages_length: Field, - block_data: ConstantBlockData, // TODO: This is not present in cpp or ts, do we need to include it? + block_data: ConstantHistoricBlockData, historic_public_data_tree_root: Field, prover_address: Field, } @@ -320,7 +320,7 @@ impl PublicCircuitPublicInputs { inputs.push_array(self.new_l2_to_l1_msgs); // We do not include block_data since it's not in the cpp hash - // inputs.push(self.block_data.hash()); + // inputs.push(self.block_data.hash()); see https://github.com/AztecProtocol/aztec-packages/issues/1473 inputs.push_array(self.unencrypted_logs_hash); inputs.push(self.unencrypted_log_preimages_length); diff --git a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr index 4d17e9c6361..435ea2756a2 100644 --- a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr +++ b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr @@ -50,7 +50,7 @@ global GET_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 23; global MAX_NOTES_PER_PAGE: comptime Field = 10; global VIEW_NOTE_ORACLE_RETURN_LENGTH: comptime Field = 212; global CALL_CONTEXT_LENGTH: comptime Field = 6; -global BLOCK_DATA_LENGTH: comptime Field = 7; +global CONSTANT_HISTORIC_BLOCK_DATA_LENGTH: comptime Field = 7; global FUNCTION_DATA_LENGTH: comptime Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: comptime Field = 6; global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: comptime Field = 58; diff --git a/yarn-project/noir-libs/noir-aztec/src/context.nr b/yarn-project/noir-libs/noir-aztec/src/context.nr index 0197d2d1e2f..4681564d2df 100644 --- a/yarn-project/noir-libs/noir-aztec/src/context.nr +++ b/yarn-project/noir-libs/noir-aztec/src/context.nr @@ -21,7 +21,7 @@ use crate::abi::{ hash_args, CallContext, ContractDeploymentData, - ConstantBlockData, + ConstantHistoricBlockData, FunctionData, PrivateCircuitPublicInputs, PublicCircuitPublicInputs, @@ -242,7 +242,7 @@ impl Context { unencrypted_logs_hash: arr_copy_slice(fields, [0; NUM_FIELDS_PER_SHA256], 44), encrypted_log_preimages_length: fields[46], unencrypted_log_preimages_length: fields[47], - block_data: ConstantBlockData { + block_data: ConstantHistoricBlockData { // Must match order in `private_circuit_public_inputs.hpp` private_data_tree_root : fields[48], nullifier_tree_root : fields[49], From 81dd1f3526ea65b1f8af0663db08a40c3914ff74 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 9 Aug 2023 10:23:11 +0000 Subject: [PATCH 58/58] merge fix --- yarn-project/archiver/src/archiver/archiver_store.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index bb50f408c56..80fbfd82c66 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -257,7 +257,10 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ public getL2Blocks(from: number, limit: number): Promise { // Return an empty array if we are outside of range - if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length || limit < 1) { + if (limit < 1) { + throw new Error(`Invalid block range from: ${from}, limit: ${limit}`); + } + if (from < INITIAL_L2_BLOCK_NUM || from > this.l2Blocks.length) { return Promise.resolve([]); } const startIndex = from - INITIAL_L2_BLOCK_NUM;