diff --git a/docs/docs/guides/js_apps/test.md b/docs/docs/guides/js_apps/test.md index 546ce64a8b60..453ede8c9505 100644 --- a/docs/docs/guides/js_apps/test.md +++ b/docs/docs/guides/js_apps/test.md @@ -132,13 +132,15 @@ The [`CheatCodes`](../../reference/sandbox_reference/cheat_codes.md) class, whic ### Set next block timestamp +Since the + The `warp` method sets the time for next execution, both on L1 and L2. We can test this using an `isTimeEqual` function in a `Test` contract defined like the following: #include_code is-time-equal noir-projects/noir-contracts/contracts/test_contract/src/main.nr rust We can then call `warp` and rely on the `isTimeEqual` function to check that the timestamp was properly modified. -#include_code warp /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript + ## Further reading diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 027afbaa2c66..4045aba154ec 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -60,7 +60,7 @@ contract Rollup is Leonidas, IRollup, ITestRollup { // @note This should not exists, but we have it now to ensure we will not be killing the devnet with our // timeliness requirements. - bool public isDevNet = false; + bool public isDevNet = Constants.IS_DEV_NET == 1; constructor( IRegistry _registry, @@ -386,6 +386,17 @@ contract Rollup is Leonidas, IRollup, ITestRollup { bytes32 _archive ) internal { if (isDevNet) { + // @note If we are running in a devnet, we don't want to perform all the consensus + // checks, we instead simply require that either there are NO validators or + // that the proposer is a validator. + // + // This means that we relaxes the condition that the block must land in the + // correct slot and epoch to make it more fluid for the devnet launch + // or for testing. + if (getValidatorCount() == 0) { + return; + } + if (!isValidator(msg.sender)) { revert Errors.Leonidas__InvalidProposer(address(0), msg.sender); } diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index ab33b0b252da..887d12e09fa3 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -91,7 +91,6 @@ library Constants { uint256 internal constant BASE_ROLLUP_INDEX = 20; uint256 internal constant MERGE_ROLLUP_INDEX = 21; uint256 internal constant ROOT_ROLLUP_INDEX = 22; - uint256 internal constant ETHEREUM_SLOT_DURATION = 12; uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4; uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 16; uint256 internal constant ARGS_HASH_CHUNK_COUNT = 16; @@ -99,6 +98,8 @@ library Constants { uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000; 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 IS_DEV_NET = 1; uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; diff --git a/l1-contracts/src/core/sequencer_selection/ILeonidas.sol b/l1-contracts/src/core/sequencer_selection/ILeonidas.sol index c77cfdee097a..24501446da30 100644 --- a/l1-contracts/src/core/sequencer_selection/ILeonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/ILeonidas.sol @@ -16,6 +16,7 @@ interface ILeonidas { function getCurrentEpoch() external view returns (uint256); function getCurrentSlot() external view returns (uint256); function isValidator(address _validator) external view returns (bool); + function getValidatorCount() external view returns (uint256); // Consider removing below this point function getTimestampForSlot(uint256 _slotNumber) external view returns (uint256); diff --git a/l1-contracts/src/core/sequencer_selection/Leonidas.sol b/l1-contracts/src/core/sequencer_selection/Leonidas.sol index d7bbbf066bbb..cfc88ffed93f 100644 --- a/l1-contracts/src/core/sequencer_selection/Leonidas.sol +++ b/l1-contracts/src/core/sequencer_selection/Leonidas.sol @@ -139,6 +139,15 @@ contract Leonidas is Ownable, ILeonidas { return validatorSet.values(); } + /** + * @notice Get the number of validators in the validator set + * + * @return The number of validators in the validator set + */ + function getValidatorCount() public view override(ILeonidas) returns (uint256) { + return validatorSet.length(); + } + /** * @notice Checks if an address is in the validator set * 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 79dcb29da4d3..19084f7828c9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -129,6 +129,7 @@ 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; +global IS_DEV_NET: bool = true; // CONTRACT CLASS CONSTANTS global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u32 = 20000; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index e934afa5c388..bfcb5e79b7de 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -77,7 +77,6 @@ export const ROOT_PARITY_INDEX = 19; export const BASE_ROLLUP_INDEX = 20; export const MERGE_ROLLUP_INDEX = 21; export const ROOT_ROLLUP_INDEX = 22; -export const ETHEREUM_SLOT_DURATION = 12; export const FUNCTION_SELECTOR_NUM_BYTES = 4; export const ARGS_HASH_CHUNK_LENGTH = 16; export const ARGS_HASH_CHUNK_COUNT = 16; @@ -85,6 +84,8 @@ export const MAX_ARGS_LENGTH = 256; 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 IS_DEV_NET = 1; export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 20000; export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; 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 024857ab6e27..9e087359f209 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 @@ -4,6 +4,8 @@ import { type AztecAddress, CompleteAddress, type DebugLogger, + type DeployL1Contracts, + EthCheatCodes, Fr, GrumpkinScalar, type SentTx, @@ -11,12 +13,15 @@ import { createDebugLogger, sleep, } from '@aztec/aztec.js'; +import { IS_DEV_NET } from '@aztec/circuits.js'; +import { RollupAbi } from '@aztec/l1-artifacts'; import { type BootNodeConfig, BootstrapNode, createLibP2PPeerId } from '@aztec/p2p'; import { type PXEService, createPXEService, getPXEServiceConfig as getRpcConfig } from '@aztec/pxe'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import fs from 'fs'; -import { mnemonicToAccount } from 'viem/accounts'; +import { getContract } from 'viem'; +import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts'; import { MNEMONIC } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; @@ -47,9 +52,45 @@ describe('e2e_p2p_network', () => { let teardown: () => Promise; let bootstrapNode: BootstrapNode; let bootstrapNodeEnr: string; + let deployL1ContractsValues: DeployL1Contracts; beforeEach(async () => { - ({ teardown, config, logger } = await setup(0)); + ({ teardown, config, logger, deployL1ContractsValues } = await setup(0)); + // 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. + + const rollup = getContract({ + address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(), + abi: RollupAbi, + client: deployL1ContractsValues.walletClient, + }); + + if (IS_DEV_NET) { + // Add just ONE of the peers as sequencer, he will be the proposer all blocks. + 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]); + logger.info(`Adding sequencer ${account.address}`); + } else { + // We add all 4 to the set and then jump ahead to the next epoch. + for (let i = 0; i < NUM_NODES; i++) { + 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]); + 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()); + + const cheatCodes = new EthCheatCodes(config.rpcUrl); + const timestamp = (await cheatCodes.timestamp()) + Number(timeToJump); + await cheatCodes.warp(timestamp); + bootstrapNode = await createBootstrapNode(); bootstrapNodeEnr = bootstrapNode.getENR().encodeTxt(); }); diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 4004a05760fe..72c99c090ccb 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -146,6 +146,10 @@ export class L1Publisher implements L2BlockReceiver { this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000; } + public async senderAddress(): Promise { + return await this.txSender.getSenderAddress(); + } + public async isItMyTurnToSubmit(): Promise { const submitter = await this.txSender.getProposerAtNextEthBlock(); const sender = await this.txSender.getSenderAddress(); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 98f6fdeb48c5..e5d2d7b1f806 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -363,7 +363,11 @@ export class Sequencer { } satisfies L2BlockBuiltStats); await this.publishL2Block(block); - this.log.info(`Submitted rollup block ${block.number} with ${processedTxs.length} transactions`); + this.log.info( + `Submitted rollup block ${block.number} with ${ + processedTxs.length + } transactions. Submitter: ${await this.publisher.senderAddress()}`, + ); // Submit the proof if we have configured this sequencer to run with an actual prover. // This is temporary while we submit one proof per block, but will have to change once we