diff --git a/yarn-project/archiver/src/l1/bin/retrieve-calldata.ts b/yarn-project/archiver/src/l1/bin/retrieve-calldata.ts index a8303211f927..6be4953275e4 100644 --- a/yarn-project/archiver/src/l1/bin/retrieve-calldata.ts +++ b/yarn-project/archiver/src/l1/bin/retrieve-calldata.ts @@ -1,10 +1,11 @@ #!/usr/bin/env node import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types'; -import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types'; +import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { EthAddress } from '@aztec/foundation/eth-address'; import { createLogger } from '@aztec/foundation/log'; +import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi'; -import { type Hex, createPublicClient, http } from 'viem'; +import { type Hex, createPublicClient, getAbiItem, http, toEventSelector } from 'viem'; import { mainnet } from 'viem/chains'; import { CalldataRetriever } from '../calldata_retriever.js'; @@ -111,43 +112,36 @@ async function main() { }, ); - // Extract L2 block number from transaction logs - logger.info('Decoding transaction to extract L2 block number...'); + // Extract checkpoint number from transaction logs + logger.info('Decoding transaction to extract checkpoint number...'); const receipt = await publicClient.getTransactionReceipt({ hash: txHash }); - const l2BlockProposedEvent = receipt.logs.find(log => { + + // Look for CheckpointProposed event (emitted when a checkpoint is proposed to the rollup) + // Event signature: CheckpointProposed(uint256 indexed checkpointNumber, bytes32 indexed archive, bytes32[], bytes32, bytes32) + // Hash: keccak256("CheckpointProposed(uint256,bytes32,bytes32[],bytes32,bytes32)") + const checkpointProposedEvent = receipt.logs.find(log => { try { - // Try to match the L2BlockProposed event return ( log.address.toLowerCase() === rollupAddress.toString().toLowerCase() && - log.topics[0] === '0x2f1d0e696fa5186494a2f2f89a0e0bcbb15d607f6c5eac4637e07e1e5e7d3c00' // L2BlockProposed event signature + log.topics[0] === toEventSelector(getAbiItem({ abi: RollupAbi, name: 'CheckpointProposed' })) ); } catch { return false; } }); - let l2BlockNumber: number; - if (l2BlockProposedEvent && l2BlockProposedEvent.topics[1]) { - // L2 block number is typically the first indexed parameter - l2BlockNumber = Number(BigInt(l2BlockProposedEvent.topics[1])); - logger.info(`L2 Block Number (from event): ${l2BlockNumber}`); - } else { - // Fallback: try to extract from transaction data or use a default - logger.warn('Could not extract L2 block number from event, using block number as fallback'); - l2BlockNumber = Number(tx.blockNumber); + if (!checkpointProposedEvent || checkpointProposedEvent.topics[1] === undefined) { + throw new Error(`Checkpoint proposed event not found`); } + const checkpointNumber = CheckpointNumber.fromBigInt(BigInt(checkpointProposedEvent.topics[1])); + logger.info(''); - logger.info('Retrieving block header from rollup transaction...'); + logger.info('Retrieving checkpoint from rollup transaction...'); logger.info(''); // For this script, we don't have blob hashes or expected hashes, so pass empty arrays/objects - const result = await retriever.getCheckpointFromRollupTx( - txHash, - [], - CheckpointNumber.fromBlockNumber(BlockNumber(l2BlockNumber)), - {}, - ); + const result = await retriever.getCheckpointFromRollupTx(txHash, [], checkpointNumber, {}); logger.info(' Successfully retrieved block header!'); logger.info(''); diff --git a/yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts b/yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts index 27950f695f1c..f00090abf580 100644 --- a/yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts +++ b/yarn-project/end-to-end/src/composed/e2e_token_bridge_tutorial_test.test.ts @@ -9,7 +9,6 @@ import { createAztecNodeClient, waitForNode } from '@aztec/aztec.js/node'; import { createExtendedL1Client } from '@aztec/ethereum/client'; import { RollupContract } from '@aztec/ethereum/contracts'; import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract'; -import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { FeeAssetHandlerAbi, FeeAssetHandlerBytecode, @@ -218,7 +217,8 @@ describe('e2e_cross_chain_messaging token_bridge_tutorial_test', () => { // docs:start:l1-withdraw const rollup = new RollupContract(l1Client, l1ContractAddresses.rollupAddress.toString()); - const epoch = await rollup.getEpochNumberForCheckpoint(CheckpointNumber.fromBlockNumber(l2TxReceipt.blockNumber!)); + const block = await node.getBlock(l2TxReceipt.blockNumber!); + const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); const result = await computeL2ToL1MembershipWitness(node, epoch, l2ToL1Message); if (!result) { diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts index ffd55390d3d7..da544278e802 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts @@ -13,7 +13,7 @@ import type { } from '@aztec/ethereum/deploy-aztec-l1-contracts'; import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract'; import type { ExtendedViemWalletClient } from '@aztec/ethereum/types'; -import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { EpochNumber } from '@aztec/foundation/branded-types'; import { sleep } from '@aztec/foundation/sleep'; import { TestERC20Abi, TestERC20Bytecode } from '@aztec/l1-artifacts'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; @@ -86,9 +86,8 @@ export class CrossChainMessagingTest { } async advanceToEpochProven(l2TxReceipt: TxReceipt): Promise { - const epoch = await this.rollup.getEpochNumberForCheckpoint( - CheckpointNumber.fromBlockNumber(l2TxReceipt.blockNumber!), - ); + const block = await this.aztecNode.getBlock(l2TxReceipt.blockNumber!); + const epoch = await this.rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); // Warp to the next epoch. await this.cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1)); // Wait for the tx to be proven. diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_invalidate_block.parallel.test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_invalidate_block.parallel.test.ts index 047981fcff1d..abbee51678c3 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_invalidate_block.parallel.test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_invalidate_block.parallel.test.ts @@ -7,7 +7,7 @@ import { RollupContract } from '@aztec/ethereum/contracts'; import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts'; import type { ExtendedViemWalletClient } from '@aztec/ethereum/types'; import { asyncMap } from '@aztec/foundation/async-map'; -import { CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types'; import { times } from '@aztec/foundation/collection'; import { SecretValue } from '@aztec/foundation/config'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -455,7 +455,8 @@ describe('e2e_epochs/epochs_invalidate_block', () => { const [event] = checkpointInvalidatedEvents; logger.warn(`CheckpointInvalidated event emitted`, { event }); expect(event.args.checkpointNumber).toBeGreaterThan(initialBlockNumber); - expect(await test.rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(initialBlockNumber)); + const initialCheckpointNumber = await getCheckpointNumberForBlock(nodes[0], initialBlockNumber); + expect(await test.rollup.getCheckpointNumber()).toEqual(initialCheckpointNumber); logger.warn(`Test succeeded '${expect.getState().currentTestName}'`); }); @@ -511,7 +512,8 @@ describe('e2e_epochs/epochs_invalidate_block', () => { const [event] = checkpointInvalidatedEvents; logger.warn(`CheckpointInvalidated event emitted`, { event }); expect(event.args.checkpointNumber).toBeGreaterThan(initialBlockNumber); - expect(await test.rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(initialBlockNumber)); + const initialCheckpointNumber = await getCheckpointNumberForBlock(nodes[0], initialBlockNumber); + expect(await test.rollup.getCheckpointNumber()).toEqual(initialCheckpointNumber); logger.warn(`Test succeeded '${expect.getState().currentTestName}'`); }); @@ -586,3 +588,17 @@ describe('e2e_epochs/epochs_invalidate_block', () => { logger.warn(`Test succeeded '${expect.getState().currentTestName}'`); }); }); + +async function getCheckpointNumberForBlock( + node: AztecNodeService, + blockNumber: BlockNumber, +): Promise { + if (blockNumber === 0) { + return CheckpointNumber(0); + } + const block = await node.getBlock(blockNumber); + if (!block) { + throw new Error(`Block ${blockNumber} not found`); + } + return block.checkpointNumber; +} diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_multiple.test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_multiple.test.ts index cffc3aef0066..d0f94c81e433 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_multiple.test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_multiple.test.ts @@ -9,6 +9,7 @@ import { EpochsTestContext, WORLD_STATE_BLOCK_HISTORY } from './epochs_test.js'; jest.setTimeout(1000 * 60 * 15); +// Assumes one block per checkpoint describe('e2e_epochs/epochs_multiple', () => { let context: EndToEndContext; let rollup: RollupContract; @@ -42,13 +43,14 @@ describe('e2e_epochs/epochs_multiple', () => { logger.info(`Reached proven checkpoint number ${epochEndCheckpointNumber}, epoch ${epochNumber} is now proven`); epochNumber++; - // Verify the state syncs - await test.waitForNodeToSync(BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber), 'proven'); - await test.verifyHistoricBlock(BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber), true); + // Verify the state syncs. Assumes one block per checkpoint. + const epochEndBlockNumber = BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber); + await test.waitForNodeToSync(epochEndBlockNumber, 'proven'); + await test.verifyHistoricBlock(epochEndBlockNumber, true); // Check that finalized blocks are purged from world state // Right now finalization means a checkpoint is two L2 epochs deep. If this rule changes then this test needs to be updated. - const provenBlockNumber = BlockNumber.fromCheckpointNumber(epochEndCheckpointNumber); + const provenBlockNumber = epochEndBlockNumber; const finalizedBlockNumber = Math.max(provenBlockNumber - context.config.aztecEpochDuration * 2, 0); const expectedOldestHistoricBlock = Math.max(finalizedBlockNumber - WORLD_STATE_BLOCK_HISTORY + 1, 1); const expectedBlockRemoved = expectedOldestHistoricBlock - 1; diff --git a/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts b/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts index bf8dc29ddcd6..593a096647f2 100644 --- a/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/e2e_l1_publisher/e2e_l1_publisher.test.ts @@ -196,6 +196,7 @@ describe('L1Publisher integration', () => { slicedBlocks.map( async block => new CheckpointedL2Block( + // Test uses 1-block-per-checkpoint, so checkpoint number equals block number CheckpointNumber.fromBlockNumber(block.number), block, new L1PublishedData(BigInt(block.number), BigInt(block.number), (await block.hash()).toString()), @@ -205,6 +206,7 @@ describe('L1Publisher integration', () => { ); }, async getCheckpoints(checkpointNumber, _limit) { + // Test uses 1-block-per-checkpoint, so we find block by checkpoint number const block = blocks.find(b => Number(b.number) === Number(checkpointNumber)); if (!block) { return Promise.resolve([]); @@ -213,7 +215,7 @@ describe('L1Publisher integration', () => { block.archive, CheckpointHeader.random({ lastArchiveRoot: block.header.lastArchive.root }), [block], - CheckpointNumber.fromBlockNumber(block.number), + checkpointNumber, ); return [ new PublishedCheckpoint( @@ -228,6 +230,7 @@ describe('L1Publisher integration', () => { const blockId = latestBlock ? { number: latestBlock.number, hash: (await latestBlock.hash()).toString() } : { number: BlockNumber.ZERO, hash: GENESIS_BLOCK_HEADER_HASH.toString() }; + // Test uses 1-block-per-checkpoint, so checkpoint number equals block number const tipId = { block: blockId, checkpoint: { number: CheckpointNumber.fromBlockNumber(blockId.number), hash: blockId.hash }, @@ -352,6 +355,7 @@ describe('L1Publisher integration', () => { gasFees: globalVariables.gasFees, }; + // Test uses 1-block-per-checkpoint const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber); const builder = await LightweightCheckpointBuilder.startNewCheckpoint( checkpointNumber, @@ -491,7 +495,7 @@ describe('L1Publisher integration', () => { }); expect(logs).toHaveLength(i + 1); expect(logs[i].args.checkpointNumber).toEqual(BigInt(i + 1)); - const thisCheckpointNumber = CheckpointNumber.fromBlockNumber(block.header.globalVariables.blockNumber); + const thisCheckpointNumber = checkpoint.number; const prevCheckpointNumber = CheckpointNumber(thisCheckpointNumber - 1); const isFirstCheckpointOfEpoch = thisCheckpointNumber == CheckpointNumber(1) || @@ -895,7 +899,6 @@ describe('L1Publisher integration', () => { it(`speeds up block proposal if not mined`, async () => { const { checkpoint } = await buildSingleCheckpoint(); - const block = checkpoint.blocks[0]; await enqueueProposeL2Checkpoint(checkpoint); await sendRequests(); @@ -925,7 +928,7 @@ describe('L1Publisher integration', () => { expect(minedTx).toBeDefined(); const minedTxReceipt = await l1Client.getTransactionReceipt({ hash: minedTx!.hash }); expect(minedTxReceipt.status).toEqual('success'); - expect(await rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(block.number)); + expect(await rollup.getCheckpointNumber()).toEqual(checkpoint.number); }); it(`can send two consecutive proposals if the first one times out`, async () => { @@ -978,8 +981,8 @@ describe('L1Publisher integration', () => { expect(sendRequestsResult).not.toBeNull(); expect(sendRequestsResult!.successfulActions).toEqual(['propose']); expect(sendRequestsResult!.failedActions).toEqual([]); - expect(await rollup.getCheckpointNumber()).toEqual(CheckpointNumber.fromBlockNumber(block2.number)); - const rollupBlock = await rollup.getCheckpoint(CheckpointNumber.fromBlockNumber(block2.number)); + expect(await rollup.getCheckpointNumber()).toEqual(checkpoint2.number); + const rollupBlock = await rollup.getCheckpoint(checkpoint2.number); expect(rollupBlock.slotNumber).toEqual(block2.slot); }); }); diff --git a/yarn-project/end-to-end/src/e2e_multi_validator/e2e_multi_validator_node.test.ts b/yarn-project/end-to-end/src/e2e_multi_validator/e2e_multi_validator_node.test.ts index 0fe774e79a48..ab66bef2f868 100644 --- a/yarn-project/end-to-end/src/e2e_multi_validator/e2e_multi_validator_node.test.ts +++ b/yarn-project/end-to-end/src/e2e_multi_validator/e2e_multi_validator_node.test.ts @@ -12,7 +12,7 @@ import { createExtendedL1Client } from '@aztec/ethereum/client'; import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config'; import { RollupContract } from '@aztec/ethereum/contracts'; import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-aztec-l1-contracts'; -import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { EpochNumber } from '@aztec/foundation/branded-types'; import { SecretValue } from '@aztec/foundation/config'; import { Signature } from '@aztec/foundation/eth-signature'; import { retryUntil } from '@aztec/foundation/retry'; @@ -127,7 +127,8 @@ describe('e2e_multi_validator_node', () => { expect(tx.blockNumber).toBeDefined(); const dataStore = (aztecNode as AztecNodeService).getBlockSource() as Archiver; - const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(tx.blockNumber!), 1); + const checkpointedBlock = await dataStore.getCheckpointedBlock(tx.blockNumber!); + const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1); const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint); const attestations = publishedCheckpoint.attestations .filter(a => !a.signature.isEmpty()) @@ -139,6 +140,7 @@ describe('e2e_multi_validator_node', () => { expect(signers.every(s => validatorAddresses.includes(s))).toBe(true); }); + it('should attest ONLY with the correct validator keys', async () => { const rollupContract1 = getContract({ address: deployL1ContractsValues.l1ContractAddresses.rollupAddress.toString(), @@ -188,7 +190,8 @@ describe('e2e_multi_validator_node', () => { expect(tx.blockNumber).toBeDefined(); const dataStore = (aztecNode as AztecNodeService).getBlockSource() as Archiver; - const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(tx.blockNumber!), 1); + const checkpointedBlock = await dataStore.getCheckpointedBlock(tx.blockNumber!); + const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1); const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint); const attestations = publishedCheckpoint.attestations .filter(a => !a.signature.isEmpty()) diff --git a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts index ec8dbab06c20..97cc8688614f 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts @@ -350,9 +350,8 @@ describe('e2e_p2p_add_rollup', () => { }); const rollup = new RollupContract(l1Client, l1ContractAddresses.rollupAddress); - const epoch = await rollup.getEpochNumberForCheckpoint( - CheckpointNumber.fromBlockNumber(l2OutgoingReceipt.blockNumber!), - ); + const block = await node.getBlock(l2OutgoingReceipt.blockNumber!); + const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); const l2ToL1MessageResult = (await computeL2ToL1MembershipWitness(node, epoch, leaf))!; const leafId = getL2ToL1MessageLeafId(l2ToL1MessageResult); diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts index 5746ccf6cdef..11b1be6a9ab5 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network.test.ts @@ -2,7 +2,6 @@ import type { Archiver } from '@aztec/archiver'; import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node'; import { waitForTx } from '@aztec/aztec.js/node'; import { TxHash } from '@aztec/aztec.js/tx'; -import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { Signature } from '@aztec/foundation/eth-signature'; import { retryUntil } from '@aztec/foundation/retry'; import type { ProverNode } from '@aztec/prover-node'; @@ -189,7 +188,8 @@ describe('e2e_p2p_network', () => { const receipt = await nodes[0].getTxReceipt(txsSentViaDifferentNodes[0][0]); const blockNumber = receipt.blockNumber!; const dataStore = (nodes[0] as AztecNodeService).getBlockSource() as Archiver; - const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(blockNumber), 1); + const checkpointedBlock = await dataStore.getCheckpointedBlock(blockNumber); + const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1); const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint); const attestations = publishedCheckpoint.attestations .filter(a => !a.signature.isEmpty()) diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts index ae9ed1450506..44d25d9cc016 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts @@ -6,7 +6,7 @@ import { waitForTx } from '@aztec/aztec.js/node'; import { TxHash } from '@aztec/aztec.js/tx'; import { addL1Validator } from '@aztec/cli/l1/validators'; import { RollupContract } from '@aztec/ethereum/contracts'; -import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { EpochNumber } from '@aztec/foundation/branded-types'; import { Signature } from '@aztec/foundation/eth-signature'; import { sleep } from '@aztec/foundation/sleep'; import { MockZKPassportVerifierAbi } from '@aztec/l1-artifacts/MockZKPassportVerifierAbi'; @@ -224,7 +224,8 @@ describe('e2e_p2p_network', () => { // Gather signers from attestations downloaded from L1 const blockNumber = await nodes[0].getTxReceipt(txsSentViaDifferentNodes[0][0]).then(r => r.blockNumber!); const dataStore = (nodes[0] as AztecNodeService).getBlockSource() as Archiver; - const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(blockNumber), 1); + const checkpointedBlock = await dataStore.getCheckpointedBlock(blockNumber); + const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1); const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint); const attestations = publishedCheckpoint.attestations .filter(a => !a.signature.isEmpty()) diff --git a/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts b/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts index 068391ccd2ce..5453d47ebcce 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/preferred_gossip_network.test.ts @@ -2,7 +2,6 @@ import type { Archiver } from '@aztec/archiver'; import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node'; import { waitForTx } from '@aztec/aztec.js/node'; import { TxHash } from '@aztec/aztec.js/tx'; -import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { Signature } from '@aztec/foundation/eth-signature'; import { retryUntil } from '@aztec/foundation/retry'; import { ENR, type P2PClient, type P2PService, type PeerId } from '@aztec/p2p'; @@ -359,7 +358,8 @@ describe('e2e_p2p_preferred_network', () => { // Gather signers from attestations downloaded from L1 const blockNumber = receipts[0].blockNumber!; const dataStore = (nodes[0] as AztecNodeService).getBlockSource() as Archiver; - const [publishedCheckpoint] = await dataStore.getCheckpoints(CheckpointNumber.fromBlockNumber(blockNumber), 1); + const checkpointedBlock = await dataStore.getCheckpointedBlock(blockNumber); + const [publishedCheckpoint] = await dataStore.getCheckpoints(checkpointedBlock!.checkpointNumber, 1); const payload = ConsensusPayload.fromCheckpoint(publishedCheckpoint.checkpoint); const attestations = publishedCheckpoint.attestations .filter(a => !a.signature.isEmpty()) diff --git a/yarn-project/end-to-end/src/e2e_synching.test.ts b/yarn-project/end-to-end/src/e2e_synching.test.ts index 23efdac1334d..b0f763a1bcfb 100644 --- a/yarn-project/end-to-end/src/e2e_synching.test.ts +++ b/yarn-project/end-to-end/src/e2e_synching.test.ts @@ -22,14 +22,14 @@ * much from running it in CI, and it is therefore skipped. * * - * Previous results. The `blockCount` is the number of blocks we will construct with `txCount` + * Previous results. The `checkpointCount` is the number of blocks we will construct with `txCount` * transactions of the `complexity` provided. * The `numberOfBlocks` is the total number of blocks, including deployments of canonical contracts * and setup before we start the "actual" test. - * blockCount: 10, txCount: 36, complexity: Deployment: {"numberOfBlocks":16, "syncTime":17.490706521987914} - * blockCount: 10, txCount: 36, complexity: PrivateTransfer: {"numberOfBlocks":19, "syncTime":20.846745924949644} - * blockCount: 10, txCount: 36, complexity: PublicTransfer: {"numberOfBlocks":18, "syncTime":21.340179460525512} - * blockCount: 10, txCount: 9, complexity: Spam: {"numberOfBlocks":17, "syncTime":49.40888188171387} + * checkpointCount: 10, txCount: 36, complexity: Deployment: {"numberOfBlocks":16, "syncTime":17.490706521987914} + * checkpointCount: 10, txCount: 36, complexity: PrivateTransfer: {"numberOfBlocks":19, "syncTime":20.846745924949644} + * checkpointCount: 10, txCount: 36, complexity: PublicTransfer: {"numberOfBlocks":18, "syncTime":21.340179460525512} + * checkpointCount: 10, txCount: 9, complexity: Spam: {"numberOfBlocks":17, "syncTime":49.40888188171387} */ import type { InitialAccountData } from '@aztec/accounts/testing'; import { createArchiver } from '@aztec/archiver'; @@ -44,7 +44,7 @@ import { EpochCache } from '@aztec/epoch-cache'; import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config'; import { EmpireSlashingProposerContract, GovernanceProposerContract, RollupContract } from '@aztec/ethereum/contracts'; import { createL1TxUtilsWithBlobsFromViemWallet } from '@aztec/ethereum/l1-tx-utils-with-blobs'; -import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types'; +import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { SecretValue } from '@aztec/foundation/config'; import { Signature } from '@aztec/foundation/eth-signature'; import { sleep } from '@aztec/foundation/sleep'; @@ -83,7 +83,7 @@ enum TxComplexity { } type VariantDefinition = { - blockCount: number; + checkpointCount: number; txCount: number; txComplexity: TxComplexity; }; @@ -111,12 +111,12 @@ class TestVariant { private contractAddresses: AztecAddress[] = []; - public blockCount: number; + public checkpointCount: number; public txCount: number; public txComplexity: TxComplexity; constructor(def: VariantDefinition) { - this.blockCount = def.blockCount; + this.checkpointCount = def.checkpointCount; this.txCount = def.txCount; this.txComplexity = def.txComplexity; } @@ -138,11 +138,11 @@ class TestVariant { } description() { - return `blockCount: ${this.blockCount}, txCount: ${this.txCount}, complexity: ${TxComplexity[this.txComplexity]}`; + return `checkpointCount: ${this.checkpointCount}, txCount: ${this.txCount}, complexity: ${TxComplexity[this.txComplexity]}`; } name() { - return `${this.blockCount}_${this.txCount}_${this.txComplexity}`; + return `${this.checkpointCount}_${this.txCount}_${this.txComplexity}`; } async deployAccounts(accounts: InitialAccountData[]) { @@ -297,11 +297,11 @@ class TestVariant { * I decided that 1/4 should be acceptable, and still small enough to work. */ const variants: VariantDefinition[] = [ - { blockCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }, - { blockCount: 10, txCount: 36, txComplexity: TxComplexity.PrivateTransfer }, - { blockCount: 10, txCount: 36, txComplexity: TxComplexity.PublicTransfer }, - { blockCount: 10, txCount: 9, txComplexity: TxComplexity.Spam }, - { blockCount: 1000, txCount: 4, txComplexity: TxComplexity.PrivateTransfer }, + { checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }, + { checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.PrivateTransfer }, + { checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.PublicTransfer }, + { checkpointCount: 10, txCount: 9, txComplexity: TxComplexity.Spam }, + { checkpointCount: 1000, txCount: 4, txComplexity: TxComplexity.PrivateTransfer }, ]; describe('e2e_synching', () => { @@ -315,7 +315,7 @@ describe('e2e_synching', () => { } // @note If the `RUN_THE_BIG_ONE` flag is not set, we DO NOT run it. - if (!RUN_THE_BIG_ONE && variantDef.blockCount === 1000) { + if (!RUN_THE_BIG_ONE && variantDef.checkpointCount === 1000) { return; } @@ -356,7 +356,7 @@ describe('e2e_synching', () => { const accountsToBeDeployed = initialFundedAccounts.slice(1); // The first one has been deployed in setup. await variant.setup(accountsToBeDeployed); - for (let i = 0; i < variant.blockCount; i++) { + for (let i = 0; i < variant.checkpointCount; i++) { const txHashPromises = await variant.createAndSendTxs(); if (txHashPromises) { const txHashes = await Promise.all(txHashPromises); @@ -378,7 +378,7 @@ describe('e2e_synching', () => { const testTheVariant = async ( variant: TestVariant, alternativeSync: (opts: Partial, variant: TestVariant) => Promise, - provenThrough: number = Number.MAX_SAFE_INTEGER, + provenThrough: CheckpointNumber = CheckpointNumber(Number.MAX_SAFE_INTEGER), ) => { if (AZTEC_GENERATE_TEST_DATA) { return; @@ -470,7 +470,7 @@ describe('e2e_synching', () => { // If it breaks here, first place you should look is the pruning. await publisher.enqueueProposeCheckpoint(checkpoint, CommitteeAttestationsAndSigners.empty(), Signature.empty()); - await cheatCodes.rollup.markAsProven(CheckpointNumber.fromBlockNumber(BlockNumber(provenThrough))); + await cheatCodes.rollup.markAsProven(CheckpointNumber(provenThrough)); } await alternativeSync( @@ -486,7 +486,7 @@ describe('e2e_synching', () => { 'vanilla - %s', async (variantDef: VariantDefinition) => { // @note If the `RUN_THE_BIG_ONE` flag is not set, we DO NOT run it. - if (!RUN_THE_BIG_ONE && variantDef.blockCount === 1000) { + if (!RUN_THE_BIG_ONE && variantDef.checkpointCount === 1000) { return; } @@ -516,7 +516,7 @@ describe('e2e_synching', () => { }); describe.skip('a wild prune appears', () => { - const ASSUME_PROVEN_THROUGH = 0; + const ASSUME_PROVEN_THROUGH = CheckpointNumber(0); it('archiver following catches reorg as it occur and deletes blocks', async () => { if (AZTEC_GENERATE_TEST_DATA) { @@ -524,7 +524,7 @@ describe('e2e_synching', () => { } await testTheVariant( - new TestVariant({ blockCount: 10, txCount: 36, txComplexity: TxComplexity.PrivateTransfer }), + new TestVariant({ checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.PrivateTransfer }), async (opts: Partial, variant: TestVariant) => { const rollup = getContract({ address: opts.deployL1ContractsValues!.l1ContractAddresses.rollupAddress.toString(), @@ -574,15 +574,14 @@ describe('e2e_synching', () => { { blobClient, dateProvider: opts.dateProvider! }, { blockUntilSync: true }, ); - const pendingBlockNumber = await rollup.read.getPendingCheckpointNumber(); + const pendingCheckpointNumber = CheckpointNumber.fromBigInt(await rollup.read.getPendingCheckpointNumber()); const worldState = await createWorldStateSynchronizer(opts.config!, archiver); await worldState.start(); - expect(await worldState.getLatestBlockNumber()).toEqual(Number(pendingBlockNumber)); // We prune the last token and schnorr contract - const provenThrough = BlockNumber.fromBigInt(pendingBlockNumber - 2n); - await opts.cheatCodes!.rollup.markAsProven(CheckpointNumber.fromBlockNumber(provenThrough)); + const provenThrough = CheckpointNumber(pendingCheckpointNumber - 2); + await opts.cheatCodes!.rollup.markAsProven(CheckpointNumber(provenThrough)); const timeliness = (await rollup.read.getEpochDuration()) * 2n; const blockLog = await rollup.read.getCheckpoint([(await rollup.read.getProvenCheckpointNumber()) + 1n]); @@ -590,7 +589,7 @@ describe('e2e_synching', () => { await opts.cheatCodes!.eth.warp(Number(timeJumpTo), { resetBlockInterval: true }); - expect(await archiver.getBlockNumber()).toBeGreaterThan(Number(provenThrough)); + expect(await archiver.getCheckpointNumber()).toBeGreaterThan(provenThrough); const blockTip = (await archiver.getBlock(await archiver.getBlockNumber()))!; const txHash = blockTip.body.txEffects[0].txHash; @@ -612,7 +611,7 @@ describe('e2e_synching', () => { // We need to sleep a bit to make sure that we have caught the prune and deleted blocks. await sleep(3000); - expect(await archiver.getBlockNumber()).toBe(Number(provenThrough)); + expect(await archiver.getCheckpointNumber()).toBe(provenThrough); const contractClassIdsAfter = await archiver.getContractClassIds(); @@ -633,12 +632,8 @@ describe('e2e_synching', () => { ); // Check world state reverted as well - expect(await worldState.getLatestBlockNumber()).toEqual(Number(provenThrough)); - const worldStateLatestBlockHash = await worldState.getL2BlockHash(BlockNumber(Number(provenThrough))); - const archiverLatestBlockHash = await archiver - .getBlockHeader(BlockNumber(Number(provenThrough))) - .then(b => b?.hash()); - expect(worldStateLatestBlockHash).toEqual(archiverLatestBlockHash?.toString()); + const latestBlockNumber = await archiver.getBlockNumber(); + expect(await worldState.getLatestBlockNumber()).toEqual(latestBlockNumber); await tryStop(archiver); await worldState.stop(); @@ -655,7 +650,7 @@ describe('e2e_synching', () => { } await testTheVariant( - new TestVariant({ blockCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }), + new TestVariant({ checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }), async (opts: Partial, variant: TestVariant) => { const rollup = getContract({ address: opts.deployL1ContractsValues!.l1ContractAddresses.rollupAddress.toString(), @@ -664,7 +659,7 @@ describe('e2e_synching', () => { }); const pendingCheckpointNumber = CheckpointNumber.fromBigInt(await rollup.read.getPendingCheckpointNumber()); - const offset = CheckpointNumber.fromBlockNumber(BlockNumber(variant.blockCount / 2)); + const offset = CheckpointNumber(variant.checkpointCount / 2); await opts.cheatCodes!.rollup.markAsProven(CheckpointNumber(pendingCheckpointNumber - offset)); const aztecNode = await AztecNodeService.createAndSync(opts.config!); @@ -721,7 +716,7 @@ describe('e2e_synching', () => { } await testTheVariant( - new TestVariant({ blockCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }), + new TestVariant({ checkpointCount: 10, txCount: 36, txComplexity: TxComplexity.Deployment }), async (opts: Partial, variant: TestVariant) => { const rollup = getContract({ address: opts.deployL1ContractsValues!.l1ContractAddresses.rollupAddress.toString(), @@ -730,7 +725,7 @@ describe('e2e_synching', () => { }); const pendingCheckpointNumber = CheckpointNumber.fromBigInt(await rollup.read.getPendingCheckpointNumber()); - const offset = CheckpointNumber.fromBlockNumber(BlockNumber(variant.blockCount / 2)); + const offset = CheckpointNumber(variant.checkpointCount / 2); await opts.cheatCodes!.rollup.markAsProven(CheckpointNumber(pendingCheckpointNumber - offset)); const timeliness = (await rollup.read.getEpochDuration()) * 2n; diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 6e65a7a52618..b52c71f5bd30 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -11,7 +11,7 @@ import type { DeployAztecL1ContractsReturnType } from '@aztec/ethereum/deploy-az import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract'; import type { ExtendedViemWalletClient } from '@aztec/ethereum/types'; import { extractEvent } from '@aztec/ethereum/utils'; -import { CheckpointNumber, EpochNumber } from '@aztec/foundation/branded-types'; +import { EpochNumber } from '@aztec/foundation/branded-types'; import { sha256ToField } from '@aztec/foundation/crypto/sha256'; import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; @@ -250,8 +250,8 @@ export const uniswapL1L2TestSuite = ( await wethCrossChainHarness.expectPublicBalanceOnL2(uniswapL2Contract.address, 0n); // Since the outbox is only consumable when the epoch is proven, we need to advance to the next epoch. - const checkpointNumber = CheckpointNumber.fromBlockNumber(l2UniswapInteractionReceipt.blockNumber!); - const epoch = await rollup.getEpochNumberForCheckpoint(checkpointNumber); + const block = await aztecNode.getBlock(l2UniswapInteractionReceipt.blockNumber!); + const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); await cheatCodes.rollup.advanceToEpoch(EpochNumber(epoch + 1)); await waitForProven(aztecNode, l2UniswapInteractionReceipt, { provenTimeout: 300 }); @@ -838,9 +838,8 @@ export const uniswapL1L2TestSuite = ( chainId: new Fr(l1Client.chain.id), }); - const epoch = await rollup.getEpochNumberForCheckpoint( - CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!), - ); + const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!); + const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPrivateLeaf); const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf); @@ -972,9 +971,8 @@ export const uniswapL1L2TestSuite = ( chainId: new Fr(l1Client.chain.id), }); - const epoch = await rollup.getEpochNumberForCheckpoint( - CheckpointNumber.fromBlockNumber(withdrawReceipt.blockNumber!), - ); + const block = await aztecNode.getBlock(withdrawReceipt.blockNumber!); + const epoch = await rollup.getEpochNumberForCheckpoint(block!.checkpointNumber); const swapResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, swapPublicLeaf); const withdrawResult = await computeL2ToL1MembershipWitness(aztecNode, epoch, withdrawLeaf); diff --git a/yarn-project/txe/src/state_machine/archiver.ts b/yarn-project/txe/src/state_machine/archiver.ts index 639c5232cc57..c601ed33ce85 100644 --- a/yarn-project/txe/src/state_machine/archiver.ts +++ b/yarn-project/txe/src/state_machine/archiver.ts @@ -59,6 +59,8 @@ export class TXEArchiver extends ArchiverDataSourceBase { if (!checkpointedBlock) { throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`); } + // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number. + // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment. const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1); if (checkpoint.length === 0) { throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`); diff --git a/yarn-project/txe/src/state_machine/index.ts b/yarn-project/txe/src/state_machine/index.ts index 924b272cb987..c9e35f72a09e 100644 --- a/yarn-project/txe/src/state_machine/index.ts +++ b/yarn-project/txe/src/state_machine/index.ts @@ -62,7 +62,10 @@ export class TXEStateMachine { } public async handleL2Block(block: L2Block) { - // Create a checkpoint from the block manually + // Create a checkpoint from the block manually. + // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number. + // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment. + const checkpointNumber = CheckpointNumber.fromBlockNumber(block.number); const checkpoint = new Checkpoint( block.archive, CheckpointHeader.from({ @@ -79,7 +82,7 @@ export class TXEStateMachine { totalManaUsed: block.header.totalManaUsed, }), [block], - CheckpointNumber.fromBlockNumber(block.number), + checkpointNumber, ); const publishedCheckpoint = new PublishedCheckpoint( diff --git a/yarn-project/txe/src/utils/block_creation.ts b/yarn-project/txe/src/utils/block_creation.ts index d38917e1fbb3..a035a2e409bd 100644 --- a/yarn-project/txe/src/utils/block_creation.ts +++ b/yarn-project/txe/src/utils/block_creation.ts @@ -87,7 +87,9 @@ export async function makeTXEBlock( const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE); const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size)); - // L2Block requires checkpointNumber and indexWithinCheckpoint + // L2Block requires checkpointNumber and indexWithinCheckpoint. + // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number. + // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment. const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber); const indexWithinCheckpoint = IndexWithinCheckpoint(0);