diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 0dd534a9e79b..2d32c4858c8e 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -90,7 +90,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { // Genesis block blocks[0] = BlockLog({ - archive: bytes32(0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e), + archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT), blockHash: bytes32(0), slotNumber: 0, isProven: true diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index fc93f58796a8..2e04e93dfe28 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -105,6 +105,8 @@ library Constants { 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/test/sparta/Sparta.t.sol b/l1-contracts/test/sparta/Sparta.t.sol index caeb9b90acf1..dad40cec3749 100644 --- a/l1-contracts/test/sparta/Sparta.t.sol +++ b/l1-contracts/test/sparta/Sparta.t.sol @@ -125,8 +125,8 @@ contract SpartaTest is DecoderBase { return; } - _testBlock("mixed_block_1", false, 3, 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) { 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 4d7d23f375fa..ebb231a48959 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -134,9 +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 54f5fe104ab0..306aca914065 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -91,6 +91,7 @@ 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/src/composed/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/composed/integration_l1_publisher.test.ts index 5831f80f1ccf..563f6cdd84dd 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, @@ -77,9 +78,6 @@ const config = getConfigEnvVars(); const numberOfConsecutiveBlocks = 2; -// The initial archive is what we have in the genesis block in `Rollup.sol`. -const INITIAL_ARCHIVE = Fr.fromString('0x1200a06aae1368abe36530b585bd7a4d2ba4de5037b82076412691a187d7621e').toBuffer(); - describe('L1Publisher integration', () => { let publicClient: PublicClient; let walletClient: WalletClient; @@ -351,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(INITIAL_ARCHIVE); + 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. @@ -469,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! + // 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(INITIAL_ARCHIVE); + expect(hexStringToBuffer(archiveInRollup_.toString())).toEqual(new Fr(GENESIS_ARCHIVE_ROOT).toBuffer()); const blockNumber = await publicClient.getBlockNumber(); diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index 5c0c9eea6b03..9eb751298801 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -243,7 +243,8 @@ export const deployL1Contracts = async ( 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 + // @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; diff --git a/yarn-project/sequencer-client/src/publisher/config.ts b/yarn-project/sequencer-client/src/publisher/config.ts index 65faaf37dc4e..b31fdd3b2519 100644 --- a/yarn-project/sequencer-client/src/publisher/config.ts +++ b/yarn-project/sequencer-client/src/publisher/config.ts @@ -26,6 +26,7 @@ export interface PublisherConfig { 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; } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index f6c075b77bda..020e5077b69d 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -95,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. @@ -187,7 +194,7 @@ export class L1Publisher { // @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<[EthAddress, bigint, bigint, Buffer]> { + public async getMetadataForSlotAtNextEthBlock(): Promise { const ts = BigInt((await this.publicClient.getBlock()).timestamp + BigInt(ETHEREUM_SLOT_DURATION)); const [submitter, slot, pendingBlockCount, archive] = await Promise.all([ @@ -197,12 +204,12 @@ export class L1Publisher { this.rollupContract.read.archive(), ]); - return [ - EthAddress.fromString(submitter), + return { + proposer: EthAddress.fromString(submitter), slot, - pendingBlockCount - 1n, - Buffer.from(archive.replace('0x', ''), 'hex'), - ]; + pendingBlockNumber: pendingBlockCount - 1n, + archive: Buffer.from(archive.replace('0x', ''), 'hex'), + }; } public async getCurrentEpochCommittee(): Promise { @@ -317,6 +324,8 @@ export class L1Publisher { // 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; diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 929f30cd1694..aec543dfef4d 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -289,7 +289,7 @@ export class Sequencer { // Also, we are logging debug messages for checks that fail to make it easier to debug, as we are usually // catching the errors. - const [submitter, slot, pendingBlockNumber, archive] = await this.publisher.getMetadataForSlotAtNextEthBlock(); + const { proposer, slot, pendingBlockNumber, archive } = await this.publisher.getMetadataForSlotAtNextEthBlock(); if (await this.publisher.willSimulationFail(slot)) { // @note See comment in willSimulationFail for more information @@ -362,7 +362,7 @@ export class Sequencer { } // Do not go forward with new block if not free for all or my turn - if (!submitter.isZero() && !submitter.equals(await this.publisher.getSenderAddress())) { + 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); @@ -440,8 +440,6 @@ export class Sequencer { return true; } - async assertCanStillProposeBlock(): Promise {} - @trackSpan( 'Sequencer.buildBlockAndPublish', (_validTxs, newGlobalVariables, _historicalHeader, _chainTipArchive) => ({