From 94cbb5d7c08df4bee408be54536492d40cc24cd7 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 2 Sep 2025 10:39:31 +0000 Subject: [PATCH] Allow consuming l1-to-l2 message in the same block. --- .../crates/rollup-base-private/Prover.toml | 2 +- .../crates/rollup-block-root/Prover.toml | 8 +- .../rollup-lib/src/base/public_base_rollup.nr | 2 +- .../block_root/block_root_rollup_inputs.nr | 8 +- .../block_root_rollup_inputs_validator.nr | 7 -- .../block_root_rollup_output_composer.nr | 9 ++ .../src/tests/rollup_fixture_builder.nr | 16 ++- .../crates/rollup-merge/Prover.toml | 4 +- .../types/src/abis/block_constant_data.nr | 8 +- .../crates/types/src/constants.nr | 2 +- .../crates/types/src/tests/fixture_builder.nr | 2 +- .../epochs_proof_public_cross_chain.test.ts | 14 ++- .../src/conversion/server.ts | 4 +- .../src/block-factory/light.test.ts | 20 ++-- .../prover-client/src/block-factory/light.ts | 4 +- .../prover-client/src/mocks/test_context.ts | 99 ++++++++++++------- .../orchestrator/block-building-helpers.ts | 6 +- .../src/orchestrator/block-proving-state.ts | 4 +- .../src/orchestrator/orchestrator.ts | 2 +- .../orchestrator/orchestrator_errors.test.ts | 19 ++-- .../orchestrator_failures.test.ts | 4 +- .../orchestrator_mixed_blocks.test.ts | 8 +- ...rchestrator_multi_public_functions.test.ts | 23 ++++- .../orchestrator_public_functions.test.ts | 4 +- .../orchestrator_single_blocks.test.ts | 10 +- .../orchestrator_workflow.test.ts | 11 ++- .../src/test/bb_prover_full_rollup.test.ts | 9 +- .../src/test/bb_prover_parity.test.ts | 5 +- .../stdlib/src/rollup/block_constant_data.ts | 6 +- yarn-project/stdlib/src/tests/factories.ts | 6 ++ yarn-project/stdlib/src/tx/tree_snapshots.ts | 8 +- 31 files changed, 199 insertions(+), 135 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-base-private/Prover.toml b/noir-projects/noir-protocol-circuits/crates/rollup-base-private/Prover.toml index 2e0a356d9f8e..4c401429bbf6 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-base-private/Prover.toml +++ b/noir-projects/noir-protocol-circuits/crates/rollup-base-private/Prover.toml @@ -8358,7 +8358,7 @@ next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000 root = "0x04522891b206ed43de89ad1f2bf6701ff8589b78893ee32d43a231522f99bfa3" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000009" - [inputs.constants.last_l1_to_l2] + [inputs.constants.new_l1_to_l2] root = "0x2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000080" diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-block-root/Prover.toml b/noir-projects/noir-protocol-circuits/crates/rollup-block-root/Prover.toml index 6779fdebb2c5..73e137c3936a 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-block-root/Prover.toml +++ b/noir-projects/noir-protocol-circuits/crates/rollup-block-root/Prover.toml @@ -13,9 +13,9 @@ accumulated_mana_used = "0x00000000000000000000000000000000000000000000000000000 root = "0x11ec690ae2d1a79033acbde89cb053a6bfeb7713fdc47a18b28fde85057afb4d" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000008" - [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.last_l1_to_l2] + [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.new_l1_to_l2] root = "0x2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6" - next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000070" + next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000080" [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.global_variables] chain_id = "0x0000000000000000000000000000000000000000000000000000000000007a69" @@ -781,9 +781,9 @@ accumulated_mana_used = "0x00000000000000000000000000000000000000000000000000000 root = "0x11ec690ae2d1a79033acbde89cb053a6bfeb7713fdc47a18b28fde85057afb4d" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000008" - [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.last_l1_to_l2] + [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.new_l1_to_l2] root = "0x2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6" - next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000070" + next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000080" [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.global_variables] chain_id = "0x0000000000000000000000000000000000000000000000000000000000007a69" diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr index 1b8f18e1ba0f..316abfda86bf 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr @@ -89,7 +89,7 @@ impl PublicBaseRollupInputs { BlockConstantData { last_archive: self.last_archive, - last_l1_to_l2: avm_data.start_tree_snapshots.l1_to_l2_message_tree, + new_l1_to_l2: avm_data.start_tree_snapshots.l1_to_l2_message_tree, global_variables: avm_data.global_variables, vk_tree_root: tube_data.constants.vk_tree_root, protocol_contract_tree_root: tube_data.constants.protocol_contract_tree_root, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/block_root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/block_root_rollup_inputs.nr index c7aa0646bae2..68efe1170095 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/block_root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/block_root_rollup_inputs.nr @@ -372,13 +372,13 @@ pub(crate) mod tests { let _ = builder.execute(); } - #[test(should_fail_with = "last_l1_to_l2 in constants does not match the value in the previous block header")] - unconstrained fn mismatch_last_l1_to_l2_snapshot_fails() { + #[test(should_fail_with = "new_l1_to_l2 in constants does not match the computed value")] + unconstrained fn mismatch_new_l1_to_l2_snapshot_fails() { let mut builder = TestBuilder::new(); - builder.inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.constants.last_l1_to_l2.root += + builder.inputs.previous_rollup_data[0].base_or_merge_rollup_public_inputs.constants.new_l1_to_l2.root += 1; - builder.inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.constants.last_l1_to_l2.root += + builder.inputs.previous_rollup_data[1].base_or_merge_rollup_public_inputs.constants.new_l1_to_l2.root += 1; let _ = builder.execute(); diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_root_rollup_inputs_validator.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_root_rollup_inputs_validator.nr index e67e808d87a3..e245d4bb5cce 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_root_rollup_inputs_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/block_root/components/block_root_rollup_inputs_validator.nr @@ -107,12 +107,5 @@ impl BlockRootRollupInputsValidator BlockConstantData { BlockConstantData { last_archive: self.last_archive, - last_l1_to_l2: self.last_l1_to_l2, + new_l1_to_l2: self.new_l1_to_l2, vk_tree_root: self.vk_tree_root, protocol_contract_tree_root: self.protocol_contract_tree_root, global_variables: self.global_variables, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-merge/Prover.toml b/noir-projects/noir-protocol-circuits/crates/rollup-merge/Prover.toml index 4b063e359998..a536ddaf03fc 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-merge/Prover.toml +++ b/noir-projects/noir-protocol-circuits/crates/rollup-merge/Prover.toml @@ -13,7 +13,7 @@ accumulated_mana_used = "0x00000000000000000000000000000000000000000000000000000 root = "0x11ec690ae2d1a79033acbde89cb053a6bfeb7713fdc47a18b28fde85057afb4d" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000008" - [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.last_l1_to_l2] + [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.new_l1_to_l2] root = "0x2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000070" @@ -781,7 +781,7 @@ accumulated_mana_used = "0x00000000000000000000000000000000000000000000000000000 root = "0x11ec690ae2d1a79033acbde89cb053a6bfeb7713fdc47a18b28fde85057afb4d" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000008" - [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.last_l1_to_l2] + [inputs.previous_rollup_data.base_or_merge_rollup_public_inputs.constants.new_l1_to_l2] root = "0x2e33ee2008411c04b99c24b313513d097a0d21a5040b6193d1f978b8226892d6" next_available_leaf_index = "0x0000000000000000000000000000000000000000000000000000000000000070" diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/block_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/block_constant_data.nr index 426d598ef54f..9539d6dd480f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/block_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/block_constant_data.nr @@ -8,8 +8,8 @@ use std::meta::derive; pub struct BlockConstantData { // Archive tree snapshot at the very beginning of the entire block. pub last_archive: AppendOnlyTreeSnapshot, - // L1toL2Message tree snapshot at the very beginning of the entire block. - pub last_l1_to_l2: AppendOnlyTreeSnapshot, + // L1toL2Message tree snapshot after this block lands. + pub new_l1_to_l2: AppendOnlyTreeSnapshot, pub vk_tree_root: Field, pub protocol_contract_tree_root: Field, pub global_variables: GlobalVariables, @@ -19,7 +19,7 @@ impl Empty for BlockConstantData { fn empty() -> Self { BlockConstantData { last_archive: AppendOnlyTreeSnapshot::empty(), - last_l1_to_l2: AppendOnlyTreeSnapshot::empty(), + new_l1_to_l2: AppendOnlyTreeSnapshot::empty(), vk_tree_root: 0, protocol_contract_tree_root: 0, global_variables: GlobalVariables::empty(), @@ -43,7 +43,7 @@ mod test { fn serialization_of_block_constant_data() { let item = BlockConstantData { last_archive: AppendOnlyTreeSnapshot { root: 123, next_available_leaf_index: 456 }, - last_l1_to_l2: AppendOnlyTreeSnapshot { root: 789, next_available_leaf_index: 101112 }, + new_l1_to_l2: AppendOnlyTreeSnapshot { root: 789, next_available_leaf_index: 101112 }, vk_tree_root: 131415, protocol_contract_tree_root: 161718, global_variables: GlobalVariables { 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 eb258f920806..3e14d73bfafc 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -468,7 +468,7 @@ pub global AVM_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = GLOBAL_VARIABLES_LENGTH + 1 /* reverted */; pub global BLOCK_CONSTANT_DATA_LENGTH: u32 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH /* last_archive */ - + APPEND_ONLY_TREE_SNAPSHOT_LENGTH /* last_l1_to_l2_message_tree */ + + APPEND_ONLY_TREE_SNAPSHOT_LENGTH /* new_l1_to_l2_message_tree */ + 1 /* vk_tree_root */ + 1 /* protocol_contract_tree_root */ + GLOBAL_VARIABLES_LENGTH; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 5043c6b57616..9a3f6874d6f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -395,7 +395,7 @@ impl FixtureBuilder { pub fn to_block_constant_data(self) -> BlockConstantData { BlockConstantData { last_archive: self.archive_tree, - last_l1_to_l2: self.start_snapshots.l1_to_l2_message_tree, + new_l1_to_l2: self.start_snapshots.l1_to_l2_message_tree, vk_tree_root: self.vk_tree_root, protocol_contract_tree_root: self.protocol_contract_tree_root, global_variables: self.global_variables, diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_public_cross_chain.test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_public_cross_chain.test.ts index 250881c450b6..900baf6c3410 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_public_cross_chain.test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_proof_public_cross_chain.test.ts @@ -1,4 +1,4 @@ -import { Fr, type Logger, generateClaimSecret, retryUntil } from '@aztec/aztec.js'; +import { Fr, type Logger, TxStatus, generateClaimSecret, retryUntil } from '@aztec/aztec.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { TestContract } from '@aztec/noir-test-contracts.js/Test'; @@ -77,6 +77,18 @@ describe('e2e_epochs/epochs_proof_public_cross_chain', () => { const provenBlockNumber = await context.aztecNode.getProvenBlockNumber(); expect(provenBlockNumber).toBeGreaterThanOrEqual(txReceipt.blockNumber!); + // Should not be able to consume the message again. + const failedReceipt = await testContract.methods + .consume_message_from_arbitrary_sender_public( + message.content, + secret, + EthAddress.fromString(context.deployL1ContractsValues.l1Client.account.address), + globalLeafIndex.toBigInt(), + ) + .send({ from: context.accounts[0] }) + .wait({ dontThrowOnRevert: true }); + expect(failedReceipt.status).toBe(TxStatus.APP_LOGIC_REVERTED); + logger.info(`Test succeeded`); }); }); diff --git a/yarn-project/noir-protocol-circuits-types/src/conversion/server.ts b/yarn-project/noir-protocol-circuits-types/src/conversion/server.ts index 737620073ee6..4b608458ef39 100644 --- a/yarn-project/noir-protocol-circuits-types/src/conversion/server.ts +++ b/yarn-project/noir-protocol-circuits-types/src/conversion/server.ts @@ -370,7 +370,7 @@ function mapPublicDataHintToNoir(hint: PublicDataHint): PublicDataHintNoir { function mapBlockConstantDataToNoir(constants: BlockConstantData): BlockConstantDataNoir { return { last_archive: mapAppendOnlyTreeSnapshotToNoir(constants.lastArchive), - last_l1_to_l2: mapAppendOnlyTreeSnapshotToNoir(constants.lastL1ToL2), + new_l1_to_l2: mapAppendOnlyTreeSnapshotToNoir(constants.newL1ToL2), vk_tree_root: mapFieldToNoir(constants.vkTreeRoot), protocol_contract_tree_root: mapFieldToNoir(constants.protocolContractTreeRoot), global_variables: mapGlobalVariablesToNoir(constants.globalVariables), @@ -380,7 +380,7 @@ function mapBlockConstantDataToNoir(constants: BlockConstantData): BlockConstant function mapBlockConstantDataFromNoir(constants: BlockConstantDataNoir) { return new BlockConstantData( mapAppendOnlyTreeSnapshotFromNoir(constants.last_archive), - mapAppendOnlyTreeSnapshotFromNoir(constants.last_l1_to_l2), + mapAppendOnlyTreeSnapshotFromNoir(constants.new_l1_to_l2), mapFieldFromNoir(constants.vk_tree_root), mapFieldFromNoir(constants.protocol_contract_tree_root), mapGlobalVariablesFromNoir(constants.global_variables), diff --git a/yarn-project/prover-client/src/block-factory/light.test.ts b/yarn-project/prover-client/src/block-factory/light.test.ts index d5c372b30106..0328c7257964 100644 --- a/yarn-project/prover-client/src/block-factory/light.test.ts +++ b/yarn-project/prover-client/src/block-factory/light.test.ts @@ -237,25 +237,26 @@ describe('LightBlockBuilder', () => { } const l1ToL2Snapshot = await getL1ToL2Snapshot(l1ToL2Messages); - const rollupOutputs = await getPrivateBaseRollupOutputs(txs, l1ToL2Snapshot.messageTreeSnapshot); - const previousRollups = await getTopMerges!(rollupOutputs); const parityOutput = await getParityOutput(l1ToL2Messages); + const newL1ToL2TreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, expectsFork); + const rollupOutputs = await getPrivateBaseRollupOutputs(txs, newL1ToL2TreeSnapshot); + const previousRollups = await getTopMerges!(rollupOutputs); const { startBlobAccumulator, blobData } = await getBlobData(txs); const rootOutput = await getBlockRootOutput( previousRollups, parityOutput, l1ToL2Snapshot, + newL1ToL2TreeSnapshot, startBlobAccumulator, blobData, ); - const messageTreeSnapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, expectsFork); const partialState = new PartialStateReference( await getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE, expectsFork), await getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE, expectsFork), await getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE, expectsFork), ); - const endState = new StateReference(messageTreeSnapshot, partialState); + const endState = new StateReference(newL1ToL2TreeSnapshot, partialState); const expectedHeader = buildHeaderFromCircuitOutputs( previousRollups, @@ -289,7 +290,7 @@ describe('LightBlockBuilder', () => { return { messageTreeSnapshot, l1ToL2MessageSubtreeSiblingPath, l1ToL2Messages }; }; - const getPrivateBaseRollupOutputs = async (txs: ProcessedTx[], l1ToL2Snapshot: AppendOnlyTreeSnapshot) => { + const getPrivateBaseRollupOutputs = async (txs: ProcessedTx[], newL1ToL2Snapshot: AppendOnlyTreeSnapshot) => { const rollupOutputs = []; const spongeBlobState = SpongeBlob.init(toNumBlobFields(txs)); for (const tx of txs) { @@ -302,7 +303,7 @@ describe('LightBlockBuilder', () => { const hints = await insertSideEffectsAndBuildBaseRollupHints( tx, globalVariables, - l1ToL2Snapshot, + newL1ToL2Snapshot, expectsFork, spongeBlobState, ); @@ -364,11 +365,12 @@ describe('LightBlockBuilder', () => { const getBlockRootOutput = async ( previousRollups: BaseOrMergeRollupPublicInputs[], parityOutput: ParityPublicInputs, - l1ToL2Snapshot: { + lastL1ToL2Snapshot: { l1ToL2Messages: Tuple; l1ToL2MessageSubtreeSiblingPath: Tuple; messageTreeSnapshot: AppendOnlyTreeSnapshot; }, + newL1ToL2Snapshot: AppendOnlyTreeSnapshot, startBlobAccumulator: BatchedBlobAccumulator, blobData: BlockRootRollupBlobData, ) => { @@ -391,7 +393,7 @@ describe('LightBlockBuilder', () => { const data = BlockRootRollupData.from({ l1ToL2Roots: rootParityInput, - l1ToL2MessageSubtreeSiblingPath: l1ToL2Snapshot.l1ToL2MessageSubtreeSiblingPath, + l1ToL2MessageSubtreeSiblingPath: lastL1ToL2Snapshot.l1ToL2MessageSubtreeSiblingPath, previousArchiveSiblingPath, newArchiveSiblingPath, previousBlockHeader, @@ -403,7 +405,7 @@ describe('LightBlockBuilder', () => { if (previousRollupData.length === 0) { const constants = BlockConstantData.from({ lastArchive: startArchiveSnapshot, - lastL1ToL2: l1ToL2Snapshot.messageTreeSnapshot, + newL1ToL2: newL1ToL2Snapshot, globalVariables, vkTreeRoot: getVKTreeRoot(), protocolContractTreeRoot, diff --git a/yarn-project/prover-client/src/block-factory/light.ts b/yarn-project/prover-client/src/block-factory/light.ts index 10f5cb618338..c62fbe0ecd99 100644 --- a/yarn-project/prover-client/src/block-factory/light.ts +++ b/yarn-project/prover-client/src/block-factory/light.ts @@ -103,12 +103,12 @@ export async function buildBlockWithCleanDB( telemetry: TelemetryClient = getTelemetryClient(), ) { const spongeBlobState = SpongeBlob.init(toNumBlobFields(txs)); + const builder = new LightweightBlockFactory(db, telemetry); + await builder.startNewBlock(globalVariables, l1ToL2Messages); const l1ToL2MessageTree = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, db); for (const tx of txs) { await insertSideEffectsAndBuildBaseRollupHints(tx, globalVariables, l1ToL2MessageTree, db, spongeBlobState); } - const builder = new LightweightBlockFactory(db, telemetry); - await builder.startNewBlock(globalVariables, l1ToL2Messages); await builder.addTxs(txs); return await builder.setBlockCompleted(); } diff --git a/yarn-project/prover-client/src/mocks/test_context.ts b/yarn-project/prover-client/src/mocks/test_context.ts index 6b73ddf33314..04a5c6785e63 100644 --- a/yarn-project/prover-client/src/mocks/test_context.ts +++ b/yarn-project/prover-client/src/mocks/test_context.ts @@ -1,19 +1,20 @@ import type { BBProverConfig } from '@aztec/bb-prover'; -import { times, timesParallel } from '@aztec/foundation/collection'; +import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants'; +import { padArrayEnd, times, timesParallel } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import type { Logger } from '@aztec/foundation/log'; import { TestDateProvider } from '@aztec/foundation/timer'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { protocolContractTreeRoot } from '@aztec/protocol-contracts'; import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-juice'; -import { PublicTxSimulationTester, SimpleContractDataSource } from '@aztec/simulator/public/fixtures'; -import { PublicProcessor, PublicProcessorFactory } from '@aztec/simulator/server'; +import { SimpleContractDataSource } from '@aztec/simulator/public/fixtures'; +import { PublicProcessorFactory } from '@aztec/simulator/server'; import { PublicDataWrite } from '@aztec/stdlib/avm'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { EthAddress, type L2Block } from '@aztec/stdlib/block'; import type { ServerCircuitProver } from '@aztec/stdlib/interfaces/server'; import { makeBloatedProcessedTx } from '@aztec/stdlib/testing'; -import { type AppendOnlyTreeSnapshot, PublicDataTreeLeaf } from '@aztec/stdlib/trees'; +import { type AppendOnlyTreeSnapshot, MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees'; import { type BlockHeader, type GlobalVariables, type ProcessedTx, TreeSnapshots, type Tx } from '@aztec/stdlib/tx'; import type { MerkleTreeAdminDatabase } from '@aztec/world-state'; import { NativeWorldStateService } from '@aztec/world-state/native'; @@ -24,6 +25,7 @@ import { promises as fs } from 'fs'; // eslint-disable-next-line import/no-relative-packages import { TestCircuitProver } from '../../../bb-prover/src/test/test_circuit_prover.js'; import { buildBlockWithCleanDB } from '../block-factory/light.js'; +import { getTreeSnapshot } from '../orchestrator/block-building-helpers.js'; import { ProvingOrchestrator } from '../orchestrator/index.js'; import { BrokerCircuitProverFacade } from '../proving_broker/broker_prover_facade.js'; import { TestBroker } from '../test/mock_prover.js'; @@ -35,7 +37,6 @@ export class TestContext { constructor( public worldState: MerkleTreeAdminDatabase, - public publicProcessor: PublicProcessor, public globalVariables: GlobalVariables, public prover: ServerCircuitProver, public broker: TestBroker, @@ -45,7 +46,6 @@ export class TestContext { public feePayer: AztecAddress, initialFeePayerBalance: Fr, public directoriesToCleanup: string[], - public tester: PublicTxSimulationTester, public logger: Logger, ) { this.feePayerBalance = initialFeePayerBalance; @@ -57,10 +57,15 @@ export class TestContext { static async new( logger: Logger, - proverCount = 4, - createProver: (bbConfig: BBProverConfig) => Promise = async (bbConfig: BBProverConfig) => - new TestCircuitProver(await getSimulator(bbConfig, logger)), - blockNumber = 1, + { + proverCount = 4, + createProver = async (bbConfig: BBProverConfig) => new TestCircuitProver(await getSimulator(bbConfig, logger)), + blockNumber = 1, + }: { + proverCount?: number; + createProver?: (bbConfig: BBProverConfig) => Promise; + blockNumber?: number; + } = {}, ) { const directoriesToCleanup: string[] = []; const globalVariables = makeGlobals(blockNumber); @@ -76,13 +81,6 @@ export class TestContext { /*cleanupTmpDir=*/ true, prefilledPublicData, ); - const merkleTrees = await ws.fork(); - - const contractDataSource = new SimpleContractDataSource(); - const tester = new PublicTxSimulationTester(merkleTrees, contractDataSource); - - const processorFactory = new PublicProcessorFactory(contractDataSource, new TestDateProvider()); - const processor = processorFactory.create(merkleTrees, globalVariables, /*skipFeeEnforcement=*/ false); let localProver: ServerCircuitProver; const config = await getEnvironmentConfig(logger); @@ -114,7 +112,6 @@ export class TestContext { return new this( ws, - processor, globalVariables, localProver, broker, @@ -124,7 +121,6 @@ export class TestContext { feePayer, initialFeePayerBalance, directoriesToCleanup, - tester, logger, ); } @@ -159,12 +155,7 @@ export class TestContext { } } - public async makeProcessedTx(opts?: Parameters[0]): Promise; - public async makeProcessedTx(seed?: number): Promise; - public async makeProcessedTx( - seedOrOpts?: Parameters[0] | number, - ): Promise { - const opts = typeof seedOrOpts === 'number' ? { seed: seedOrOpts } : seedOrOpts; + private async makeProcessedTx(opts?: Parameters[0]): Promise { const blockNum = (opts?.globalVariables ?? this.globalVariables).blockNumber; const header = this.getBlockHeader(blockNum - 1); const tx = await makeBloatedProcessedTx({ @@ -186,44 +177,80 @@ export class TestContext { /** Creates a block with the given number of txs and adds it to world-state */ public async makePendingBlock( numTxs: number, - numMsgs: number = 0, + numL1ToL2Messages: number = 0, blockNumOrGlobals: GlobalVariables | number = this.globalVariables, makeProcessedTxOpts: (index: number) => Partial[0]> = () => ({}), ) { const globalVariables = typeof blockNumOrGlobals === 'number' ? makeGlobals(blockNumOrGlobals) : blockNumOrGlobals; const blockNum = globalVariables.blockNumber; const db = await this.worldState.fork(); - const msgs = times(numMsgs, i => new Fr(blockNum * 100 + i)); + const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(blockNum * 100 + i)); + const merkleTrees = await this.worldState.fork(); + await merkleTrees.appendLeaves( + MerkleTreeId.L1_TO_L2_MESSAGE_TREE, + padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), + ); + const newL1ToL2Snapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, merkleTrees); const txs = await timesParallel(numTxs, i => - this.makeProcessedTx({ seed: i + blockNum * 1000, globalVariables, ...makeProcessedTxOpts(i) }), + this.makeProcessedTx({ + seed: i + blockNum * 1000, + globalVariables, + newL1ToL2Snapshot, + ...makeProcessedTxOpts(i), + }), ); await this.setTreeRoots(txs); - const block = await buildBlockWithCleanDB(txs, globalVariables, msgs, db); + const block = await buildBlockWithCleanDB(txs, globalVariables, l1ToL2Messages, db); this.headers.set(blockNum, block.header); - await this.worldState.handleL2BlockAndMessages(block, msgs); - return { block, txs, msgs }; + await this.worldState.handleL2BlockAndMessages(block, l1ToL2Messages); + return { block, txs, l1ToL2Messages }; } - public async processPublicFunctions(txs: Tx[], maxTransactions: number) { - return await this.publicProcessor.process(txs, { maxTransactions }); + public async processPublicFunctions( + txs: Tx[], + { + maxTransactions = txs.length, + numL1ToL2Messages = 0, + contractDataSource, + }: { + maxTransactions?: number; + numL1ToL2Messages?: number; + contractDataSource?: SimpleContractDataSource; + } = {}, + ) { + const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(this.blockNumber * 100 + i)); + const merkleTrees = await this.worldState.fork(); + await merkleTrees.appendLeaves( + MerkleTreeId.L1_TO_L2_MESSAGE_TREE, + padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), + ); + + const processorFactory = new PublicProcessorFactory( + contractDataSource ?? new SimpleContractDataSource(), + new TestDateProvider(), + ); + const publicProcessor = processorFactory.create(merkleTrees, this.globalVariables, /*skipFeeEnforcement=*/ false); + + return await publicProcessor.process(txs, { maxTransactions }); } - public async setTreeRoots(txs: ProcessedTx[]) { + private async setTreeRoots(txs: ProcessedTx[]) { const db = await this.worldState.fork(); for (const tx of txs) { const startStateReference = await db.getStateReference(); await updateExpectedTreesFromTxs(db, [tx]); const endStateReference = await db.getStateReference(); if (tx.avmProvingRequest) { + const l1ToL2MessageTree = tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots.l1ToL2MessageTree; tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots = new TreeSnapshots( - startStateReference.l1ToL2MessageTree, + l1ToL2MessageTree, startStateReference.partial.noteHashTree, startStateReference.partial.nullifierTree, startStateReference.partial.publicDataTree, ); tx.avmProvingRequest.inputs.publicInputs.endTreeSnapshots = new TreeSnapshots( - endStateReference.l1ToL2MessageTree, + l1ToL2MessageTree, endStateReference.partial.noteHashTree, endStateReference.partial.nullifierTree, endStateReference.partial.publicDataTree, diff --git a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts index 5a9d2ede8170..aab48d0a05c3 100644 --- a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts +++ b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts @@ -71,9 +71,7 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan( span: Span, tx: ProcessedTx, globalVariables: GlobalVariables, - // Passing in the snapshot instead of getting it from the db because it might've been updated in the orchestrator - // when base parity proof is being generated. - l1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, + newL1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, db: MerkleTreeWriteOperations, startSpongeBlob: SpongeBlob, ) => { @@ -209,7 +207,7 @@ export const insertSideEffectsAndBuildBaseRollupHints = runInSpan( const constants = BlockConstantData.from({ lastArchive, - lastL1ToL2: l1ToL2MessageTreeSnapshot, + newL1ToL2: newL1ToL2MessageTreeSnapshot, vkTreeRoot: getVKTreeRoot(), protocolContractTreeRoot, globalVariables, diff --git a/yarn-project/prover-client/src/orchestrator/block-proving-state.ts b/yarn-project/prover-client/src/orchestrator/block-proving-state.ts index 6190affd1596..db70d5eb8946 100644 --- a/yarn-project/prover-client/src/orchestrator/block-proving-state.ts +++ b/yarn-project/prover-client/src/orchestrator/block-proving-state.ts @@ -76,7 +76,7 @@ export class BlockProvingState { public readonly newL1ToL2Messages: Fr[], public readonly l1ToL2MessageTreeSnapshot: AppendOnlyTreeSnapshot, private readonly l1ToL2MessageSubtreeSiblingPath: Tuple, - private readonly l1ToL2MessageTreeSnapshotAfterInsertion: AppendOnlyTreeSnapshot, + public readonly l1ToL2MessageTreeSnapshotAfterInsertion: AppendOnlyTreeSnapshot, private readonly lastArchiveSnapshot: AppendOnlyTreeSnapshot, private readonly lastArchiveSiblingPath: Tuple, private readonly newArchiveSiblingPath: Tuple, @@ -223,7 +223,7 @@ export class BlockProvingState { if (this.totalNumTxs === 0) { const constants = BlockConstantData.from({ lastArchive: this.lastArchiveSnapshot, - lastL1ToL2: this.l1ToL2MessageTreeSnapshot, + newL1ToL2: this.l1ToL2MessageTreeSnapshotAfterInsertion, globalVariables: this.globalVariables, vkTreeRoot: getVKTreeRoot(), protocolContractTreeRoot, diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 92898464e7ee..2e9d44ed7c91 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -525,7 +525,7 @@ export class ProvingOrchestrator implements EpochProver { insertSideEffectsAndBuildBaseRollupHints( tx, provingState.globalVariables, - provingState.l1ToL2MessageTreeSnapshot, + provingState.l1ToL2MessageTreeSnapshotAfterInsertion, db, provingState.spongeBlobState, ), diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts index 4d3344a122f5..49249844fdd9 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_errors.test.ts @@ -1,5 +1,4 @@ import { BatchedBlob, Blob, FinalBlobBatchingChallenges } from '@aztec/blob-lib'; -import { timesParallel } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; @@ -27,8 +26,7 @@ describe('prover/orchestrator/errors', () => { describe('errors', () => { it('throws if adding too many transactions', async () => { - const txs = await timesParallel(4, i => context.makeProcessedTx(i + 1)); - await context.setTreeRoots(txs); + const { txs } = await context.makePendingBlock(4); const blobs = await Blob.getBlobsPerBlock(txs.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); @@ -36,7 +34,7 @@ describe('prover/orchestrator/errors', () => { await orchestrator.startNewBlock(context.globalVariables, [], context.getPreviousBlockHeader()); await orchestrator.addTxs(txs); - await expect(async () => await orchestrator.addTxs([await context.makeProcessedTx()])).rejects.toThrow( + await expect(async () => await orchestrator.addTxs(txs)).rejects.toThrow( `Block ${context.blockNumber} has been initialized with transactions.`, ); @@ -56,16 +54,14 @@ describe('prover/orchestrator/errors', () => { }); it('throws if adding a transaction before starting epoch', async () => { - await expect(async () => await orchestrator.addTxs([await context.makeProcessedTx()])).rejects.toThrow( - /Block proving state for 1 not found/, - ); + const { txs } = await context.makePendingBlock(1); + await expect(async () => await orchestrator.addTxs(txs)).rejects.toThrow(/Block proving state for 1 not found/); }); it('throws if adding a transaction before starting block', async () => { orchestrator.startNewEpoch(1, 1, 1, emptyChallenges); - await expect(async () => await orchestrator.addTxs([await context.makeProcessedTx()])).rejects.toThrow( - /Block proving state for 1 not found/, - ); + const { txs } = await context.makePendingBlock(1); + await expect(async () => await orchestrator.addTxs(txs)).rejects.toThrow(/Block proving state for 1 not found/); }); it('throws if completing a block before start', async () => { @@ -80,7 +76,8 @@ describe('prover/orchestrator/errors', () => { await orchestrator.startNewBlock(context.globalVariables, [], context.getPreviousBlockHeader()); orchestrator.cancel(); - await expect(async () => await context.orchestrator.addTxs([await context.makeProcessedTx()])).rejects.toThrow( + const { txs } = await context.makePendingBlock(1); + await expect(async () => await context.orchestrator.addTxs(txs)).rejects.toThrow( 'Invalid proving state when adding a tx', ); }); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts index 6a935b141583..31221ae57a72 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_failures.test.ts @@ -41,12 +41,12 @@ describe('prover/orchestrator/failures', () => { orchestrator.startNewEpoch(1, 1, 3, finalBlobChallenges); - for (const { block, txs, msgs } of blocks) { + for (const { block, txs, l1ToL2Messages } of blocks) { // these operations could fail if the target circuit fails before adding all blocks or txs try { await orchestrator.startNewBlock( block.header.globalVariables, - msgs, + l1ToL2Messages, context.getPreviousBlockHeader(block.number), ); let allTxsAdded = true; diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts index 2fc47d1455ad..7ef314585f80 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_mixed_blocks.test.ts @@ -1,9 +1,6 @@ import { BatchedBlob, Blob } from '@aztec/blob-lib'; import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants'; -import { range } from '@aztec/foundation/array'; -import { timesParallel } from '@aztec/foundation/collection'; import { createLogger } from '@aztec/foundation/log'; -import { fr } from '@aztec/stdlib/testing'; import { TestContext } from '../mocks/test_context.js'; @@ -13,10 +10,7 @@ describe('prover/orchestrator/mixed-blocks', () => { let context: TestContext; const runTest = async (numTxs: number) => { - const txs = await timesParallel(numTxs, i => context.makeProcessedTx(i + 1)); - await context.setTreeRoots(txs); - - const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + const { txs, l1ToL2Messages } = await context.makePendingBlock(numTxs, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); const blobs = await Blob.getBlobsPerBlock(txs.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_multi_public_functions.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_multi_public_functions.test.ts index 234bbfb07892..cc65ab5e41e4 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_multi_public_functions.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_multi_public_functions.test.ts @@ -5,7 +5,11 @@ import { createLogger } from '@aztec/foundation/log'; import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { protocolContractTreeRoot } from '@aztec/protocol-contracts'; -import type { TestEnqueuedCall } from '@aztec/simulator/public/fixtures'; +import { + PublicTxSimulationTester, + SimpleContractDataSource, + type TestEnqueuedCall, +} from '@aztec/simulator/public/fixtures'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract'; import { siloNullifier } from '@aztec/stdlib/hash'; @@ -17,6 +21,8 @@ const logger = createLogger('prover-client:test:orchestrator-multi-public-functi describe('prover/orchestrator/public-functions', () => { let context: TestContext; + let tester: PublicTxSimulationTester; + let contractDataSource: SimpleContractDataSource; beforeEach(async () => { context = await TestContext.new(logger); @@ -34,8 +40,12 @@ describe('prover/orchestrator/public-functions', () => { beforeEach(async () => { admin = context.feePayer; // make sure tx sender has sufficient balance + const merkleTrees = await context.worldState.fork(); + contractDataSource = new SimpleContractDataSource(); + tester = new PublicTxSimulationTester(merkleTrees, contractDataSource); + const constructorArgs = [admin, /*name=*/ 'Token', /*symbol=*/ 'TOK', /*decimals=*/ new Fr(18)]; - token = await context.tester.registerAndDeployContract( + token = await tester.registerAndDeployContract( constructorArgs, /*deployer=*/ admin, TokenContractArtifact, @@ -48,7 +58,7 @@ describe('prover/orchestrator/public-functions', () => { token.address.toField(), ); - constructorTx = await context.tester.createTx( + constructorTx = await tester.createTx( /*sender=*/ admin, /*setupCalls=*/ [], /*appCalls=*/ [ @@ -92,7 +102,10 @@ describe('prover/orchestrator/public-functions', () => { await tx.recomputeHash(); } - const [processed, failed] = await context.processPublicFunctions(txs, numTransactions); + const [processed, failed] = await context.processPublicFunctions(txs, { + maxTransactions: numTransactions, + contractDataSource, + }); expect(processed.length).toBe(numTransactions); expect(failed.length).toBe(0); @@ -136,7 +149,7 @@ describe('prover/orchestrator/public-functions', () => { const appCalls = Array.from({ length: numberOfRevertiblePublicCallRequests }, (_, i) => createMintCall(/*seed=*/ appCallSeed(i)), ); - return await context.tester.createTx( + return await tester.createTx( /*sender=*/ admin, /*setupCalls=*/ setupCalls, /*appCalls=*/ appCalls, diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts index fe21817cc597..6a9decdd84a6 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_public_functions.test.ts @@ -39,7 +39,7 @@ describe('prover/orchestrator/public-functions', () => { // Since this TX is mocked/garbage, it will revert because it calls a non-existent contract, // but it reverts in app logic so it can still be included. - const [processed, _] = await context.processPublicFunctions([tx], 1); + const [processed, _] = await context.processPublicFunctions([tx]); const blobs = await Blob.getBlobsPerBlock(processed.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); @@ -66,7 +66,7 @@ describe('prover/orchestrator/public-functions', () => { tx.data.constants.vkTreeRoot = getVKTreeRoot(); tx.data.constants.protocolContractTreeRoot = protocolContractTreeRoot; - const [processed, _] = await context.processPublicFunctions([tx], 1); + const [processed, _] = await context.processPublicFunctions([tx]); const blobs = await Blob.getBlobsPerBlock(processed.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); context.orchestrator.startNewEpoch(1, 1, 1, finalBlobChallenges); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts index 3b3e6a574d48..da7a8d312ff4 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_single_blocks.test.ts @@ -1,9 +1,6 @@ import { BatchedBlob, Blob } from '@aztec/blob-lib'; import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants'; -import { range } from '@aztec/foundation/array'; -import { timesParallel } from '@aztec/foundation/collection'; import { createLogger } from '@aztec/foundation/log'; -import { fr } from '@aztec/stdlib/testing'; import { TestContext } from '../mocks/test_context.js'; @@ -31,8 +28,7 @@ describe('prover/orchestrator/blocks', () => { }); it('builds a block with 1 transaction', async () => { - const txs = [await context.makeProcessedTx(1)]; - await context.setTreeRoots(txs); + const { txs } = await context.makePendingBlock(1); const blobFields = txs.map(tx => tx.txEffect.toBlobFields()).flat(); const blobs = await Blob.getBlobsPerBlock(blobFields); @@ -50,9 +46,7 @@ describe('prover/orchestrator/blocks', () => { }); it('builds a block concurrently with transaction simulation', async () => { - const txs = await timesParallel(4, i => context.makeProcessedTx(i + 1)); - await context.setTreeRoots(txs); - const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); + const { txs, l1ToL2Messages } = await context.makePendingBlock(4, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); const blobFields = txs.map(tx => tx.txEffect.toBlobFields()).flat(); const blobs = await Blob.getBlobsPerBlock(blobFields); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_workflow.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_workflow.test.ts index d1fc74249743..c1a352bb5a68 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_workflow.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_workflow.test.ts @@ -35,7 +35,10 @@ describe('prover/orchestrator', () => { beforeEach(async () => { mockProver = mock(); - context = await TestContext.new(logger, 4, () => Promise.resolve(mockProver)); + context = await TestContext.new(logger, { + proverCount: 4, + createProver: () => Promise.resolve(mockProver), + }); ({ orchestrator, globalVariables } = context); previousBlockHeader = context.getPreviousBlockHeader(); }); @@ -108,12 +111,11 @@ describe('prover/orchestrator', () => { }); it('waits for block to be completed before enqueueing block root proof', async () => { - const txs = await Promise.all([context.makeProcessedTx(1), context.makeProcessedTx(2)]); + const { txs } = await context.makePendingBlock(2); const blobs = await Blob.getBlobsPerBlock(txs.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); orchestrator.startNewEpoch(1, 1, 1, finalBlobChallenges); await orchestrator.startNewBlock(globalVariables, [], previousBlockHeader); - await context.setTreeRoots(txs); await orchestrator.addTxs(txs); // wait for the block root proof to try to be enqueued @@ -128,7 +130,7 @@ describe('prover/orchestrator', () => { it('can start tube proofs before adding processed txs', async () => { const getTubeSpy = jest.spyOn(prover, 'getTubeProof'); - const processedTxs = await Promise.all([context.makeProcessedTx(1), context.makeProcessedTx(2)]); + const { txs: processedTxs } = await context.makePendingBlock(2); const blobs = await Blob.getBlobsPerBlock(processedTxs.map(tx => tx.txEffect.toBlobFields()).flat()); const finalBlobChallenges = await BatchedBlob.precomputeBatchedBlobChallenges(blobs); orchestrator.startNewEpoch(1, 1, 1, finalBlobChallenges); @@ -145,7 +147,6 @@ describe('prover/orchestrator', () => { getTubeSpy.mockReset(); await orchestrator.startNewBlock(globalVariables, [], previousBlockHeader); - await context.setTreeRoots(processedTxs); await orchestrator.addTxs(processedTxs); await orchestrator.setBlockCompleted(context.blockNumber); const result = await orchestrator.finalizeEpoch(); diff --git a/yarn-project/prover-client/src/test/bb_prover_full_rollup.test.ts b/yarn-project/prover-client/src/test/bb_prover_full_rollup.test.ts index 94d50052de7a..a02497608576 100644 --- a/yarn-project/prover-client/src/test/bb_prover_full_rollup.test.ts +++ b/yarn-project/prover-client/src/test/bb_prover_full_rollup.test.ts @@ -31,7 +31,10 @@ describe('prover/bb_prover/full-rollup', () => { return prover; }; log = createLogger('prover-client:test:bb-prover-full-rollup'); - context = await TestContext.new(log, 1, FAKE_PROOFS ? undefined : buildProver); + context = await TestContext.new(log, { + proverCount: 1, + createProver: FAKE_PROOFS ? undefined : buildProver, + }); previousBlockHeader = context.getPreviousBlockHeader(); }); @@ -61,7 +64,7 @@ describe('prover/bb_prover/full-rollup', () => { }); log.info(`Processing public functions`); - const [processed, failed] = await context.processPublicFunctions(txs, nonEmptyTxs); + const [processed, failed] = await context.processPublicFunctions(txs); expect(processed.length).toBe(nonEmptyTxs); expect(failed.length).toBe(0); processedTxs[blockNum] = processed; @@ -129,7 +132,7 @@ describe('prover/bb_prover/full-rollup', () => { Fr.random, ); - const [processed, failed] = await context.processPublicFunctions(txs, numTransactions); + const [processed, failed] = await context.processPublicFunctions(txs); expect(processed.length).toBe(numTransactions); expect(failed.length).toBe(0); diff --git a/yarn-project/prover-client/src/test/bb_prover_parity.test.ts b/yarn-project/prover-client/src/test/bb_prover_parity.test.ts index 427f74cc8ad8..dda2fea14d92 100644 --- a/yarn-project/prover-client/src/test/bb_prover_parity.test.ts +++ b/yarn-project/prover-client/src/test/bb_prover_parity.test.ts @@ -31,7 +31,10 @@ describe('prover/bb_prover/parity', () => { bbProver = await BBNativeRollupProver.new(bbConfig); return bbProver; }; - context = await TestContext.new(logger, 1, FAKE_PROOFS ? undefined : buildProver); + context = await TestContext.new(logger, { + proverCount: 1, + createProver: FAKE_PROOFS ? undefined : buildProver, + }); }); afterAll(async () => { diff --git a/yarn-project/stdlib/src/rollup/block_constant_data.ts b/yarn-project/stdlib/src/rollup/block_constant_data.ts index 75f461977e61..c275ef9d416e 100644 --- a/yarn-project/stdlib/src/rollup/block_constant_data.ts +++ b/yarn-project/stdlib/src/rollup/block_constant_data.ts @@ -12,8 +12,8 @@ export class BlockConstantData { constructor( /** Archive tree snapshot at the very beginning of the entire rollup. */ public lastArchive: AppendOnlyTreeSnapshot, - /** L1 to L2 message tree snapshot at the very beginning of the entire rollup. */ - public lastL1ToL2: AppendOnlyTreeSnapshot, + /** L1 to L2 message tree snapshot after this block lands. */ + public newL1ToL2: AppendOnlyTreeSnapshot, /** Root of the verification key tree. */ public vkTreeRoot: Fr, /** Root of the protocol contract tree. */ @@ -40,7 +40,7 @@ export class BlockConstantData { static getFields(fields: FieldsOf) { return [ fields.lastArchive, - fields.lastL1ToL2, + fields.newL1ToL2, fields.vkTreeRoot, fields.protocolContractTreeRoot, fields.globalVariables, diff --git a/yarn-project/stdlib/src/tests/factories.ts b/yarn-project/stdlib/src/tests/factories.ts index 44381a47131b..cb427836633d 100644 --- a/yarn-project/stdlib/src/tests/factories.ts +++ b/yarn-project/stdlib/src/tests/factories.ts @@ -1607,6 +1607,7 @@ export async function makeBloatedProcessedTx({ vkTreeRoot = Fr.ZERO, protocolContractTreeRoot = Fr.ZERO, globalVariables = GlobalVariables.empty(), + newL1ToL2Snapshot = AppendOnlyTreeSnapshot.empty(), feePayer, feePaymentPublicDataWrite, privateOnly = false, @@ -1619,6 +1620,7 @@ export async function makeBloatedProcessedTx({ gasSettings?: GasSettings; vkTreeRoot?: Fr; globalVariables?: GlobalVariables; + newL1ToL2Snapshot?: AppendOnlyTreeSnapshot; protocolContractTreeRoot?: Fr; feePayer?: AztecAddress; feePaymentPublicDataWrite?: PublicDataWrite; @@ -1672,6 +1674,9 @@ export async function makeBloatedProcessedTx({ // Create avm output. const avmOutput = AvmCircuitPublicInputs.empty(); + // Assign data from hints. + avmOutput.startTreeSnapshots.l1ToL2MessageTree = newL1ToL2Snapshot; + avmOutput.endTreeSnapshots.l1ToL2MessageTree = newL1ToL2Snapshot; // Assign data from private. avmOutput.globalVariables = globalVariables; avmOutput.startGasUsed = tx.data.gasUsed; @@ -1715,6 +1720,7 @@ export async function makeBloatedProcessedTx({ avmOutput.gasSettings = gasSettings; const avmCircuitInputs = await makeAvmCircuitInputs(seed + 0x3000, { publicInputs: avmOutput }); + avmCircuitInputs.hints.startingTreeRoots.l1ToL2MessageTree = newL1ToL2Snapshot; const gasUsed = { totalGas: Gas.empty(), diff --git a/yarn-project/stdlib/src/tx/tree_snapshots.ts b/yarn-project/stdlib/src/tx/tree_snapshots.ts index 5002080d018c..ab7f99e35784 100644 --- a/yarn-project/stdlib/src/tx/tree_snapshots.ts +++ b/yarn-project/stdlib/src/tx/tree_snapshots.ts @@ -12,10 +12,10 @@ import { AppendOnlyTreeSnapshot } from '../trees/append_only_tree_snapshot.js'; */ export class TreeSnapshots { constructor( - public readonly l1ToL2MessageTree: AppendOnlyTreeSnapshot, - public readonly noteHashTree: AppendOnlyTreeSnapshot, - public readonly nullifierTree: AppendOnlyTreeSnapshot, - public readonly publicDataTree: AppendOnlyTreeSnapshot, + public l1ToL2MessageTree: AppendOnlyTreeSnapshot, + public noteHashTree: AppendOnlyTreeSnapshot, + public nullifierTree: AppendOnlyTreeSnapshot, + public publicDataTree: AppendOnlyTreeSnapshot, ) {} static get schema() {