From 708e4e5588a73d46faa0fc258dd9664515764f5d Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Tue, 27 Aug 2024 15:06:22 +0100 Subject: [PATCH] feat: slot duration flexibility (#8122) This PR add support for using Aztec slot durations that are not just 1 ethereum slot. To do so it adds more logic to the sequencer such that they can figure out if they are really the sequencer or not. This is mainly in the `canProposeBlock` and `shouldProposeBlock` functions which respectively assert that the proposer can actually propose, and whether he should. The logic in those functions are partly what we had sprinkled over the code before, but also adding some additional checks to match what is in the rollup contract and Leonidas. Since there are now additional restrictions to block production related to WHEN the block is to land on L1, I have added a `commitTimeJump` function into the `l1-publisher`which will jump to the next slot after a block have been published. This functionality toggled with a `TIME_TRAVELER` boolean flag. Note that we will jump INTO the next slot, since simulations in `viem` and `anvil` are limited to run on block values in the bast, meaning that we cannot nicely just simulate as if it was included in the NEXT block which is what we ideally want. See issue #8110 for more information. Since it caused some issues that there was no actual genesis state (just 0), I have inserted a genesis state equal to what we compute as the `lastArchive` for the very first block, fixing #4148. To not mess too much with DEVNET, the extra logic related to the exact timing of when L2 blocks should make it onto L1 can be "toggled" with the `IS_DEV_NET` flag. Namely, if `IS_DEV_NET` is toggled, we can publish outside of the "current" slot, as long as the slots are in order. With the changes in this pr, we should be able to run DEVNET without `automine`, I have tried a minor test but that seemed to work fine when we have `AZTEC_SLOT_DURATION = 36` and internal mining :) Points of interest: - `sequencer.ts` - `canProposeBlock` - `shouldProposeBlock` - `l1-publisher.ts` - Adding `simulate` since viem `write` does not provide meaningful error messages, but `simulate` does. - The `commitTimeJump` won't happen if the `AZTEC_SLOT_DURATION = ETHEREUM_SLOT_DURATION` or `TIME_TRAVELER = false` - `sequencer.test.ts` - Some of the test naming a odd. For example the test `builds a block that contains zero real transactions once flushed` sounds to me like you expect to have an empty block, after the block flushed, e.g., once flushed make it sound like it already happened - `l1-publisher.test.ts` - `does not publish if last archive root is different to expected` is deleted, as that job falls on the sequencer. The sequencer should define whether or not it will send a tx, and publisher deals more with publishing tasks. - Adding a `simulate` that is also mocked to account for `simulate` in the publisher. - `e2e_p2p_network.test.ts` - There is a flag for using a local anvil chain that you are running in another terminal. This is useful for running internal mining etc. --- This PR will be run with `AZTEC_SLOT_DURATION = 12` and `IS_DEV_NET = true`. Note that when using values different from those, there are still some hiccups and kinks, but it should be addressed in a separate PR to not make this explode in size. --- l1-contracts/src/core/Rollup.sol | 11 +- .../src/core/libraries/ConstantsGen.sol | 4 + l1-contracts/src/core/libraries/Errors.sol | 2 +- .../src/core/sequencer_selection/Leonidas.sol | 4 +- l1-contracts/test/Rollup.t.sol | 9 + l1-contracts/test/fixtures/empty_block_1.json | 14 +- l1-contracts/test/fixtures/empty_block_2.json | 16 +- l1-contracts/test/fixtures/mixed_block_1.json | 14 +- l1-contracts/test/fixtures/mixed_block_2.json | 16 +- l1-contracts/test/sparta/Sparta.t.sol | 42 +-- .../crates/types/src/constants.nr | 6 + yarn-project/circuits.js/src/constants.gen.ts | 3 + yarn-project/end-to-end/package.json | 10 +- yarn-project/end-to-end/package.local.json | 2 +- .../composed/integration_l1_publisher.test.ts | 20 +- .../end-to-end/src/e2e_p2p_network.test.ts | 25 +- .../ethereum/src/deploy_l1_contracts.ts | 37 ++- yarn-project/foundation/src/config/env_var.ts | 1 + yarn-project/sequencer-client/package.json | 1 + .../global_variable_builder/global_builder.ts | 13 +- .../sequencer-client/src/publisher/config.ts | 12 +- .../src/publisher/l1-publisher.test.ts | 63 +++- .../src/publisher/l1-publisher.ts | 215 ++++++++---- .../src/sequencer/sequencer.test.ts | 96 ++++-- .../src/sequencer/sequencer.ts | 312 +++++++++++++----- yarn-project/sequencer-client/tsconfig.json | 3 + .../validator-client/src/validator.ts | 13 +- yarn-project/yarn.lock | 1 + 28 files changed, 655 insertions(+), 310 deletions(-) diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 87de3e24310..2d32c4858c8 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -89,8 +89,12 @@ contract Rollup is Leonidas, IRollup, ITestRollup { VERSION = 1; // Genesis block - blocks[0] = - BlockLog({archive: bytes32(0), blockHash: bytes32(0), slotNumber: 0, isProven: true}); + blocks[0] = BlockLog({ + archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT), + blockHash: bytes32(0), + slotNumber: 0, + isProven: true + }); pendingBlockCount = 1; provenBlockCount = 1; } @@ -579,9 +583,8 @@ contract Rollup is Leonidas, IRollup, ITestRollup { ); } - // TODO(#4148) Proper genesis state. If the state is empty, we allow anything for now. bytes32 tipArchive = archive(); - if (tipArchive != bytes32(0) && tipArchive != _header.lastArchive.root) { + if (tipArchive != _header.lastArchive.root) { revert Errors.Rollup__InvalidArchive(tipArchive, _header.lastArchive.root); } diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index e5b0a08205f..2e04e93dfe2 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -102,7 +102,11 @@ library Constants { uint256 internal constant INITIAL_L2_BLOCK_NUM = 1; uint256 internal constant BLOB_SIZE_IN_BYTES = 126976; uint256 internal constant ETHEREUM_SLOT_DURATION = 12; + uint256 internal constant AZTEC_SLOT_DURATION = 12; + uint256 internal constant AZTEC_EPOCH_DURATION = 48; uint256 internal constant IS_DEV_NET = 1; + uint256 internal constant GENESIS_ARCHIVE_ROOT = + 8142738430000951296386584486068033372964809139261822027365426310856631083550; uint256 internal constant FEE_JUICE_INITIAL_MINT = 20000000000; uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 469b1bc7c02..d2bad00bffa 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -84,7 +84,7 @@ library Errors { error Leonidas__EpochNotSetup(); // 0xcf4e597e error Leonidas__InvalidProposer(address expected, address actual); // 0xd02d278e error Leonidas__InsufficientAttestations(uint256 minimumNeeded, uint256 provided); // 0xbf1ca4cb - error Leonidas__InsufficientAttestationsProvided(uint256 minimumNeeded, uint256 provided); // 0x2e7debe9 + error Leonidas__InsufficientAttestationsProvided(uint256 minimumNeeded, uint256 provided); // 0xb3a697c2 // Fee Juice Portal error FeeJuicePortal__AlreadyInitialized(); // 0xc7a172fe diff --git a/l1-contracts/src/core/sequencer_selection/Leonidas.sol b/l1-contracts/src/core/sequencer_selection/Leonidas.sol index 4efdc8ff3cd..511b49eb622 100644 --- a/l1-contracts/src/core/sequencer_selection/Leonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/Leonidas.sol @@ -52,12 +52,12 @@ contract Leonidas is Ownable, ILeonidas { // // The value should be a higher multiple for any actual chain // @todo #8019 - uint256 public constant SLOT_DURATION = Constants.ETHEREUM_SLOT_DURATION * 1; + uint256 public constant SLOT_DURATION = Constants.AZTEC_SLOT_DURATION; // The duration of an epoch in slots // @todo @LHerskind - This value should be updated when we are not blind. // @todo #8020 - uint256 public constant EPOCH_DURATION = 32; + uint256 public constant EPOCH_DURATION = Constants.AZTEC_EPOCH_DURATION; // The target number of validators in a committee // @todo #8021 diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index a9205542fbc..7c1c9739b01 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -158,6 +158,9 @@ contract RollupTest is DecoderBase { bytes32 archive = data.archive; bytes memory body = data.body; + // Progress time as necessary + vm.warp(max(block.timestamp, data.decodedHeader.globalVariables.timestamp)); + assembly { mstore(add(header, add(0x20, 0x0248)), feeAmount) } @@ -302,6 +305,9 @@ contract RollupTest is DecoderBase { function testBlocksWithAssumeProven() public setUpFor("mixed_block_1") { rollup.setAssumeProvenUntilBlockNumber(2); + assertEq(rollup.pendingBlockCount(), 1, "Invalid pending block count"); + assertEq(rollup.provenBlockCount(), 1, "Invalid proven block count"); + _testBlock("mixed_block_1", false); _testBlock("mixed_block_2", false); @@ -310,6 +316,9 @@ contract RollupTest is DecoderBase { } function testSetAssumeProvenAfterBlocksProcessed() public setUpFor("mixed_block_1") { + assertEq(rollup.pendingBlockCount(), 1, "Invalid pending block count"); + assertEq(rollup.provenBlockCount(), 1, "Invalid proven block count"); + _testBlock("mixed_block_1", false); _testBlock("mixed_block_2", false); rollup.setAssumeProvenUntilBlockNumber(2); diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index ef20e7e8154..20b938cbc40 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x0b97584f2e175ce708df94c14fee5e53d1c92cd5308346c6eabb79005ccf6733", + "archive": "0x1fc4515430abede0c269e0aaf99fe032b4368b094b2a399d112144d8e0b4b803", "body": "0x00000000", "txsEffectsHash": "0x00e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d6", "decodedHeader": { @@ -20,12 +20,12 @@ }, "globalVariables": { "blockNumber": 1, - "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000005", + "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000033", "chainId": 31337, - "timestamp": 1723460388, + "timestamp": 1724321038, "version": 1, - "coinbase": "0x92c3bc662a41b5406370e6e30b6e4541c9c223e3", - "feeRecipient": "0x2af4d139729812fa69edfc27fc2d19b3d2616c9e4ec2313efb66fb2f234d59da", + "coinbase": "0x69d2d2c697a0ac4a874c591f6906706af27eb737", + "feeRecipient": "0x2c6280804920e2ecb139fe6185aeba95ee3687e64a14ff68a72a25ab9bb0d5eb", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -56,8 +56,8 @@ } } }, - "header": "0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e00000001000000000000000000000000000000000000000000000000000000000000000200e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d600089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb14f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000100b59baa35b9dc267744f0ccb4e3b0255c1fc512460d91130c6bc19fb2668568d0000008019a8c197c12bb33da6314c4ef4f8f6fcb9e25250c085df8672adf67c8f1e3dbc0000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000001000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000066b9eb2492c3bc662a41b5406370e6e30b6e4541c9c223e32af4d139729812fa69edfc27fc2d19b3d2616c9e4ec2313efb66fb2f234d59da000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00330b9ccec92816ea3dd5fefce65cdb3803cf663cf2959f403501ff1f27a73c", + "header": "0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e00000001000000000000000000000000000000000000000000000000000000000000000200e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d600089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb14f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000100b59baa35b9dc267744f0ccb4e3b0255c1fc512460d91130c6bc19fb2668568d0000008019a8c197c12bb33da6314c4ef4f8f6fcb9e25250c085df8672adf67c8f1e3dbc0000010023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000001000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000066c70d0e69d2d2c697a0ac4a874c591f6906706af27eb7372c6280804920e2ecb139fe6185aeba95ee3687e64a14ff68a72a25ab9bb0d5eb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00acfc19a39d0814b57d47fbf843284cd2d293382e82dfcaafc819daf89b81b5", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_2.json b/l1-contracts/test/fixtures/empty_block_2.json index c45b0a4fc85..0142912e043 100644 --- a/l1-contracts/test/fixtures/empty_block_2.json +++ b/l1-contracts/test/fixtures/empty_block_2.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x1d77208270a6eca3c2b56adaad130b28e2fa111d6bc325ce3cc52b6a68f4894f", + "archive": "0x2da3733e9f6522fcc8016aff753cb69100051aae6f3612a2180959adfd3293f6", "body": "0x00000000", "txsEffectsHash": "0x00e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d6", "decodedHeader": { @@ -20,12 +20,12 @@ }, "globalVariables": { "blockNumber": 2, - "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000006", + "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000035", "chainId": 31337, - "timestamp": 1723460400, + "timestamp": 1724321062, "version": 1, - "coinbase": "0x92c3bc662a41b5406370e6e30b6e4541c9c223e3", - "feeRecipient": "0x2af4d139729812fa69edfc27fc2d19b3d2616c9e4ec2313efb66fb2f234d59da", + "coinbase": "0x69d2d2c697a0ac4a874c591f6906706af27eb737", + "feeRecipient": "0x2c6280804920e2ecb139fe6185aeba95ee3687e64a14ff68a72a25ab9bb0d5eb", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -33,7 +33,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0b97584f2e175ce708df94c14fee5e53d1c92cd5308346c6eabb79005ccf6733" + "root": "0x1fc4515430abede0c269e0aaf99fe032b4368b094b2a399d112144d8e0b4b803" }, "stateReference": { "l1ToL2MessageTree": { @@ -56,8 +56,8 @@ } } }, - "header": "0x0b97584f2e175ce708df94c14fee5e53d1c92cd5308346c6eabb79005ccf673300000002000000000000000000000000000000000000000000000000000000000000000200e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d600089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb14f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000200b59baa35b9dc267744f0ccb4e3b0255c1fc512460d91130c6bc19fb2668568d0000010019a8c197c12bb33da6314c4ef4f8f6fcb9e25250c085df8672adf67c8f1e3dbc0000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000066b9eb3092c3bc662a41b5406370e6e30b6e4541c9c223e32af4d139729812fa69edfc27fc2d19b3d2616c9e4ec2313efb66fb2f234d59da000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x006ccf0ce5551a2a07b16c10a4b208bd30403231409d44cedac9b6d489b9f212", + "header": "0x1fc4515430abede0c269e0aaf99fe032b4368b094b2a399d112144d8e0b4b80300000002000000000000000000000000000000000000000000000000000000000000000200e994e16b3763fd5039413cf99c2b3c378e2bab939e7992a77bd201b28160d600089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00f5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb14f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000200b59baa35b9dc267744f0ccb4e3b0255c1fc512460d91130c6bc19fb2668568d0000010019a8c197c12bb33da6314c4ef4f8f6fcb9e25250c085df8672adf67c8f1e3dbc0000018023c08a6b1297210c5e24c76b9a936250a1ce2721576c26ea797c7ec35f9e46a9000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000066c70d2669d2d2c697a0ac4a874c591f6906706af27eb7372c6280804920e2ecb139fe6185aeba95ee3687e64a14ff68a72a25ab9bb0d5eb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00318295aad2a231c68b825b4fca99e2cbb1345c82ee6d01888289771199d1b9", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index ee676dee4ca..7d6b8e45d9f 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -58,7 +58,7 @@ ] }, "block": { - "archive": "0x0f16cd5260bfdd24b99a5aa4fd778c58f4348f57e5c9697bde3f2ec56a026d56", + "archive": "0x2e509ada109d80ef634c0eca74fecd28b17727847e3b21cf01961c73b1b58978", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0800c47667396742a5474f325e2567bff3bb99b7f0bfd2b1a689b635d8b8726cce00284120278895e8d47084ae759f390e9634881e41369a257a36fe99a2369dc800a328b4a4a6ed156325253b4ab2af7ca00e21caf7963f0fba8a88ccdc3512c300705c99df420bface231f6855799db1d0ed7d39419abc47aa8c6efe2ae7aae2009299cc308de6d23788384411e024791a5b2448e455fbdd1d1f28f3ff76631f002d6c03d81ad764de51b0f34584645191cdc2aaae2ca08fb838d142b95d62f5003032f3618b2df0fa335d5fd548d6d85e42b4e7eb5fff9eb687facbbdecb8a60016cab7ddf4d1b440d53d10284c5c82a78b2d4e27dcdb44ef434ef4c6bad6783f0000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005690000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000561000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000562000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005660000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000056700000000000000000000000000000000000000000000000000000000000005710000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000057200000000000000000000000000000000000000000000000000000000000005690000000000000000000000000000000000000000000000000000000000000573000000000000000000000000000000000000000000000000000000000000056a0000000000000000000000000000000000000000000000000000000000000574000000000000000000000000000000000000000000000000000000000000056b0000000000000000000000000000000000000000000000000000000000000575000000000000000000000000000000000000000000000000000000000000056c0000000000000000000000000000000000000000000000000000000000000576000000000000000000000000000000000000000000000000000000000000056d0000000000000000000000000000000000000000000000000000000000000577000000000000000000000000000000000000000000000000000000000000056e0000000000000000000000000000000000000000000000000000000000000578000000000000000000000000000000000000000000000000000000000000056f00000000000000000000000000000000000000000000000000000000000005790000000000000000000000000000000000000000000000000000000000000570000000000000000000000000000000000000000000000000000000000000057a0000000000000000000000000000000000000000000000000000000000000571000000000000000000000000000000000000000000000000000000000000057b0000000000000000000000000000000000000000000000000000000000000572000000000000000000000000000000000000000000000000000000000000057c0000000000000000000000000000000000000000000000000000000000000573000000000000000000000000000000000000000000000000000000000000057d0000000000000000000000000000000000000000000000000000000000000574000000000000000000000000000000000000000000000000000000000000057e0000000000000000000000000000000000000000000000000000000000000575000000000000000000000000000000000000000000000000000000000000057f00000000000000000000000000000000000000000000000000000000000005760000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000057700000000000000000000000000000000000000000000000000000000000005810000000000000000000000000000000000000000000000000000000000000578000000000000000000000000000000000000000000000000000000000000058200000000000000000000000000000000000000000000000000000000000005790000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000057a0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000057b0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000057c0000000000000000000000000000000000000000000000000000000000000586000000000000000000000000000000000000000000000000000000000000057d0000000000000000000000000000000000000000000000000000000000000587000000000000000000000000000000000000000000000000000000000000057e0000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0800789ff73d7787206612d96dfc2143f2344de21669a3f8cae7fe9a8918631eb00084a17f00bf8793b6851a106e9155543125e0be987ad3c8334456bdda171d0b00a400f8fd336ad84f467465964008238fd1b7f9c51c22912d706cd2b874d24e002c79bdd83c14ff50a46964f838ee207564909e28af79a57fc195810d36f9b20070083c6ef1e4dd88a064e94d2582283b203cf8a2ab1667f4370eda1b4c1fe8005373dffb5b590053d7762efcf9e11280f1486ce82e7996d94ee0f5d7c093bc009eefd90eb40e79c78bac1f71ec78bdc2f8b30041974239bdc765edffed813800ea95742e72792ca7a0f66ce9f55bc47dc09d5ea08c1b9018763102776978303f0000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a900000000000000000000000000000000000000000000000000000000000005a000000000000000000000000000000000000000000000000000000000000005aa00000000000000000000000000000000000000000000000000000000000005a100000000000000000000000000000000000000000000000000000000000005ab00000000000000000000000000000000000000000000000000000000000005a200000000000000000000000000000000000000000000000000000000000005ac00000000000000000000000000000000000000000000000000000000000005a300000000000000000000000000000000000000000000000000000000000005ad00000000000000000000000000000000000000000000000000000000000005a400000000000000000000000000000000000000000000000000000000000005ae00000000000000000000000000000000000000000000000000000000000005a500000000000000000000000000000000000000000000000000000000000005af00000000000000000000000000000000000000000000000000000000000005a600000000000000000000000000000000000000000000000000000000000005b000000000000000000000000000000000000000000000000000000000000005a700000000000000000000000000000000000000000000000000000000000005b100000000000000000000000000000000000000000000000000000000000005a800000000000000000000000000000000000000000000000000000000000005b200000000000000000000000000000000000000000000000000000000000005a900000000000000000000000000000000000000000000000000000000000005b300000000000000000000000000000000000000000000000000000000000005aa00000000000000000000000000000000000000000000000000000000000005b400000000000000000000000000000000000000000000000000000000000005ab00000000000000000000000000000000000000000000000000000000000005b500000000000000000000000000000000000000000000000000000000000005ac00000000000000000000000000000000000000000000000000000000000005b600000000000000000000000000000000000000000000000000000000000005ad00000000000000000000000000000000000000000000000000000000000005b700000000000000000000000000000000000000000000000000000000000005ae00000000000000000000000000000000000000000000000000000000000005b800000000000000000000000000000000000000000000000000000000000005af00000000000000000000000000000000000000000000000000000000000005b900000000000000000000000000000000000000000000000000000000000005b000000000000000000000000000000000000000000000000000000000000005ba00000000000000000000000000000000000000000000000000000000000005b100000000000000000000000000000000000000000000000000000000000005bb00000000000000000000000000000000000000000000000000000000000005b200000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000000000000000000000000000000000000000005b300000000000000000000000000000000000000000000000000000000000005bd00000000000000000000000000000000000000000000000000000000000005b400000000000000000000000000000000000000000000000000000000000005be00000000000000000000000000000000000000000000000000000000000005b500000000000000000000000000000000000000000000000000000000000005bf00000000000000000000000000000000000000000000000000000000000005b600000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005b700000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005b800000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005b900000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005ba00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005bb00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005bc00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005bd00000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005be00000000000000000000000000000000000000000000000000000000000005c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0800a68d2df6e48c8b31f4c76529e586de2cd9d0f2f2fdfbc4c523db9e3a29e9b80016c236e57bf17afe324437acd1060772e3f31d4f9e734ad758d0627c4ba2a200d659011ddde95e32886bdd8c9464da1ca144ccadd539f0992b4abb491d812a00c8025bb9006a976ebd6ad940155f15f89ca0bb7312b53841fc257e7ed689c8004165f2c46b70fb183468b38f31bba7aa9d22ce8dfb61fe721470729ce1c6b100afeb60dd983514ebbaee141b2196f3eb3c9c299f576a0097872cc85a79a43f005f6bfee53d20a474901493558419dbceb3aca40e5e18915d38031498f4d2bb008791217ee341ec5dc11f7d7a31160fb1b1f2cf767062970e9526e5751956253f00000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005ea00000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005eb00000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005ec00000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005ed00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005ee00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005ef00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005f000000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005f100000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005f200000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000005f300000000000000000000000000000000000000000000000000000000000005ea00000000000000000000000000000000000000000000000000000000000005f400000000000000000000000000000000000000000000000000000000000005eb00000000000000000000000000000000000000000000000000000000000005f500000000000000000000000000000000000000000000000000000000000005ec00000000000000000000000000000000000000000000000000000000000005f600000000000000000000000000000000000000000000000000000000000005ed00000000000000000000000000000000000000000000000000000000000005f700000000000000000000000000000000000000000000000000000000000005ee00000000000000000000000000000000000000000000000000000000000005f800000000000000000000000000000000000000000000000000000000000005ef00000000000000000000000000000000000000000000000000000000000005f900000000000000000000000000000000000000000000000000000000000005f000000000000000000000000000000000000000000000000000000000000005fa00000000000000000000000000000000000000000000000000000000000005f100000000000000000000000000000000000000000000000000000000000005fb00000000000000000000000000000000000000000000000000000000000005f200000000000000000000000000000000000000000000000000000000000005fc00000000000000000000000000000000000000000000000000000000000005f300000000000000000000000000000000000000000000000000000000000005fd00000000000000000000000000000000000000000000000000000000000005f400000000000000000000000000000000000000000000000000000000000005fe00000000000000000000000000000000000000000000000000000000000005f500000000000000000000000000000000000000000000000000000000000005ff00000000000000000000000000000000000000000000000000000000000005f6000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000005f7000000000000000000000000000000000000000000000000000000000000060100000000000000000000000000000000000000000000000000000000000005f8000000000000000000000000000000000000000000000000000000000000060200000000000000000000000000000000000000000000000000000000000005f9000000000000000000000000000000000000000000000000000000000000060300000000000000000000000000000000000000000000000000000000000005fa000000000000000000000000000000000000000000000000000000000000060400000000000000000000000000000000000000000000000000000000000005fb000000000000000000000000000000000000000000000000000000000000060500000000000000000000000000000000000000000000000000000000000005fc000000000000000000000000000000000000000000000000000000000000060600000000000000000000000000000000000000000000000000000000000005fd000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000005fe0000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0800c064a9343bfaf1345a5ad188e96aa4c5bad0b4a5590da51a9ff8f3c98ade8d008803d57dd0923c95a01b2bfbee4df6d66dc7baee1d2cd2770575feb86d040200ea64eed9489feb7bdf29bf817a6e8772e549da7b291028852d0dd3810cee9500947e8f904d41be8a4e08b146b4e1f0cd88f55722ef987d1d485c4196ab9f71002e5d9ed5d71bc3bea6edf988c4b9ba7fceb0815180d893852ed343c64ab55c0040f7f519ec89d360d83e242b6c0ce049d2b3356b8cfbf1ff3b733ef0f8a089006f5cfe5fc4a7b87c634f9e253a7cea2052229250d0c0e913eb50b5ef3612de00b759fce0eed36bb653b67255cce111b3529c383bd7d2b758f8cb53a4451f273f0000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006290000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000062a0000000000000000000000000000000000000000000000000000000000000621000000000000000000000000000000000000000000000000000000000000062b0000000000000000000000000000000000000000000000000000000000000622000000000000000000000000000000000000000000000000000000000000062c0000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000062d0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000062e0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000062f00000000000000000000000000000000000000000000000000000000000006260000000000000000000000000000000000000000000000000000000000000630000000000000000000000000000000000000000000000000000000000000062700000000000000000000000000000000000000000000000000000000000006310000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000063200000000000000000000000000000000000000000000000000000000000006290000000000000000000000000000000000000000000000000000000000000633000000000000000000000000000000000000000000000000000000000000062a0000000000000000000000000000000000000000000000000000000000000634000000000000000000000000000000000000000000000000000000000000062b0000000000000000000000000000000000000000000000000000000000000635000000000000000000000000000000000000000000000000000000000000062c0000000000000000000000000000000000000000000000000000000000000636000000000000000000000000000000000000000000000000000000000000062d0000000000000000000000000000000000000000000000000000000000000637000000000000000000000000000000000000000000000000000000000000062e0000000000000000000000000000000000000000000000000000000000000638000000000000000000000000000000000000000000000000000000000000062f00000000000000000000000000000000000000000000000000000000000006390000000000000000000000000000000000000000000000000000000000000630000000000000000000000000000000000000000000000000000000000000063a0000000000000000000000000000000000000000000000000000000000000631000000000000000000000000000000000000000000000000000000000000063b0000000000000000000000000000000000000000000000000000000000000632000000000000000000000000000000000000000000000000000000000000063c0000000000000000000000000000000000000000000000000000000000000633000000000000000000000000000000000000000000000000000000000000063d0000000000000000000000000000000000000000000000000000000000000634000000000000000000000000000000000000000000000000000000000000063e0000000000000000000000000000000000000000000000000000000000000635000000000000000000000000000000000000000000000000000000000000063f00000000000000000000000000000000000000000000000000000000000006360000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000063700000000000000000000000000000000000000000000000000000000000006410000000000000000000000000000000000000000000000000000000000000638000000000000000000000000000000000000000000000000000000000000064200000000000000000000000000000000000000000000000000000000000006390000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000063a0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000063b0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000063c0000000000000000000000000000000000000000000000000000000000000646000000000000000000000000000000000000000000000000000000000000063d0000000000000000000000000000000000000000000000000000000000000647000000000000000000000000000000000000000000000000000000000000063e0000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x00e7daa0660d17d3ae04747bd24c7238da34e77cb04b0b9dd2843dd08f0fd87b", "decodedHeader": { @@ -70,12 +70,12 @@ }, "globalVariables": { "blockNumber": 1, - "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000015", + "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000043", "chainId": 31337, - "timestamp": 1723460076, + "timestamp": 1724320114, "version": 1, - "coinbase": "0x626f9afff6e3b189ec5e445c51dc49adfeb76787", - "feeRecipient": "0x3006484f89d6047e247437886aadc397f0e95715967c3b28802a79b7c176171f", + "coinbase": "0xa7cd83a4518a418b4dfbec14238d07ea9e6a0e58", + "feeRecipient": "0x25ce59a5810d314c43717d1b8e0bb9fb8eb574fb4250817e4125c65496cf12f1", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -106,8 +106,8 @@ } } }, - "header": "0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e00000001000000000000000000000000000000000000000000000000000000000000000400e7daa0660d17d3ae04747bd24c7238da34e77cb04b0b9dd2843dd08f0fd87b00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00d0169cc64b8f1bd695ec8611a5602da48854dc4cc04989c4b63288b339cb1814f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000101a995cda6f326074cf650c6644269e29dbd0532e6a832238345b53ee70c878af000001000deac8396e31bc1196b442ad724bf8f751a245e518147d738cc84b9e1a56b4420000018023866f4c16f3ea1f37dd2ca42d1a635ea909b6c016e45e8434780d3741eb7dbb000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000066b9e9ec626f9afff6e3b189ec5e445c51dc49adfeb767873006484f89d6047e247437886aadc397f0e95715967c3b28802a79b7c176171f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00527b3ec43d9c93df7272603b7d6381e2438c958fa7f901c499e44fde448f02", + "header": "0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e00000001000000000000000000000000000000000000000000000000000000000000000400e7daa0660d17d3ae04747bd24c7238da34e77cb04b0b9dd2843dd08f0fd87b00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00d0169cc64b8f1bd695ec8611a5602da48854dc4cc04989c4b63288b339cb1814f44d672eb357739e42463497f9fdac46623af863eea4d947ca00a497dcdeb3000000101a995cda6f326074cf650c6644269e29dbd0532e6a832238345b53ee70c878af000001000deac8396e31bc1196b442ad724bf8f751a245e518147d738cc84b9e1a56b4420000018023866f4c16f3ea1f37dd2ca42d1a635ea909b6c016e45e8434780d3741eb7dbb000001800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000066c70972a7cd83a4518a418b4dfbec14238d07ea9e6a0e5825ce59a5810d314c43717d1b8e0bb9fb8eb574fb4250817e4125c65496cf12f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x0020d6fe0ac1564351eed062d6592a6255b2148ecda811aebaf64769a9a98092", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_2.json b/l1-contracts/test/fixtures/mixed_block_2.json index 666859288b0..603ca2936a6 100644 --- a/l1-contracts/test/fixtures/mixed_block_2.json +++ b/l1-contracts/test/fixtures/mixed_block_2.json @@ -58,7 +58,7 @@ ] }, "block": { - "archive": "0x134870d4e66a9ef122ee79c14ef6f75c9b34a63fd337a86c3a3ea27b5d08e10a", + "archive": "0x04b567324d50f258764769f7c4d666346e730bbb64572dfb6d3a8a5fb8fe93e3", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e08003bbb1177505f3433bb062787fcac6585d30fa1a7e0b809ca5eef1cecc56cd0002d5b86280022d106b72e4425ea49f927ca2b8138fc13b3d9feeaf36ae61fb100adab9d66b73ae23a6e9127ebe0bcd963ef4312dd66878a6be131d39a7ee01c00d48f30dbb82c96c734c8abe33f4f9f75e6d0ba4462ee07d73c5335e04a02e900f31a3a4e7333ac6043a929fca12f5347e9e8bf1d67f5993860a774f10b77bc00230e3132bfa5df23e2e018b20cd4e0c75555825ee7924da73f017a279d39cd0095e2affd6b67c6ecbf77fa1e638139498e1642abb468c58ca8ce275260ea6100362e0941035fd171fab926caf55d18b22f7de99d60ac6f454386a9cce4a1ff3f0000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006690000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000066a0000000000000000000000000000000000000000000000000000000000000661000000000000000000000000000000000000000000000000000000000000066b0000000000000000000000000000000000000000000000000000000000000662000000000000000000000000000000000000000000000000000000000000066c0000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000066d0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000066e0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000066f00000000000000000000000000000000000000000000000000000000000006660000000000000000000000000000000000000000000000000000000000000670000000000000000000000000000000000000000000000000000000000000066700000000000000000000000000000000000000000000000000000000000006710000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000067200000000000000000000000000000000000000000000000000000000000006690000000000000000000000000000000000000000000000000000000000000673000000000000000000000000000000000000000000000000000000000000066a0000000000000000000000000000000000000000000000000000000000000674000000000000000000000000000000000000000000000000000000000000066b0000000000000000000000000000000000000000000000000000000000000675000000000000000000000000000000000000000000000000000000000000066c0000000000000000000000000000000000000000000000000000000000000676000000000000000000000000000000000000000000000000000000000000066d0000000000000000000000000000000000000000000000000000000000000677000000000000000000000000000000000000000000000000000000000000066e0000000000000000000000000000000000000000000000000000000000000678000000000000000000000000000000000000000000000000000000000000066f00000000000000000000000000000000000000000000000000000000000006790000000000000000000000000000000000000000000000000000000000000670000000000000000000000000000000000000000000000000000000000000067a0000000000000000000000000000000000000000000000000000000000000671000000000000000000000000000000000000000000000000000000000000067b0000000000000000000000000000000000000000000000000000000000000672000000000000000000000000000000000000000000000000000000000000067c0000000000000000000000000000000000000000000000000000000000000673000000000000000000000000000000000000000000000000000000000000067d0000000000000000000000000000000000000000000000000000000000000674000000000000000000000000000000000000000000000000000000000000067e0000000000000000000000000000000000000000000000000000000000000675000000000000000000000000000000000000000000000000000000000000067f00000000000000000000000000000000000000000000000000000000000006760000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000067700000000000000000000000000000000000000000000000000000000000006810000000000000000000000000000000000000000000000000000000000000678000000000000000000000000000000000000000000000000000000000000068200000000000000000000000000000000000000000000000000000000000006790000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000067a0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000067b0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000067c0000000000000000000000000000000000000000000000000000000000000686000000000000000000000000000000000000000000000000000000000000067d0000000000000000000000000000000000000000000000000000000000000687000000000000000000000000000000000000000000000000000000000000067e0000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be08004a32502b5d2a0cf5d776c92ef74de61a28e7882bdadeb3b0530f472704604300808c2412e2725ecaa6a6bd77e3159349e238dc7817f906ba32afd40b3cb3cb00d7d4e3b313c4cce9bd98c317ea715847a92d795b82a6f8b8144b7c61bee64200b76f07678c289f41378029b1353a73e1afbe241612a97c23e7fc059099f49d00c72046b39a9dc902cee36db5214c72315636bd824abfabdf80b1c5e6a01fd7006e0a74fec166a12f5a62954776784f01cba3be7ab876eef2e49a2ab7a5b0f900c83ddd8f6b91086bc83485adbe8056212b4d33b91840cd3dc649f9736881460022441e76225010acce7f429dc754fb3260ae1d387937978f69c67a879ed0733f0000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a900000000000000000000000000000000000000000000000000000000000006a000000000000000000000000000000000000000000000000000000000000006aa00000000000000000000000000000000000000000000000000000000000006a100000000000000000000000000000000000000000000000000000000000006ab00000000000000000000000000000000000000000000000000000000000006a200000000000000000000000000000000000000000000000000000000000006ac00000000000000000000000000000000000000000000000000000000000006a300000000000000000000000000000000000000000000000000000000000006ad00000000000000000000000000000000000000000000000000000000000006a400000000000000000000000000000000000000000000000000000000000006ae00000000000000000000000000000000000000000000000000000000000006a500000000000000000000000000000000000000000000000000000000000006af00000000000000000000000000000000000000000000000000000000000006a600000000000000000000000000000000000000000000000000000000000006b000000000000000000000000000000000000000000000000000000000000006a700000000000000000000000000000000000000000000000000000000000006b100000000000000000000000000000000000000000000000000000000000006a800000000000000000000000000000000000000000000000000000000000006b200000000000000000000000000000000000000000000000000000000000006a900000000000000000000000000000000000000000000000000000000000006b300000000000000000000000000000000000000000000000000000000000006aa00000000000000000000000000000000000000000000000000000000000006b400000000000000000000000000000000000000000000000000000000000006ab00000000000000000000000000000000000000000000000000000000000006b500000000000000000000000000000000000000000000000000000000000006ac00000000000000000000000000000000000000000000000000000000000006b600000000000000000000000000000000000000000000000000000000000006ad00000000000000000000000000000000000000000000000000000000000006b700000000000000000000000000000000000000000000000000000000000006ae00000000000000000000000000000000000000000000000000000000000006b800000000000000000000000000000000000000000000000000000000000006af00000000000000000000000000000000000000000000000000000000000006b900000000000000000000000000000000000000000000000000000000000006b000000000000000000000000000000000000000000000000000000000000006ba00000000000000000000000000000000000000000000000000000000000006b100000000000000000000000000000000000000000000000000000000000006bb00000000000000000000000000000000000000000000000000000000000006b200000000000000000000000000000000000000000000000000000000000006bc00000000000000000000000000000000000000000000000000000000000006b300000000000000000000000000000000000000000000000000000000000006bd00000000000000000000000000000000000000000000000000000000000006b400000000000000000000000000000000000000000000000000000000000006be00000000000000000000000000000000000000000000000000000000000006b500000000000000000000000000000000000000000000000000000000000006bf00000000000000000000000000000000000000000000000000000000000006b600000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006b700000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006b800000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006b900000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006ba00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006bb00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006bc00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006bd00000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006be00000000000000000000000000000000000000000000000000000000000006c80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0800bb07f923e24c36227d717557d58d32b99370b81f7a70d1835becc1114f7d7700624291eff6ab801e5668bc6619a3df132f8b392b063f09dfe8a69e38224eb200bd6b195f8716ab3dc93c44037cac579d25d0e77c2782b5aa62534ee25d36bc008c99d470d2c53624a8c5bedfeffdcc5356f6da89ee0e372b3ea3fa4f8cd652009944e00a3f9a7d2e8a535d3a210c3271d5732518037704d67ef5d42a8b82c200523014cb6eabe4366c6e599ba96534fc15ecc804a13fbaaacf8717e1b0a8d20005621252c4b36c113f21ad6c13b99e5cef514bdd98ef0aae4075b5cb5a000a00d80cb2a60aae6c3d2e7d27fb1519a708a18bb5b5085f78684bdee7512856a93f00000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006ea00000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006eb00000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006ec00000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006ed00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006ee00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006ef00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006f100000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006f200000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000006f300000000000000000000000000000000000000000000000000000000000006ea00000000000000000000000000000000000000000000000000000000000006f400000000000000000000000000000000000000000000000000000000000006eb00000000000000000000000000000000000000000000000000000000000006f500000000000000000000000000000000000000000000000000000000000006ec00000000000000000000000000000000000000000000000000000000000006f600000000000000000000000000000000000000000000000000000000000006ed00000000000000000000000000000000000000000000000000000000000006f700000000000000000000000000000000000000000000000000000000000006ee00000000000000000000000000000000000000000000000000000000000006f800000000000000000000000000000000000000000000000000000000000006ef00000000000000000000000000000000000000000000000000000000000006f900000000000000000000000000000000000000000000000000000000000006f000000000000000000000000000000000000000000000000000000000000006fa00000000000000000000000000000000000000000000000000000000000006f100000000000000000000000000000000000000000000000000000000000006fb00000000000000000000000000000000000000000000000000000000000006f200000000000000000000000000000000000000000000000000000000000006fc00000000000000000000000000000000000000000000000000000000000006f300000000000000000000000000000000000000000000000000000000000006fd00000000000000000000000000000000000000000000000000000000000006f400000000000000000000000000000000000000000000000000000000000006fe00000000000000000000000000000000000000000000000000000000000006f500000000000000000000000000000000000000000000000000000000000006ff00000000000000000000000000000000000000000000000000000000000006f6000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000006f7000000000000000000000000000000000000000000000000000000000000070100000000000000000000000000000000000000000000000000000000000006f8000000000000000000000000000000000000000000000000000000000000070200000000000000000000000000000000000000000000000000000000000006f9000000000000000000000000000000000000000000000000000000000000070300000000000000000000000000000000000000000000000000000000000006fa000000000000000000000000000000000000000000000000000000000000070400000000000000000000000000000000000000000000000000000000000006fb000000000000000000000000000000000000000000000000000000000000070500000000000000000000000000000000000000000000000000000000000006fc000000000000000000000000000000000000000000000000000000000000070600000000000000000000000000000000000000000000000000000000000006fd000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000006fe0000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0800a38df4d53fe5da3d48c97dd0f58e7a52faade40c8f50bc0f6408a2b5b3829800a3d4b994758c6630518cce3116391874b9b3b8a1bbcb36485d2702f05af359004c06e9dd14418667d7c66384699665f9222ed08be87c67293a2f1b6b4c41aa006b77b11703f0e3d21aa68c9f6d2ae8ad94ecafdb56be0c4605a0c6723e9ddc0049a087e215b640d8360f8dd98e07c77e4d2025a0dcdcaf78bc00bd6fde09680014741a52013a10622de90b1a7854f1203af5c97121a4b3774c249fba6e0dba00c783bd01c4a4cafe83fd3b4d1ce0c555be4b6d1f772cccccf86049f9af0bbe002ff3ac4d7e2f1caf1fb30e1d20eba5be2b6a42dd54690dee988a934026491e3f0000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007290000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000072a0000000000000000000000000000000000000000000000000000000000000721000000000000000000000000000000000000000000000000000000000000072b0000000000000000000000000000000000000000000000000000000000000722000000000000000000000000000000000000000000000000000000000000072c0000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000072d0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000072e0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000072f00000000000000000000000000000000000000000000000000000000000007260000000000000000000000000000000000000000000000000000000000000730000000000000000000000000000000000000000000000000000000000000072700000000000000000000000000000000000000000000000000000000000007310000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000073200000000000000000000000000000000000000000000000000000000000007290000000000000000000000000000000000000000000000000000000000000733000000000000000000000000000000000000000000000000000000000000072a0000000000000000000000000000000000000000000000000000000000000734000000000000000000000000000000000000000000000000000000000000072b0000000000000000000000000000000000000000000000000000000000000735000000000000000000000000000000000000000000000000000000000000072c0000000000000000000000000000000000000000000000000000000000000736000000000000000000000000000000000000000000000000000000000000072d0000000000000000000000000000000000000000000000000000000000000737000000000000000000000000000000000000000000000000000000000000072e0000000000000000000000000000000000000000000000000000000000000738000000000000000000000000000000000000000000000000000000000000072f00000000000000000000000000000000000000000000000000000000000007390000000000000000000000000000000000000000000000000000000000000730000000000000000000000000000000000000000000000000000000000000073a0000000000000000000000000000000000000000000000000000000000000731000000000000000000000000000000000000000000000000000000000000073b0000000000000000000000000000000000000000000000000000000000000732000000000000000000000000000000000000000000000000000000000000073c0000000000000000000000000000000000000000000000000000000000000733000000000000000000000000000000000000000000000000000000000000073d0000000000000000000000000000000000000000000000000000000000000734000000000000000000000000000000000000000000000000000000000000073e0000000000000000000000000000000000000000000000000000000000000735000000000000000000000000000000000000000000000000000000000000073f00000000000000000000000000000000000000000000000000000000000007360000000000000000000000000000000000000000000000000000000000000740000000000000000000000000000000000000000000000000000000000000073700000000000000000000000000000000000000000000000000000000000007410000000000000000000000000000000000000000000000000000000000000738000000000000000000000000000000000000000000000000000000000000074200000000000000000000000000000000000000000000000000000000000007390000000000000000000000000000000000000000000000000000000000000743000000000000000000000000000000000000000000000000000000000000073a0000000000000000000000000000000000000000000000000000000000000744000000000000000000000000000000000000000000000000000000000000073b0000000000000000000000000000000000000000000000000000000000000745000000000000000000000000000000000000000000000000000000000000073c0000000000000000000000000000000000000000000000000000000000000746000000000000000000000000000000000000000000000000000000000000073d0000000000000000000000000000000000000000000000000000000000000747000000000000000000000000000000000000000000000000000000000000073e0000000000000000000000000000000000000000000000000000000000000748000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x008e46703a73fee39cb8a1bd50a03e090eb250de227639bbf1448462452bd646", "decodedHeader": { @@ -70,12 +70,12 @@ }, "globalVariables": { "blockNumber": 2, - "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000026", + "slotNumber": "0x0000000000000000000000000000000000000000000000000000000000000055", "chainId": 31337, - "timestamp": 1723460280, + "timestamp": 1724320330, "version": 1, - "coinbase": "0x626f9afff6e3b189ec5e445c51dc49adfeb76787", - "feeRecipient": "0x3006484f89d6047e247437886aadc397f0e95715967c3b28802a79b7c176171f", + "coinbase": "0xa7cd83a4518a418b4dfbec14238d07ea9e6a0e58", + "feeRecipient": "0x25ce59a5810d314c43717d1b8e0bb9fb8eb574fb4250817e4125c65496cf12f1", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -83,7 +83,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0f16cd5260bfdd24b99a5aa4fd778c58f4348f57e5c9697bde3f2ec56a026d56" + "root": "0x2e509ada109d80ef634c0eca74fecd28b17727847e3b21cf01961c73b1b58978" }, "stateReference": { "l1ToL2MessageTree": { @@ -106,8 +106,8 @@ } } }, - "header": "0x0f16cd5260bfdd24b99a5aa4fd778c58f4348f57e5c9697bde3f2ec56a026d56000000020000000000000000000000000000000000000000000000000000000000000004008e46703a73fee39cb8a1bd50a03e090eb250de227639bbf1448462452bd64600212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700d4b436f0c9857646ed7cf0836bd61c857183956d1acefe52fc99ef7b333a38224c43ed89fb9404e06e7382170d1e279a53211bab61876f38d8a4180390b7ad0000002017752a4346cf34b18277458ace73be4895316cb1c3cbce628d573d5d10cde7ce00000200152db065a479b5630768d6c5250bb6233e71729f857c16cffa98569acf90a2bf000002800a020b31737a919cbd6b0c0fe25d466a11e2186eb8038cd63a5e7d2900473d53000002800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000066b9eab8626f9afff6e3b189ec5e445c51dc49adfeb767873006484f89d6047e247437886aadc397f0e95715967c3b28802a79b7c176171f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x004eda0b54627380c070bcc54fec28054dc20d47285a458a30c9159eba44a2ad", + "header": "0x2e509ada109d80ef634c0eca74fecd28b17727847e3b21cf01961c73b1b58978000000020000000000000000000000000000000000000000000000000000000000000004008e46703a73fee39cb8a1bd50a03e090eb250de227639bbf1448462452bd64600212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700d4b436f0c9857646ed7cf0836bd61c857183956d1acefe52fc99ef7b333a38224c43ed89fb9404e06e7382170d1e279a53211bab61876f38d8a4180390b7ad0000002017752a4346cf34b18277458ace73be4895316cb1c3cbce628d573d5d10cde7ce00000200152db065a479b5630768d6c5250bb6233e71729f857c16cffa98569acf90a2bf000002800a020b31737a919cbd6b0c0fe25d466a11e2186eb8038cd63a5e7d2900473d53000002800000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000066c70a4aa7cd83a4518a418b4dfbec14238d07ea9e6a0e5825ce59a5810d314c43717d1b8e0bb9fb8eb574fb4250817e4125c65496cf12f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x001c5bc0fe3f9edc312a5599452feb890df0d72a034179b49335c34055ba9c05", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index c48ba0bf3a2..dad40cec374 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -109,12 +109,9 @@ contract SpartaTest is DecoderBase { } assertGt(rollup.getValidators().length, rollup.TARGET_COMMITTEE_SIZE(), "Not enough validators"); - _testBlock("mixed_block_1", false, 0, false); // We run a block before the epoch with validators - - uint256 ts = block.timestamp + rollup.EPOCH_DURATION() * rollup.SLOT_DURATION(); - uint256 committeSize = rollup.TARGET_COMMITTEE_SIZE() * 2 / 3 + (_insufficientSigs ? 0 : 1); - _testBlock("mixed_block_2", _insufficientSigs, committeSize, false, ts); // We need signatures! + + _testBlock("mixed_block_1", _insufficientSigs, committeSize, false); assertEq( rollup.getEpochCommittee(rollup.getCurrentEpoch()).length, @@ -128,8 +125,8 @@ contract SpartaTest is DecoderBase { return; } - _testBlock("mixed_block_1", false, 0, false); // We run a block before the epoch with validators - _testBlock("mixed_block_2", false, 3, false); // We need signatures! + _testBlock("mixed_block_1", false, 3, false); + _testBlock("mixed_block_2", false, 3, false); } function testInvalidProposer() public setup(4) { @@ -137,8 +134,7 @@ contract SpartaTest is DecoderBase { return; } - _testBlock("mixed_block_1", false, 0, false); // We run a block before the epoch with validators - _testBlock("mixed_block_2", true, 3, true); // We need signatures! + _testBlock("mixed_block_1", true, 3, true); } function testInsufficientSigs() public setup(4) { @@ -146,8 +142,7 @@ contract SpartaTest is DecoderBase { return; } - _testBlock("mixed_block_1", false, 0, false); // We run a block before the epoch with validators - _testBlock("mixed_block_2", true, 2, false); // We need signatures! + _testBlock("mixed_block_1", true, 2, false); } struct StructToAvoidDeepStacks { @@ -161,16 +156,6 @@ contract SpartaTest is DecoderBase { bool _expectRevert, uint256 _signatureCount, bool _invalidaProposer - ) internal { - _testBlock(_name, _expectRevert, _signatureCount, _invalidaProposer, 0); - } - - function _testBlock( - string memory _name, - bool _expectRevert, - uint256 _signatureCount, - bool _invalidaProposer, - uint256 _ts ) internal { DecoderBase.Full memory full = load(_name); bytes memory header = full.block.header; @@ -180,18 +165,7 @@ contract SpartaTest is DecoderBase { StructToAvoidDeepStacks memory ree; // We jump to the time of the block. (unless it is in the past) - vm.warp(max(block.timestamp, max(full.block.decodedHeader.globalVariables.timestamp, _ts))); - - if (_ts > 0) { - // Update the timestamp and slot in the header - uint256 slotValue = rollup.getCurrentSlot(); - uint256 timestampMemoryPosition = 0x01b4; - uint256 slotMemoryPosition = 0x0194; - assembly { - mstore(add(header, add(0x20, timestampMemoryPosition)), _ts) - mstore(add(header, add(0x20, slotMemoryPosition)), slotValue) - } - } + vm.warp(max(block.timestamp, full.block.decodedHeader.globalVariables.timestamp)); _populateInbox(full.populate.sender, full.populate.recipient, full.populate.l1ToL2Content); @@ -248,7 +222,7 @@ contract SpartaTest is DecoderBase { rollup.process(header, archive, bytes32(0)); } - assertEq(_expectRevert, ree.shouldRevert, "Invalid revert expectation"); + assertEq(_expectRevert, ree.shouldRevert, "Does not match revert expectation"); bytes32 l2ToL1MessageTreeRoot; { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 8c567281c1f..ebb231a4895 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -134,7 +134,13 @@ global INITIALIZATION_SLOT_SEPARATOR: Field = 1000_000_000; global INITIAL_L2_BLOCK_NUM: Field = 1; global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; global ETHEREUM_SLOT_DURATION: u32 = 12; +// AZTEC_SLOT_DURATION should be a multiple of ETHEREUM_SLOT_DURATION +global AZTEC_SLOT_DURATION: u32 = ETHEREUM_SLOT_DURATION * 1; +global AZTEC_EPOCH_DURATION: u32 = 48; global IS_DEV_NET: bool = true; +// The following is taken from building a block and looking at the `lastArchive` value in it. +// You can run the `integration_l1_publisher.test.ts` and look at the first blocks in the fixtures. +global GENESIS_ARCHIVE_ROOT: Field = 0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e; // The following and the value in `deploy_l1_contracts´ must match. We should not have the code both places, but // we are running into circular dependency issues. #3342 global FEE_JUICE_INITIAL_MINT: Field = 20000000000; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 71ba8886eba..306aca91406 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -88,7 +88,10 @@ export const INITIALIZATION_SLOT_SEPARATOR = 1000000000; export const INITIAL_L2_BLOCK_NUM = 1; export const BLOB_SIZE_IN_BYTES = 126976; export const ETHEREUM_SLOT_DURATION = 12; +export const AZTEC_SLOT_DURATION = 12; +export const AZTEC_EPOCH_DURATION = 48; export const IS_DEV_NET = 1; +export const GENESIS_ARCHIVE_ROOT = 8142738430000951296386584486068033372964809139261822027365426310856631083550n; export const FEE_JUICE_INITIAL_MINT = 20000000000; export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; diff --git a/yarn-project/end-to-end/package.json b/yarn-project/end-to-end/package.json index 98d1e156cd4..e1bdd04b338 100644 --- a/yarn-project/end-to-end/package.json +++ b/yarn-project/end-to-end/package.json @@ -15,12 +15,12 @@ "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "test": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", - "test:profile": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 0x --output-dir \"flame_graph/{pid}.0x\" -- node --experimental-vm-modules ../node_modules/jest/bin/jest.js --runInBand --testTimeout=300000 --forceExit", + "test": "TIME_TRAVELER=${TIME_TRAVELER:-true} LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", + "test:profile": "TIME_TRAVELER=${TIME_TRAVELER:-true} LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 0x --output-dir \"flame_graph/{pid}.0x\" -- node --experimental-vm-modules ../node_modules/jest/bin/jest.js --runInBand --testTimeout=300000 --forceExit", "serve:flames": "python3 -m http.server --directory \"flame_graph\" 8000", - "test:debug": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --inspect --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", - "test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"", - "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --no-cache --runInBand --config jest.integration.config.json", + "test:debug": "TIME_TRAVELER=${TIME_TRAVELER:-true} LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --inspect --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", + "test:integration": "TIME_TRAVELER=${TIME_TRAVELER:-true} concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"", + "test:integration:run": "TIME_TRAVELER=${TIME_TRAVELER:-true} NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --no-cache --runInBand --config jest.integration.config.json", "test:unit": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest src/fixtures" }, "dependencies": { diff --git a/yarn-project/end-to-end/package.local.json b/yarn-project/end-to-end/package.local.json index 62f136fa45d..c76111c3c26 100644 --- a/yarn-project/end-to-end/package.local.json +++ b/yarn-project/end-to-end/package.local.json @@ -2,7 +2,7 @@ "scripts": { "build": "yarn clean && tsc -b && webpack", "formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src", - "test": "LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", + "test": "TIME_TRAVELER=${TIME_TRAVELER:-true} LOG_LEVEL=${LOG_LEVEL:-verbose} DEBUG_COLORS=1 NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --testTimeout=300000 --forceExit", "test:unit": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest src/fixtures" } } \ No newline at end of file diff --git a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index 4f6d31e5cfc..563f6cdd84d 100644 --- a/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts @@ -21,6 +21,7 @@ import { import { ETHEREUM_SLOT_DURATION, EthAddress, + GENESIS_ARCHIVE_ROOT, GasFees, type Header, KernelCircuitPublicInputs, @@ -113,10 +114,10 @@ describe('L1Publisher integration', () => { // If running ANVIL locally, you can use ETHEREUM_HOST="http://0.0.0.0:8545" const AZTEC_GENERATE_TEST_DATA = !!process.env.AZTEC_GENERATE_TEST_DATA; - const setTimeToNextSlot = async () => { + const progressTimeBySlot = async (slotsToJump = 1n) => { const currentTime = (await publicClient.getBlock()).timestamp; const currentSlot = await rollup.read.getCurrentSlot(); - const timestamp = (await rollup.read.getTimestampForSlot([currentSlot + 1n])) - BigInt(ETHEREUM_SLOT_DURATION); + const timestamp = await rollup.read.getTimestampForSlot([currentSlot + slotsToJump]); if (timestamp > currentTime) { await ethCheatCodes.warp(Number(timestamp)); } @@ -169,6 +170,7 @@ describe('L1Publisher integration', () => { publisherPrivateKey: sequencerPK, l1PublishRetryIntervalMS: 100, l1ChainId: 31337, + timeTraveler: true, }, new NoopTelemetryClient(), ); @@ -178,7 +180,9 @@ describe('L1Publisher integration', () => { prevHeader = builderDb.getInitialHeader(); - await setTimeToNextSlot(); + // We jump to the next epoch such that the committee can be setup. + const timeToJump = await rollup.read.EPOCH_DURATION(); + await progressTimeBySlot(timeToJump); }); const makeEmptyProcessedTx = () => @@ -345,7 +349,7 @@ describe('L1Publisher integration', () => { it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { const archiveInRollup_ = await rollup.read.archive(); - expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(Buffer.alloc(32, 0)); + expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(new Fr(GENESIS_ARCHIVE_ROOT).toBuffer()); const blockNumber = await publicClient.getBlockNumber(); // random recipient address, just kept consistent for easy testing ts/sol. @@ -463,14 +467,14 @@ describe('L1Publisher integration', () => { // We wipe the messages from previous iteration nextL1ToL2Messages = []; - // @todo @LHerskind need to make sure that time have progressed to the next slot! - await setTimeToNextSlot(); + // Make sure that time have progressed to the next slot! + await progressTimeBySlot(); } }); it(`Build ${numberOfConsecutiveBlocks} blocks of 2 empty txs building on each other`, async () => { const archiveInRollup_ = await rollup.read.archive(); - expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(Buffer.alloc(32, 0)); + expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(new Fr(GENESIS_ARCHIVE_ROOT).toBuffer()); const blockNumber = await publicClient.getBlockNumber(); @@ -545,7 +549,7 @@ describe('L1Publisher integration', () => { }); expect(ethTx.input).toEqual(expectedData); - await setTimeToNextSlot(); + await progressTimeBySlot(); } }); }); diff --git a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts index fed7d9ce6c1..c3ec8d93737 100644 --- a/yarn-project/end-to-end/src/e2e_p2p_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p_network.test.ts @@ -16,6 +16,7 @@ import { RollupAbi } from '@aztec/l1-artifacts'; import { type BootstrapNode } from '@aztec/p2p'; import { type PXEService, createPXEService, getPXEServiceConfig as getRpcConfig } from '@aztec/pxe'; +import { jest } from '@jest/globals'; import fs from 'fs'; import { getContract } from 'viem'; import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; @@ -47,7 +48,13 @@ describe('e2e_p2p_network', () => { let deployL1ContractsValues: DeployL1Contracts; beforeEach(async () => { - ({ teardown, config, logger, deployL1ContractsValues } = await setup(0)); + // If we want to test with interval mining, we can use the local host and start `anvil --block-time 12` + const useLocalHost = false; + if (useLocalHost) { + jest.setTimeout(300_000); + } + const options = useLocalHost ? { l1RpcUrl: 'http://127.0.0.1:8545' } : {}; + ({ teardown, config, logger, deployL1ContractsValues } = await setup(0, options)); // It would likely be useful if we had the sequencers in such that they don't spam each other. // However, even if they do, it should still work. Not sure what caused the failure // Would be easier if I could see the errors from anvil as well, but those seem to be hidden. @@ -63,7 +70,7 @@ describe('e2e_p2p_network', () => { const hdAccount = mnemonicToAccount(MNEMONIC, { addressIndex: 1 }); const publisherPrivKey = Buffer.from(hdAccount.getHdKey().privateKey!); const account = privateKeyToAccount(`0x${publisherPrivKey!.toString('hex')}`); - await rollup.write.addValidator([account.address]); + await rollup.write.addValidator([account.address], { gas: 1_000_000n }); logger.info(`Adding sequencer ${account.address}`); } else { // Add all nodes as validators - they will all sign attestations of each other's proposals @@ -71,17 +78,19 @@ describe('e2e_p2p_network', () => { const hdAccount = mnemonicToAccount(MNEMONIC, { addressIndex: i + 1 }); const publisherPrivKey = Buffer.from(hdAccount.getHdKey().privateKey!); const account = privateKeyToAccount(`0x${publisherPrivKey!.toString('hex')}`); - await rollup.write.addValidator([account.address]); + await rollup.write.addValidator([account.address], { gas: 1_000_000n }); logger.info(`Adding sequencer ${account.address}`); } } - // Now we jump ahead to the next epoch, such that the next epoch begins - const timeToJump = (await rollup.read.EPOCH_DURATION()) * (await rollup.read.SLOT_DURATION()); + //@note Now we jump ahead to the next epoch such that the validator committee is picked + // INTERVAL MINING: If we are using anvil interval mining this will NOT progress the time! + // Which means that the validator set will still be empty! So anyone can propose. + const slotsInEpoch = await rollup.read.EPOCH_DURATION(); + const timestamp = await rollup.read.getTimestampForSlot([slotsInEpoch]); const cheatCodes = new EthCheatCodes(config.l1RpcUrl); - const timestamp = (await cheatCodes.timestamp()) + Number(timeToJump); - await cheatCodes.warp(timestamp); + await cheatCodes.warp(Number(timestamp)); bootstrapNode = await createBootstrapNode(BOOT_NODE_UDP_PORT); bootstrapNodeEnr = bootstrapNode.getENR().encodeTxt(); @@ -175,7 +184,7 @@ describe('e2e_p2p_network', () => { i + 1 + BOOT_NODE_UDP_PORT, undefined, i, - /*validators*/ false, + /*validators*/ !IS_DEV_NET, `./data-${i}`, ); logger.info(`Node ${i} restarted`); diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index bf4d2b00447..9eb75129880 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -152,7 +152,7 @@ export const deployL1Contracts = async ( // We are assuming that you are running this on a local anvil node which have 1s block times // To align better with actual deployment, we update the block interval to 12s // The code is same as `setBlockInterval` in `cheat_codes.ts` - const rpcCall = async (rpcUrl: string, method: string, params: any[]) => { + const rpcCall = async (method: string, params: any[]) => { const paramsString = JSON.stringify(params); const content = { body: `{"jsonrpc":"2.0", "method": "${method}", "params": ${paramsString}, "id": 1}`, @@ -163,7 +163,7 @@ export const deployL1Contracts = async ( }; if (chain.id == foundry.id) { const interval = 12; - const res = await rpcCall(rpcUrl, 'anvil_setBlockTimestampInterval', [interval]); + const res = await rpcCall('anvil_setBlockTimestampInterval', [interval]); if (res.error) { throw new Error(`Error setting block interval: ${res.error.message}`); } @@ -205,6 +205,7 @@ export const deployL1Contracts = async ( // @note This value MUST match what is in `constants.nr`. It is currently specified here instead of just importing // because there is circular dependency hell. This is a temporary solution. #3342 + // @todo #8084 const FEE_JUICE_INITIAL_MINT = 20000000000; const receipt = await feeJuice.write.mint([feeJuicePortalAddress.toString(), FEE_JUICE_INITIAL_MINT], {} as any); await publicClient.waitForTransactionReceipt({ hash: receipt }); @@ -236,13 +237,35 @@ export const deployL1Contracts = async ( ]); logger.info(`Deployed Rollup at ${rollupAddress}`); + const rollup = getContract({ + address: getAddress(rollupAddress.toString()), + abi: contractsToDeploy.rollup.contractAbi, + client: walletClient, + }); + + // @note We make a time jump PAST the very first slot to not have to deal with the edge case of the first slot. + // The edge case being that the genesis block is already occupying slot 0, so we cannot have another block. + try { + // Need to get the time + const currentSlot = (await rollup.read.getCurrentSlot([])) as bigint; + + if (BigInt(currentSlot) === 0n) { + const ts = Number(await rollup.read.getTimestampForSlot([1])); + await rpcCall('evm_setNextBlockTimestamp', [ts]); + await rpcCall('hardhat_mine', [1]); + const currentSlot = (await rollup.read.getCurrentSlot([])) as bigint; + + if (BigInt(currentSlot) !== 1n) { + throw new Error(`Error jumping time: current slot is ${currentSlot}`); + } + logger.info(`Jumped to slot 1`); + } + } catch (e) { + throw new Error(`Error jumping time: ${e}`); + } + // Set initial blocks as proven if requested if (args.assumeProvenUntil && args.assumeProvenUntil > 0) { - const rollup = getContract({ - address: getAddress(rollupAddress.toString()), - abi: contractsToDeploy.rollup.contractAbi, - client: walletClient, - }); await rollup.write.setAssumeProvenUntilBlockNumber([BigInt(args.assumeProvenUntil)], { account }); logger.info(`Set Rollup assumedProvenUntil to ${args.assumeProvenUntil}`); } diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index 2d9a5029351..7f034f51296 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -63,6 +63,7 @@ export type EnvVar = | 'SEQ_PUBLISHER_PRIVATE_KEY' | 'SEQ_REQUIRED_CONFIRMATIONS' | 'SEQ_PUBLISH_RETRY_INTERVAL_MS' + | 'TIME_TRAVELER' | 'VERSION' | 'SEQ_DISABLED' | 'PROVER_DISABLED' diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index a6d7d7f0fec..835dd9bbea1 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -24,6 +24,7 @@ "test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json" }, "dependencies": { + "@aztec/aztec.js": "workspace:^", "@aztec/bb-prover": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", diff --git a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts index f37db0af1cd..91da4e1b46c 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts @@ -52,23 +52,26 @@ export class GlobalVariableBuilder { * @param blockNumber - The block number to build global variables for. * @param coinbase - The address to receive block reward. * @param feeRecipient - The address to receive fees. + * @param slotNumber - The slot number to use for the global variables, if undefined it will be calculated. * @returns The global variables for the given block number. */ public async buildGlobalVariables( blockNumber: Fr, coinbase: EthAddress, feeRecipient: AztecAddress, + slotNumber?: bigint, ): Promise { const version = new Fr(await this.rollupContract.read.VERSION()); const chainId = new Fr(this.publicClient.chain.id); - const ts = (await this.publicClient.getBlock()).timestamp; + if (slotNumber === undefined) { + const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); + slotNumber = await this.rollupContract.read.getSlotAt([ts]); + } - // Not just the current slot, the slot of the next block. - const slot = await this.rollupContract.read.getSlotAt([ts + BigInt(ETHEREUM_SLOT_DURATION)]); - const timestamp = await this.rollupContract.read.getTimestampForSlot([slot]); + const timestamp = await this.rollupContract.read.getTimestampForSlot([slotNumber]); - const slotFr = new Fr(slot); + const slotFr = new Fr(slotNumber); const timestampFr = new Fr(timestamp); const gasFees = GasFees.default(); diff --git a/yarn-project/sequencer-client/src/publisher/config.ts b/yarn-project/sequencer-client/src/publisher/config.ts index bfe5eb42943..b31fdd3b251 100644 --- a/yarn-project/sequencer-client/src/publisher/config.ts +++ b/yarn-project/sequencer-client/src/publisher/config.ts @@ -1,5 +1,5 @@ import { type L1ReaderConfig, NULL_KEY } from '@aztec/ethereum'; -import { type ConfigMappingsType, getConfigFromMappings } from '@aztec/foundation/config'; +import { type ConfigMappingsType, booleanConfigHelper, getConfigFromMappings } from '@aztec/foundation/config'; /** * The configuration of the rollup transaction publisher. @@ -24,6 +24,11 @@ export interface PublisherConfig { * The interval to wait between publish retries. */ l1PublishRetryIntervalMS: number; + /** + * Whether the publisher is a time traveler and can warp the underlying chain + * @todo #8153 - Remove this flag once the time traveler is removed + */ + timeTraveler: boolean; } export const getTxSenderConfigMappings: ( @@ -64,6 +69,11 @@ export const getPublisherConfigMappings: (scope: 'PROVER' | 'SEQ') => ConfigMapp defaultValue: 1000, description: 'The interval to wait between publish retries.', }, + timeTraveler: { + env: `TIME_TRAVELER`, + description: 'Whether the publisher is a time traveler and can warp the underlying chain', + ...booleanConfigHelper(), + }, }); export function getPublisherConfigFromEnv(scope: 'PROVER' | 'SEQ'): PublisherConfig { diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts index dda5091237f..33e0dcc7325 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts @@ -1,5 +1,5 @@ import { L2Block } from '@aztec/circuit-types'; -import { EthAddress, Fr } from '@aztec/circuits.js'; +import { EthAddress } from '@aztec/circuits.js'; import { sleep } from '@aztec/foundation/sleep'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; @@ -18,7 +18,11 @@ interface MockAvailabilityOracleRead { } class MockAvailabilityOracle { - constructor(public write: MockAvailabilityOracleWrite, public read: MockAvailabilityOracleRead) {} + constructor( + public write: MockAvailabilityOracleWrite, + public simulate: MockAvailabilityOracleWrite, + public read: MockAvailabilityOracleRead, + ) {} } interface MockPublicClient { @@ -41,19 +45,26 @@ interface MockRollupContractWrite { interface MockRollupContractRead { archive: () => Promise<`0x${string}`>; + getCurrentSlot(): Promise; } class MockRollupContract { - constructor(public write: MockRollupContractWrite, public read: MockRollupContractRead) {} + constructor( + public write: MockRollupContractWrite, + public simulate: MockRollupContractWrite, + public read: MockRollupContractRead, + ) {} } describe('L1Publisher', () => { let rollupContractRead: MockProxy; let rollupContractWrite: MockProxy; + let rollupContractSimulate: MockProxy; let rollupContract: MockRollupContract; let availabilityOracleRead: MockProxy; let availabilityOracleWrite: MockProxy; + let availabilityOracleSimulate: MockProxy; let availabilityOracle: MockAvailabilityOracle; let publicClient: MockProxy; @@ -96,12 +107,18 @@ describe('L1Publisher', () => { } as unknown as GetTransactionReceiptReturnType; rollupContractWrite = mock(); + rollupContractSimulate = mock(); rollupContractRead = mock(); - rollupContract = new MockRollupContract(rollupContractWrite, rollupContractRead); + rollupContract = new MockRollupContract(rollupContractWrite, rollupContractSimulate, rollupContractRead); availabilityOracleWrite = mock(); availabilityOracleRead = mock(); - availabilityOracle = new MockAvailabilityOracle(availabilityOracleWrite, availabilityOracleRead); + availabilityOracleSimulate = mock(); + availabilityOracle = new MockAvailabilityOracle( + availabilityOracleWrite, + availabilityOracleSimulate, + availabilityOracleRead, + ); publicClient = mock(); @@ -114,6 +131,7 @@ describe('L1Publisher', () => { rollupAddress: EthAddress.ZERO.toString(), }, l1PublishRetryIntervalMS: 1, + timeTraveller: false, } as unknown as TxSenderConfig & PublisherConfig; publisher = new L1Publisher(config, new NoopTelemetryClient()); @@ -123,11 +141,14 @@ describe('L1Publisher', () => { (publisher as any)['publicClient'] = publicClient; account = (publisher as any)['account']; + + rollupContractRead.getCurrentSlot.mockResolvedValue(l2Block.header.globalVariables.slotNumber.toBigInt()); }); it('publishes and process l2 block to l1', async () => { rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractWrite.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash); + rollupContractSimulate.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash); publicClient.getTransactionReceipt.mockResolvedValueOnce(publishAndProcessTxReceipt); const result = await publisher.processL2Block(l2Block); @@ -140,6 +161,7 @@ describe('L1Publisher', () => { `0x${blockHash.toString('hex')}`, `0x${body.toString('hex')}`, ] as const; + expect(rollupContractSimulate.publishAndProcess).toHaveBeenCalledWith(args, { account: account }); expect(rollupContractWrite.publishAndProcess).toHaveBeenCalledWith(args, { account: account }); expect(publicClient.getTransactionReceipt).toHaveBeenCalledWith({ hash: publishAndProcessTxHash }); }); @@ -148,6 +170,7 @@ describe('L1Publisher', () => { availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); rollupContractWrite.process.mockResolvedValueOnce(processTxHash); + rollupContractSimulate.process.mockResolvedValueOnce(processTxHash); publicClient.getTransactionReceipt.mockResolvedValueOnce(processTxReceipt); const result = await publisher.processL2Block(l2Block); @@ -158,20 +181,11 @@ describe('L1Publisher', () => { `0x${archive.toString('hex')}`, `0x${blockHash.toString('hex')}`, ] as const; + expect(rollupContractSimulate.process).toHaveBeenCalledWith(args, { account }); expect(rollupContractWrite.process).toHaveBeenCalledWith(args, { account }); expect(publicClient.getTransactionReceipt).toHaveBeenCalledWith({ hash: processTxHash }); }); - it('does not publish if last archive root is different to expected', async () => { - rollupContractRead.archive.mockResolvedValue(Fr.random().toString()); - - const result = await publisher.processL2Block(l2Block); - expect(result).toBe(false); - expect(availabilityOracleWrite.publish).not.toHaveBeenCalled(); - expect(rollupContractWrite.process).not.toHaveBeenCalled(); - expect(rollupContractWrite.publishAndProcess).not.toHaveBeenCalled(); - }); - it('does not retry if sending a process tx fails', async () => { availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); @@ -179,14 +193,31 @@ describe('L1Publisher', () => { .mockRejectedValueOnce(new Error()) .mockResolvedValueOnce(processTxHash as `0x${string}`); + // Note that simulate will be valid both times + rollupContractSimulate.process + .mockResolvedValueOnce(processTxHash as `0x${string}`) + .mockResolvedValueOnce(processTxHash as `0x${string}`); + const result = await publisher.processL2Block(l2Block); expect(result).toEqual(false); expect(rollupContractWrite.process).toHaveBeenCalledTimes(1); }); + it('does not retry if simulating a publish and process tx fails', async () => { + rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractSimulate.publishAndProcess.mockRejectedValueOnce(new Error()); + + const result = await publisher.processL2Block(l2Block); + + expect(result).toEqual(false); + expect(rollupContractSimulate.publishAndProcess).toHaveBeenCalledTimes(1); + expect(rollupContractWrite.publishAndProcess).toHaveBeenCalledTimes(0); + }); + it('does not retry if sending a publish and process tx fails', async () => { rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractSimulate.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash as `0x${string}`); rollupContractWrite.publishAndProcess.mockRejectedValueOnce(new Error()); const result = await publisher.processL2Block(l2Block); @@ -198,6 +229,7 @@ describe('L1Publisher', () => { it('retries if fetching the receipt fails (process)', async () => { availabilityOracleRead.isAvailable.mockResolvedValueOnce(true); rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractSimulate.process.mockResolvedValueOnce(processTxHash); rollupContractWrite.process.mockResolvedValueOnce(processTxHash); publicClient.getTransactionReceipt.mockRejectedValueOnce(new Error()).mockResolvedValueOnce(processTxReceipt); @@ -209,6 +241,7 @@ describe('L1Publisher', () => { it('retries if fetching the receipt fails (publish process)', async () => { rollupContractRead.archive.mockResolvedValue(l2Block.header.lastArchive.root.toString() as `0x${string}`); + rollupContractSimulate.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash as `0x${string}`); rollupContractWrite.publishAndProcess.mockResolvedValueOnce(publishAndProcessTxHash as `0x${string}`); publicClient.getTransactionReceipt .mockRejectedValueOnce(new Error()) diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index fa1bf420f8e..020e5077b69 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -1,6 +1,14 @@ +import { EthCheatCodes } from '@aztec/aztec.js'; import { type L2Block, type Signature } from '@aztec/circuit-types'; import { type L1PublishBlockStats, type L1PublishProofStats } from '@aztec/circuit-types/stats'; -import { ETHEREUM_SLOT_DURATION, EthAddress, type Header, type Proof } from '@aztec/circuits.js'; +import { + AZTEC_SLOT_DURATION, + ETHEREUM_SLOT_DURATION, + EthAddress, + type Header, + IS_DEV_NET, + type Proof, +} from '@aztec/circuits.js'; import { createEthereumChain } from '@aztec/ethereum'; import { type Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -59,13 +67,6 @@ export type MinimalTransactionReceipt = { logs: any[]; }; -/** - * @notice An attestation for the sequencing model. - * @todo This is not where it belongs. But I think we should do a bigger rewrite of some of - * this spaghetti. - */ -export type Attestation = { isEmpty: boolean; v: number; r: `0x${string}`; s: `0x${string}` }; - /** Arguments to the process method of the rollup contract */ export type L1ProcessArgs = { /** The L2 block header. */ @@ -94,6 +95,13 @@ export type L1SubmitProofArgs = { aggregationObject: Buffer; }; +export type MetadataForSlot = { + proposer: EthAddress; + slot: bigint; + pendingBlockNumber: bigint; + archive: Buffer; +}; + /** * Publishes L2 blocks to L1. This implementation does *not* retry a transaction in * the event of network congestion, but should work for local development. @@ -105,6 +113,7 @@ export type L1SubmitProofArgs = { export class L1Publisher { private interruptibleSleep = new InterruptibleSleep(); private sleepTimeMs: number; + private timeTraveler: boolean; private interrupted = false; private metrics: L1PublisherMetrics; private log = createDebugLogger('aztec:sequencer:publisher'); @@ -120,8 +129,11 @@ export class L1Publisher { private publicClient: PublicClient; private account: PrivateKeyAccount; + private ethCheatCodes: EthCheatCodes; + constructor(config: TxSenderConfig & PublisherConfig, client: TelemetryClient) { this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000; + this.timeTraveler = config?.timeTraveler ?? false; this.metrics = new L1PublisherMetrics(client, 'L1Publisher'); const { l1RpcUrl: rpcUrl, l1ChainId: chainId, publisherPrivateKey, l1Contracts } = config; @@ -148,30 +160,56 @@ export class L1Publisher { abi: RollupAbi, client: walletClient, }); + + this.ethCheatCodes = new EthCheatCodes(rpcUrl); + } + + public async amIAValidator(): Promise { + return await this.rollupContract.read.isValidator([this.account.address]); + } + + public async getValidatorCount(): Promise { + return BigInt(await this.rollupContract.read.getValidatorCount()); } public getSenderAddress(): Promise { return Promise.resolve(EthAddress.fromString(this.account.address)); } - // Computes who will be the L2 proposer at the next Ethereum block - // Using next Ethereum block so we do NOT need to wait for it being mined before seeing the effect - // @note Assumes that all ethereum slots have blocks - async getProposerAtNextEthBlock(): Promise { - try { - const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); - const submitter = await this.rollupContract.read.getProposerAt([ts]); - return EthAddress.fromString(submitter); - } catch (err) { - this.log.warn(`Failed to get submitter: ${err}`); - return EthAddress.ZERO; + public async willSimulationFail(slot: bigint): Promise { + // @note When simulating or estimating gas, `viem` will use the CURRENT state of the chain + // and not the state in the next block. Meaning that the timestamp will be the same as + // the previous block, which means that the slot will also be the same. + // This effectively means that if we try to simulate for the first L1 block where we + // will be proposer, we will have a failure as the slot have not yet changed. + // @todo #8110 + + if (IS_DEV_NET) { + return false; } + + const currentSlot = BigInt(await this.rollupContract.read.getCurrentSlot()); + return currentSlot != slot; } - public async isItMyTurnToSubmit(): Promise { - const submitter = await this.getProposerAtNextEthBlock(); - const sender = await this.getSenderAddress(); - return submitter.isZero() || submitter.equals(sender); + // @note Assumes that all ethereum slots have blocks + // Using next Ethereum block so we do NOT need to wait for it being mined before seeing the effect + public async getMetadataForSlotAtNextEthBlock(): Promise { + const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); + + const [submitter, slot, pendingBlockCount, archive] = await Promise.all([ + this.rollupContract.read.getProposerAt([ts]), + this.rollupContract.read.getSlotAt([ts]), + this.rollupContract.read.pendingBlockCount(), + this.rollupContract.read.archive(), + ]); + + return { + proposer: EthAddress.fromString(submitter), + slot, + pendingBlockNumber: pendingBlockCount - 1n, + archive: Buffer.from(archive.replace('0x', ''), 'hex'), + }; } public async getCurrentEpochCommittee(): Promise { @@ -203,25 +241,28 @@ export class L1Publisher { * @returns True once the tx has been confirmed and is successful, false on revert or interrupt, blocks otherwise. */ public async processL2Block(block: L2Block, attestations?: Signature[]): Promise { - const ctx = { blockNumber: block.number, blockHash: block.hash().toString() }; - // TODO(#4148) Remove this block number check, it's here because we don't currently have proper genesis state on the contract - const lastArchive = block.header.lastArchive.root.toBuffer(); - if (block.number != 1 && !(await this.checkLastArchiveHash(lastArchive))) { - this.log.info(`Detected different last archive prior to publishing a block, aborting publish...`, ctx); + const ctx = { + blockNumber: block.number, + slotNumber: block.header.globalVariables.slotNumber.toBigInt(), + blockHash: block.hash().toString(), + }; + + if (await this.willSimulationFail(block.header.globalVariables.slotNumber.toBigInt())) { + // @note See comment in willSimulationFail for more information + this.log.info(`Simulation will fail for slot ${block.header.globalVariables.slotNumber.toBigInt()}`); return false; } - const encodedBody = block.body.toBuffer(); const processTxArgs = { header: block.header.toBuffer(), archive: block.archive.root.toBuffer(), blockHash: block.header.hash().toBuffer(), - body: encodedBody, + body: block.body.toBuffer(), attestations, }; // Process block and publish the body if needed (if not already published) - while (!this.interrupted) { + if (!this.interrupted) { let txHash; const timer = new Timer(); @@ -234,13 +275,13 @@ export class L1Publisher { if (!txHash) { this.log.info(`Failed to publish block ${block.number} to L1`, ctx); - break; + return false; } const receipt = await this.getTransactionReceipt(txHash); if (!receipt) { this.log.info(`Failed to get receipt for tx ${txHash}`, ctx); - break; + return false; } // Tx was mined successfully @@ -254,17 +295,14 @@ export class L1Publisher { }; this.log.info(`Published L2 block to L1 rollup contract`, { ...stats, ...ctx }); this.metrics.recordProcessBlockTx(timer.ms(), stats); + + await this.commitTimeJump(block.header.globalVariables.slotNumber.toBigInt() + 1n); + return true; } this.metrics.recordFailedTx('process'); - // Check if someone else incremented the block number - if (!(await this.checkLastArchiveHash(lastArchive))) { - this.log.warn('Publish failed. Detected different last archive hash.', ctx); - break; - } - this.log.error(`Rollup.process tx status failed: ${receipt.transactionHash}`, ctx); await this.sleepOrInterrupted(); } @@ -273,6 +311,49 @@ export class L1Publisher { return false; } + async commitTimeJump(slot: bigint) { + // @note So, we are cheating a bit here. Since the tests are running anvil auto-mine + // no blocks are coming around unless we do something, and since we cannot push + // more blocks within the same slot (when `IS_DEV_NET = false`), we can just + // fast forward the anvil chain such that the next block will be the one we need. + // this means that we are forwarding to time of the next slot - 12 seconds such that + // the NEXT ethereum block will be within the new slot. + // If the slot duration of L2 is just 1 L1 slot, then this will not do anything, as + // the time to jump to is current time. + // + // Time jumps only allowed into the future. + // + // If this is run on top of a real chain, the time lords will catch you. + // + // @todo #8153 + + if (!this.timeTraveler) { + return; + } + + // If the aztec slot duration is same length as the ethereum slot duration, we don't need to do anything + if ((ETHEREUM_SLOT_DURATION as number) === (AZTEC_SLOT_DURATION as number)) { + return; + } + + const [currentTime, timeStampForSlot] = await Promise.all([ + this.ethCheatCodes.timestamp(), + this.rollupContract.read.getTimestampForSlot([slot]), + ]); + + // @note We progress the time to the next slot AND mine the block. + // This means that the next effective block will be ETHEREUM_SLOT_DURATION after that. + // This will cause issues if slot duration is equal to one (1) L1 slot, and sequencer selection is run + // The reason is that simulations on ANVIL cannot be run with timestamp + x, so we need to "BE" there. + // @todo #8110 + const timestamp = timeStampForSlot; // - BigInt(ETHEREUM_SLOT_DURATION); + + if (timestamp > currentTime) { + this.log.info(`Committing time jump to slot ${slot}`); + await this.ethCheatCodes.warp(Number(timestamp)); + } + } + public async submitProof( header: Header, archiveRoot: Fr, @@ -280,7 +361,7 @@ export class L1Publisher { aggregationObject: Fr[], proof: Proof, ): Promise { - const ctx = { blockNumber: header.globalVariables.blockNumber }; + const ctx = { blockNumber: header.globalVariables.blockNumber, slotNumber: header.globalVariables.slotNumber }; const txArgs: L1SubmitProofArgs = { header: header.toBuffer(), @@ -291,16 +372,16 @@ export class L1Publisher { }; // Process block - while (!this.interrupted) { + if (!this.interrupted) { const timer = new Timer(); const txHash = await this.sendSubmitProofTx(txArgs); if (!txHash) { - break; + return false; } const receipt = await this.getTransactionReceipt(txHash); if (!receipt) { - break; + return false; } // Tx was mined successfully @@ -341,26 +422,6 @@ export class L1Publisher { this.interrupted = false; } - async getCurrentArchive(): Promise { - const archive = await this.rollupContract.read.archive(); - return Buffer.from(archive.replace('0x', ''), 'hex'); - } - - /** - * Verifies that the given value of last archive in a block header equals current archive of the rollup contract - * @param lastArchive - The last archive of the block we wish to publish. - * @returns Boolean indicating if the hashes are equal. - */ - private async checkLastArchiveHash(lastArchive: Buffer): Promise { - const fromChain = await this.getCurrentArchive(); - const areSame = lastArchive.equals(fromChain); - if (!areSame) { - this.log.debug(`Contract archive: ${fromChain.toString('hex')}`); - this.log.debug(`New block last archive: ${lastArchive.toString('hex')}`); - } - return areSame; - } - private async sendSubmitProofTx(submitProofArgs: L1SubmitProofArgs): Promise { try { const size = Object.values(submitProofArgs).reduce((acc, arg) => acc + arg.length, 0); @@ -375,6 +436,10 @@ export class L1Publisher { `0x${proof.toString('hex')}`, ] as const; + await this.rollupContract.simulate.submitBlockRootProof(args, { + account: this.account, + }); + return await this.rollupContract.write.submitBlockRootProof(args, { account: this.account, }); @@ -385,11 +450,15 @@ export class L1Publisher { } private async sendPublishTx(encodedBody: Buffer): Promise { - while (!this.interrupted) { + if (!this.interrupted) { try { this.log.info(`TxEffects size=${encodedBody.length} bytes`); const args = [`0x${encodedBody.toString('hex')}`] as const; + await this.availabilityOracleContract.simulate.publish(args, { + account: this.account, + }); + return await this.availabilityOracleContract.write.publish(args, { account: this.account, }); @@ -401,7 +470,7 @@ export class L1Publisher { } private async sendProcessTx(encodedData: L1ProcessArgs): Promise { - while (!this.interrupted) { + if (!this.interrupted) { try { if (encodedData.attestations) { const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); @@ -412,6 +481,8 @@ export class L1Publisher { attestations, ] as const; + await this.rollupContract.simulate.process(args, { account: this.account }); + return await this.rollupContract.write.process(args, { account: this.account, }); @@ -422,6 +493,8 @@ export class L1Publisher { `0x${encodedData.blockHash.toString('hex')}`, ] as const; + await this.rollupContract.simulate.process(args, { account: this.account }); + return await this.rollupContract.write.process(args, { account: this.account, }); @@ -434,9 +507,8 @@ export class L1Publisher { } private async sendPublishAndProcessTx(encodedData: L1ProcessArgs): Promise { - while (!this.interrupted) { + if (!this.interrupted) { try { - // @note This is quite a sin, but I'm committing war crimes in this code already. if (encodedData.attestations) { const attestations = encodedData.attestations.map(attest => attest.toViemSignature()); const args = [ @@ -447,6 +519,11 @@ export class L1Publisher { `0x${encodedData.body.toString('hex')}`, ] as const; + // Using simulate to get a meaningful error message + await this.rollupContract.simulate.publishAndProcess(args, { + account: this.account, + }); + return await this.rollupContract.write.publishAndProcess(args, { account: this.account, }); @@ -458,6 +535,10 @@ export class L1Publisher { `0x${encodedData.body.toString('hex')}`, ] as const; + await this.rollupContract.simulate.publishAndProcess(args, { + account: this.account, + }); + return await this.rollupContract.write.publishAndProcess(args, { account: this.account, }); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 9f4f79046fa..9ee5c089474 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -1,4 +1,6 @@ import { + BlockAttestation, + BlockProposal, type BlockSimulator, type L1ToL2MessageSource, L2Block, @@ -7,7 +9,9 @@ import { PROVING_STATUS, type ProvingSuccess, type ProvingTicket, + Signature, type Tx, + TxHash, type UnencryptedL2Log, UnencryptedTxL2Logs, makeProcessedTx, @@ -22,6 +26,7 @@ import { IS_DEV_NET, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, } from '@aztec/circuits.js'; +import { Buffer32 } from '@aztec/foundation/buffer'; import { times } from '@aztec/foundation/collection'; import { randomBytes } from '@aztec/foundation/crypto'; import { type Writeable } from '@aztec/foundation/types'; @@ -36,7 +41,7 @@ import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; import { type BlockBuilderFactory } from '../block_builder/index.js'; import { type GlobalVariableBuilder } from '../global_variable_builder/global_builder.js'; -import { type L1Publisher } from '../publisher/l1-publisher.js'; +import { type L1Publisher, type MetadataForSlot } from '../publisher/l1-publisher.js'; import { TxValidatorFactory } from '../tx_validator/tx_validator_factory.js'; import { Sequencer } from './sequencer.js'; @@ -63,22 +68,45 @@ describe('sequencer', () => { const feeRecipient = AztecAddress.random(); const gasFees = GasFees.empty(); - // We mock an attestation - const mockedAttestation = { - isEmpty: false, - v: 27, - r: Fr.random().toString(), - s: Fr.random().toString(), + const archive = Fr.random(); + + const mockedSig = new Signature(Buffer32.fromField(Fr.random()), Buffer32.fromField(Fr.random()), 27); + + const committee = [EthAddress.random()]; + const getSignatures = () => (IS_DEV_NET ? undefined : [mockedSig]); + const getAttestations = () => { + if (IS_DEV_NET) { + return undefined; + } + + const attestation = new BlockAttestation(block.header, archive, mockedSig); + (attestation as any).sender = committee[0]; + + return [attestation]; + }; + const createBlockProposal = () => { + return new BlockProposal(block.header, archive, [TxHash.random()], mockedSig); }; - const getAttestations = () => (IS_DEV_NET ? undefined : [mockedAttestation]); + let block: L2Block; + let metadata: MetadataForSlot; beforeEach(() => { lastBlockNumber = 0; - publisher = mock(); + block = L2Block.random(lastBlockNumber + 1); + + metadata = { + proposer: EthAddress.ZERO, + slot: block.header.globalVariables.slotNumber.toBigInt(), + pendingBlockNumber: BigInt(lastBlockNumber), + archive: block.header.lastArchive.toBuffer(), + }; - publisher.isItMyTurnToSubmit.mockResolvedValue(true); + publisher = mock(); + publisher.getCurrentEpochCommittee.mockResolvedValue(committee); + publisher.getMetadataForSlotAtNextEthBlock.mockResolvedValue(metadata); + publisher.getValidatorCount.mockResolvedValue(0n); globalVariableBuilder = mock(); merkleTreeOps = mock(); @@ -124,6 +152,13 @@ describe('sequencer', () => { create: () => blockSimulator, }); + if (!IS_DEV_NET) { + validatorClient = mock({ + collectAttestations: mockFn().mockResolvedValue(getAttestations()), + createBlockProposal: mockFn().mockResolvedValue(createBlockProposal()), + }); + } + sequencer = new TestSubject( publisher, // TDOO(md): add the relevant methods to the validator client that will prevent it stalling when waiting for attestations @@ -143,7 +178,7 @@ describe('sequencer', () => { it('builds a block out of a single tx', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; - const block = L2Block.random(lastBlockNumber + 1); + const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -159,7 +194,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -178,14 +213,13 @@ describe('sequencer', () => { Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledTimes(1); - expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getSignatures()); expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); it('builds a block when it is their turn', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; - const block = L2Block.random(lastBlockNumber + 1); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -201,7 +235,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -212,20 +246,26 @@ describe('sequencer', () => { globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce(mockedGlobalVariables); // Not your turn! - publisher.isItMyTurnToSubmit.mockClear().mockResolvedValue(false); + const publisherAddress = EthAddress.random(); + publisher.getSenderAddress.mockResolvedValue(publisherAddress); + publisher.getMetadataForSlotAtNextEthBlock.mockResolvedValue({ ...metadata, proposer: EthAddress.random() }); + // Specify that there is a validator, such that we don't allow everyone to publish + publisher.getValidatorCount.mockResolvedValueOnce(1n); + await sequencer.initialSync(); await sequencer.work(); expect(blockSimulator.startNewBlock).not.toHaveBeenCalled(); // Now it is! - publisher.isItMyTurnToSubmit.mockClear().mockResolvedValue(true); + publisher.getMetadataForSlotAtNextEthBlock.mockResolvedValue({ ...metadata, proposer: publisherAddress }); + await sequencer.work(); expect(blockSimulator.startNewBlock).toHaveBeenCalledWith( 2, mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); - expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getSignatures()); expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); @@ -235,7 +275,6 @@ describe('sequencer', () => { tx.data.constants.txContext.chainId = chainId; }); const doubleSpendTx = txs[1]; - const block = L2Block.random(lastBlockNumber + 1); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -251,7 +290,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -277,7 +316,7 @@ describe('sequencer', () => { mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); - expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getSignatures()); expect(p2p.deleteTxs).toHaveBeenCalledWith([doubleSpendTx.getTxHash()]); expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); @@ -288,7 +327,6 @@ describe('sequencer', () => { tx.data.constants.txContext.chainId = chainId; }); const invalidChainTx = txs[1]; - const block = L2Block.random(lastBlockNumber + 1); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -304,7 +342,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -325,7 +363,7 @@ describe('sequencer', () => { mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); - expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getSignatures()); expect(p2p.deleteTxs).toHaveBeenCalledWith([invalidChainTx.getTxHash()]); expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); @@ -335,7 +373,6 @@ describe('sequencer', () => { txs.forEach(tx => { tx.data.constants.txContext.chainId = chainId; }); - const block = L2Block.random(lastBlockNumber + 1); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -373,7 +410,7 @@ describe('sequencer', () => { mockedGlobalVariables, Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); - expect(publisher.processL2Block).toHaveBeenCalledWith(block, getAttestations()); + expect(publisher.processL2Block).toHaveBeenCalledWith(block, getSignatures()); expect(blockSimulator.cancelBlock).toHaveBeenCalledTimes(0); }); @@ -457,7 +494,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -519,7 +556,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, @@ -563,7 +600,6 @@ describe('sequencer', () => { it('aborts building a block if the chain moves underneath it', async () => { const tx = mockTxForRollup(); tx.data.constants.txContext.chainId = chainId; - const block = L2Block.random(lastBlockNumber + 1); const result: ProvingSuccess = { status: PROVING_STATUS.SUCCESS, }; @@ -579,7 +615,7 @@ describe('sequencer', () => { const mockedGlobalVariables = new GlobalVariables( chainId, version, - new Fr(lastBlockNumber + 1), + block.header.globalVariables.blockNumber, block.header.globalVariables.slotNumber, Fr.ZERO, coinbase, diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 1fe8fa5f52c..aec543dfef4 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -28,6 +28,12 @@ import { type TxValidatorFactory } from '../tx_validator/tx_validator_factory.js import { type SequencerConfig } from './config.js'; import { SequencerMetrics } from './metrics.js'; +export type ShouldProposeArgs = { + pendingTxsCount?: number; + validTxsCount?: number; + processedTxsCount?: number; +}; + /** * Sequencer client * - Wins a period of time to become the sequencer (depending on finalized protocol). @@ -183,39 +189,25 @@ export class Sequencer { this.state = SequencerState.IDLE; } - const historicalHeader = (await this.l2BlockSource.getBlock(-1))?.header; + const chainTip = await this.l2BlockSource.getBlock(-1); + const historicalHeader = chainTip?.header; + const newBlockNumber = (historicalHeader === undefined ? await this.l2BlockSource.getBlockNumber() : Number(historicalHeader.globalVariables.blockNumber.toBigInt())) + 1; - // Do not go forward with new block if not my turn - if (!(await this.publisher.isItMyTurnToSubmit())) { - this.log.debug('Not my turn to submit block'); - return; - } + const chainTipArchive = chainTip?.archive.root.toBuffer(); - if (this.isFlushing) { - this.log.verbose(`Flushing all pending txs in new block`); + let slot: bigint; + try { + slot = await this.canProposeBlock(historicalHeader, undefined, chainTipArchive); + } catch (err) { + this.log.debug(`Cannot propose for block ${newBlockNumber}`); + return; } - // Compute time elapsed since the previous block - const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0; - const currentTime = Math.floor(Date.now() / 1000); - const elapsedSinceLastBlock = currentTime - lastBlockTime; - this.log.debug( - `Last block mined at ${lastBlockTime} current time is ${currentTime} (elapsed ${elapsedSinceLastBlock})`, - ); - - // Do not go forward with new block if not enough time has passed since last block - if ( - !this.isFlushing && - this.minSecondsBetweenBlocks > 0 && - elapsedSinceLastBlock < this.minSecondsBetweenBlocks - ) { - this.log.debug( - `Not creating block because not enough time ${this.minSecondsBetweenBlocks} has passed since last block`, - ); + if (!this.shouldProposeBlock(historicalHeader, {})) { return; } @@ -224,18 +216,8 @@ export class Sequencer { // Get txs to build the new block. const pendingTxs = this.p2pClient.getTxs('pending'); - // If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs. - if (!this.isFlushing && pendingTxs.length < this.minTxsPerBLock) { - if (this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock)) { - this.log.debug( - `Creating block with only ${pendingTxs.length} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`, - ); - } else { - this.log.debug( - `Not creating block because not enough txs in the pool (got ${pendingTxs.length} min ${this.minTxsPerBLock})`, - ); - return; - } + if (!this.shouldProposeBlock(historicalHeader, { pendingTxsCount: pendingTxs.length })) { + return; } this.log.debug(`Retrieved ${pendingTxs.length} txs from P2P pool`); @@ -243,10 +225,9 @@ export class Sequencer { new Fr(newBlockNumber), this._coinbase, this._feeRecipient, + slot, ); - // @todo @LHerskind Include some logic to consider slots - // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here const allValidTxs = await this.takeValidTxs( pendingTxs, @@ -261,18 +242,11 @@ export class Sequencer { const validTxs = this.takeTxsWithinMaxSize(allValidTxs); // Bail if we don't have enough valid txs - if ( - !this.isFlushing && - !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && - validTxs.length < this.minTxsPerBLock - ) { - this.log.debug( - `Not creating block because not enough valid txs loaded from the pool (got ${validTxs.length} min ${this.minTxsPerBLock})`, - ); + if (!this.shouldProposeBlock(historicalHeader, { validTxsCount: validTxs.length })) { return; } - await this.buildBlockAndPublish(validTxs, newGlobalVariables, historicalHeader, elapsedSinceLastBlock); + await this.buildBlockAndPublish(validTxs, newGlobalVariables, historicalHeader, chainTipArchive); } catch (err) { if (BlockProofError.isBlockProofError(err)) { const txHashes = err.txHashes.filter(h => !h.isZero()); @@ -285,38 +259,204 @@ export class Sequencer { } /** Whether to skip the check of min txs per block if more than maxSecondsBetweenBlocks has passed since the previous block. */ - private skipMinTxsPerBlockCheck(elapsed: number): boolean { + private skipMinTxsPerBlockCheck(historicalHeader: Header | undefined): boolean { + const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0; + const currentTime = Math.floor(Date.now() / 1000); + const elapsed = currentTime - lastBlockTime; + return this.maxSecondsBetweenBlocks > 0 && elapsed >= this.maxSecondsBetweenBlocks; } - @trackSpan('Sequencer.buildBlockAndPublish', (_validTxs, newGlobalVariables, _historicalHeader) => ({ - [Attributes.BLOCK_NUMBER]: newGlobalVariables.blockNumber.toNumber(), - })) + async canProposeBlock( + historicalHeader?: Header, + globalVariables?: GlobalVariables, + tipArchive?: Buffer, + ): Promise { + // @note In order to be able to propose a block, a few conditions must be met: + // - We must be caught up to the pending chain + // - The tip archive must match the one from the L1 + // - The block number should match the one from the L1 + // - If we have built a block, the block number must match the next pending block + // - There cannot already be a block for the slot + // - If we are NOT in devnet, then the active slot must match the slot number of the block + // - The proposer must either be free for all or specifically us. + // + // Note that the ordering of these checks are NOT optimised for performance, but to resemble the ordering + // that is used in the Rollup contract: + // - _validateHeaderForSubmissionBase + // - _validateHeaderForSubmissionSequencerSelection + // + // Also, we are logging debug messages for checks that fail to make it easier to debug, as we are usually + // catching the errors. + + const { proposer, slot, pendingBlockNumber, archive } = await this.publisher.getMetadataForSlotAtNextEthBlock(); + + if (await this.publisher.willSimulationFail(slot)) { + // @note See comment in willSimulationFail for more information + const msg = `Simulation will fail for slot ${slot}`; + this.log.debug(msg); + throw new Error(msg); + } + + // If our tip of the chain is different from the tip on L1, we should not propose a block + // @note This will change along with the data publication changes. + if (tipArchive && !archive.equals(tipArchive)) { + const msg = `Tip archive does not match the one from the L1`; + this.log.debug(msg); + throw new Error(msg); + } + + // Make sure I'm caught up to the pending chain + if ( + pendingBlockNumber > 0 && + (historicalHeader == undefined || historicalHeader.globalVariables.blockNumber.toBigInt() != pendingBlockNumber) + ) { + const msg = `Not caught up to pending block ${pendingBlockNumber}`; + this.log.debug(msg); + throw new Error(msg); + } + + // If I have constructed a block, make sure that the block number matches the next pending block number + if (globalVariables) { + if (globalVariables.blockNumber.toBigInt() !== pendingBlockNumber + 1n) { + const msg = `Block number mismatch. Expected ${ + pendingBlockNumber + 1n + } but got ${globalVariables.blockNumber.toBigInt()}`; + this.log.debug(msg); + throw new Error(msg); + } + + const currentBlockNumber = await this.l2BlockSource.getBlockNumber(); + if (currentBlockNumber + 1 !== globalVariables.blockNumber.toNumber()) { + this.metrics.recordCancelledBlock(); + const msg = 'New block was emitted while building block'; + this.log.debug(msg); + throw new Error(msg); + } + } + + // Do not go forward if there was already a block for the slot + if (historicalHeader && historicalHeader.globalVariables.slotNumber.toBigInt() === slot) { + const msg = `Block already exists for slot ${slot}`; + this.log.debug(msg); + throw new Error(msg); + } + + // Related to _validateHeaderForSubmissionSequencerSelection + + if (IS_DEV_NET) { + // If we are in devnet, make sure that we are a validator + if ((await this.publisher.getValidatorCount()) != 0n && !(await this.publisher.amIAValidator())) { + const msg = 'Not a validator in devnet'; + this.log.debug(msg); + throw new Error(msg); + } + } else { + // If I have a constructed a block, make sure that the slot matches the current slot number + if (globalVariables) { + if (slot !== globalVariables.slotNumber.toBigInt()) { + const msg = `Slot number mismatch. Expected ${slot} but got ${globalVariables.slotNumber.toBigInt()}`; + this.log.debug(msg); + throw new Error(msg); + } + } + + // Do not go forward with new block if not free for all or my turn + if (!proposer.isZero() && !proposer.equals(await this.publisher.getSenderAddress())) { + const msg = 'Not my turn to submit block'; + this.log.debug(msg); + throw new Error(msg); + } + } + + return slot; + } + + shouldProposeBlock(historicalHeader: Header | undefined, args: ShouldProposeArgs): boolean { + if (this.isFlushing) { + this.log.verbose(`Flushing all pending txs in new block`); + return true; + } + + if (IS_DEV_NET) { + // Compute time elapsed since the previous block + const lastBlockTime = historicalHeader?.globalVariables.timestamp.toNumber() || 0; + const currentTime = Math.floor(Date.now() / 1000); + const elapsedSinceLastBlock = currentTime - lastBlockTime; + this.log.debug( + `Last block mined at ${lastBlockTime} current time is ${currentTime} (elapsed ${elapsedSinceLastBlock})`, + ); + + // If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs. + // Do not go forward with new block if not enough time has passed since last block + if (this.minSecondsBetweenBlocks > 0 && elapsedSinceLastBlock < this.minSecondsBetweenBlocks) { + this.log.debug( + `Not creating block because not enough time ${this.minSecondsBetweenBlocks} has passed since last block`, + ); + return false; + } + } + + const skipCheck = this.skipMinTxsPerBlockCheck(historicalHeader); + + // If we haven't hit the maxSecondsBetweenBlocks, we need to have at least minTxsPerBLock txs. + if (args.pendingTxsCount != undefined) { + if (args.pendingTxsCount < this.minTxsPerBLock) { + if (skipCheck) { + this.log.debug( + `Creating block with only ${args.pendingTxsCount} txs as more than ${this.maxSecondsBetweenBlocks}s have passed since last block`, + ); + } else { + this.log.debug( + `Not creating block because not enough txs in the pool (got ${args.pendingTxsCount} min ${this.minTxsPerBLock})`, + ); + return false; + } + } + } + + // Bail if we don't have enough valid txs + if (args.validTxsCount != undefined) { + // Bail if we don't have enough valid txs + if (!skipCheck && args.validTxsCount < this.minTxsPerBLock) { + this.log.debug( + `Not creating block because not enough valid txs loaded from the pool (got ${args.validTxsCount} min ${this.minTxsPerBLock})`, + ); + return false; + } + } + + // TODO: This check should be processedTxs.length < this.minTxsPerBLock, so we don't publish a block with + // less txs than the minimum. But that'd cause the entire block to be aborted and retried. Instead, we should + // go back to the p2p pool and load more txs until we hit our minTxsPerBLock target. Only if there are no txs + // we should bail. + if (args.processedTxsCount != undefined) { + if (args.processedTxsCount === 0 && !skipCheck && this.minTxsPerBLock > 0) { + this.log.verbose('No txs processed correctly to build block. Exiting'); + return false; + } + } + + return true; + } + + @trackSpan( + 'Sequencer.buildBlockAndPublish', + (_validTxs, newGlobalVariables, _historicalHeader, _chainTipArchive) => ({ + [Attributes.BLOCK_NUMBER]: newGlobalVariables.blockNumber.toNumber(), + }), + ) private async buildBlockAndPublish( validTxs: Tx[], newGlobalVariables: GlobalVariables, historicalHeader: Header | undefined, - elapsedSinceLastBlock: number, + chainTipArchive: Buffer | undefined, ): Promise { this.metrics.recordNewBlock(newGlobalVariables.blockNumber.toNumber(), validTxs.length); const workTimer = new Timer(); this.state = SequencerState.CREATING_BLOCK; this.log.info(`Building block ${newGlobalVariables.blockNumber.toNumber()} with ${validTxs.length} transactions`); - const assertBlockHeight = async () => { - const currentBlockNumber = await this.l2BlockSource.getBlockNumber(); - if (currentBlockNumber + 1 !== newGlobalVariables.blockNumber.toNumber()) { - this.metrics.recordCancelledBlock(); - throw new Error('New block was emitted while building block'); - } - - if (!(await this.publisher.isItMyTurnToSubmit())) { - throw new Error(`Not this sequencer turn to submit block`); - } - - // @todo @LHerskind Should take into account, block number, proposer and slot number - }; - // Get l1 to l2 messages from the contract this.log.debug('Requesting L1 to L2 messages from contract'); const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(newGlobalVariables.blockNumber.toBigInt()); @@ -343,27 +483,21 @@ export class Sequencer { await this.p2pClient.deleteTxs(Tx.getHashes(failedTxData)); } - // TODO: This check should be processedTxs.length < this.minTxsPerBLock, so we don't publish a block with - // less txs than the minimum. But that'd cause the entire block to be aborted and retried. Instead, we should - // go back to the p2p pool and load more txs until we hit our minTxsPerBLock target. Only if there are no txs - // we should bail. + await this.canProposeBlock(historicalHeader, newGlobalVariables, chainTipArchive); if ( - !this.isFlushing && - processedTxs.length === 0 && - !this.skipMinTxsPerBlockCheck(elapsedSinceLastBlock) && - this.minTxsPerBLock > 0 + !this.shouldProposeBlock(historicalHeader, { + validTxsCount: validTxs.length, + processedTxsCount: processedTxs.length, + }) ) { - this.log.verbose('No txs processed correctly to build block. Exiting'); blockBuilder.cancelBlock(); return; } - await assertBlockHeight(); - // All real transactions have been added, set the block as full and complete the proving. await blockBuilder.setBlockCompleted(); - // Here we are now waiting for the block to be proven. + // Here we are now waiting for the block to be proven (using simulated[fake] proofs). // TODO(@PhilWindle) We should probably periodically check for things like another // block being published before ours instead of just waiting on our block const result = await blockTicket.provingPromise; @@ -371,12 +505,10 @@ export class Sequencer { throw new Error(`Block proving failed, reason: ${result.reason}`); } - await assertBlockHeight(); - - // Block is ready, now finalise and publish! + // Block is ready, now finalise const { block } = await blockBuilder.finaliseBlock(); - await assertBlockHeight(); + await this.canProposeBlock(historicalHeader, newGlobalVariables, chainTipArchive); const workDuration = workTimer.ms(); this.log.verbose( @@ -395,10 +527,12 @@ export class Sequencer { if (this.isFlushing) { this.log.verbose(`Flushing completed`); } + this.isFlushing = false; + const attestations = await this.collectAttestations(block); + await this.canProposeBlock(historicalHeader, newGlobalVariables, chainTipArchive); try { - const attestations = await this.collectAttestations(block); await this.publishL2Block(block, attestations); this.metrics.recordPublishedBlock(workDuration); this.log.info( @@ -437,6 +571,11 @@ export class Sequencer { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7962): inefficient to have a round trip in here - this should be cached const committee = await this.publisher.getCurrentEpochCommittee(); + + if (committee.length === 0) { + return undefined; + } + const numberOfRequiredAttestations = Math.floor((committee.length * 2) / 3) + 1; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7974): we do not have transaction[] lists in the block for now @@ -448,10 +587,7 @@ export class Sequencer { this.validatorClient.broadcastBlockProposal(proposal); this.state = SequencerState.WAITING_FOR_ATTESTATIONS; - const attestations = await this.validatorClient.collectAttestations( - proposal.header.globalVariables.slotNumber.toBigInt(), - numberOfRequiredAttestations, - ); + const attestations = await this.validatorClient.collectAttestations(proposal, numberOfRequiredAttestations); // note: the smart contract requires that the signatures are provided in the order of the committee return await orderAttestations(attestations, committee); diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index 54c62d4427f..9a8615c0299 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -6,6 +6,9 @@ "tsBuildInfoFile": ".tsbuildinfo" }, "references": [ + { + "path": "../aztec.js" + }, { "path": "../bb-prover" }, diff --git a/yarn-project/validator-client/src/validator.ts b/yarn-project/validator-client/src/validator.ts index a0338ddadb0..1425f7d464c 100644 --- a/yarn-project/validator-client/src/validator.ts +++ b/yarn-project/validator-client/src/validator.ts @@ -20,7 +20,7 @@ export interface Validator { // TODO(md): possible abstraction leak broadcastBlockProposal(proposal: BlockProposal): void; - collectAttestations(slot: bigint, numberOfRequiredAttestations: number): Promise; + collectAttestations(proposal: BlockProposal, numberOfRequiredAttestations: number): Promise; } /** Validator Client @@ -75,13 +75,18 @@ export class ValidatorClient implements Validator { // Target is temporarily hardcoded, for a test, but will be calculated from smart contract // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7962) // TODO(https://github.com/AztecProtocol/aztec-packages/issues/7976): require suitable timeouts - async collectAttestations(slot: bigint, numberOfRequiredAttestations: number): Promise { + async collectAttestations( + proposal: BlockProposal, + numberOfRequiredAttestations: number, + ): Promise { // Wait and poll the p2pClients attestation pool for this block // until we have enough attestations - this.log.info(`Waiting for attestations for slot, ${slot}`); + const slot = proposal.header.globalVariables.slotNumber.toBigInt(); - let attestations: BlockAttestation[] = []; + this.log.info(`Waiting for ${numberOfRequiredAttestations} attestations for slot: ${slot}`); + + let attestations: BlockAttestation[] = [await this.attestToProposal(proposal)]; while (attestations.length < numberOfRequiredAttestations) { attestations = await this.p2pClient.getAttestationsForSlot(slot); diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 2f89126d3f8..e325bdd7b59 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -1018,6 +1018,7 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/sequencer-client@workspace:sequencer-client" dependencies: + "@aztec/aztec.js": "workspace:^" "@aztec/bb-prover": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^"