@aztec/prover-client 3.0.0-canary.a9708bd → 3.0.0-devnet.20251212

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dest/block-factory/index.d.ts +1 -1
  2. package/dest/block-factory/light.d.ts +5 -3
  3. package/dest/block-factory/light.d.ts.map +1 -1
  4. package/dest/block-factory/light.js +32 -11
  5. package/dest/config.d.ts +1 -1
  6. package/dest/config.js +1 -1
  7. package/dest/index.d.ts +1 -1
  8. package/dest/light/lightweight_checkpoint_builder.d.ts +29 -0
  9. package/dest/light/lightweight_checkpoint_builder.d.ts.map +1 -0
  10. package/dest/light/lightweight_checkpoint_builder.js +108 -0
  11. package/dest/mocks/fixtures.d.ts +5 -5
  12. package/dest/mocks/fixtures.d.ts.map +1 -1
  13. package/dest/mocks/fixtures.js +33 -15
  14. package/dest/mocks/test_context.d.ts +37 -33
  15. package/dest/mocks/test_context.d.ts.map +1 -1
  16. package/dest/mocks/test_context.js +124 -82
  17. package/dest/orchestrator/block-building-helpers.d.ts +35 -35
  18. package/dest/orchestrator/block-building-helpers.d.ts.map +1 -1
  19. package/dest/orchestrator/block-building-helpers.js +151 -187
  20. package/dest/orchestrator/block-proving-state.d.ts +68 -55
  21. package/dest/orchestrator/block-proving-state.d.ts.map +1 -1
  22. package/dest/orchestrator/block-proving-state.js +273 -185
  23. package/dest/orchestrator/checkpoint-proving-state.d.ts +63 -0
  24. package/dest/orchestrator/checkpoint-proving-state.d.ts.map +1 -0
  25. package/dest/orchestrator/checkpoint-proving-state.js +210 -0
  26. package/dest/orchestrator/epoch-proving-state.d.ts +38 -31
  27. package/dest/orchestrator/epoch-proving-state.d.ts.map +1 -1
  28. package/dest/orchestrator/epoch-proving-state.js +128 -84
  29. package/dest/orchestrator/index.d.ts +1 -1
  30. package/dest/orchestrator/orchestrator.d.ts +33 -32
  31. package/dest/orchestrator/orchestrator.d.ts.map +1 -1
  32. package/dest/orchestrator/orchestrator.js +369 -243
  33. package/dest/orchestrator/orchestrator_metrics.d.ts +1 -1
  34. package/dest/orchestrator/orchestrator_metrics.d.ts.map +1 -1
  35. package/dest/orchestrator/tx-proving-state.d.ts +12 -10
  36. package/dest/orchestrator/tx-proving-state.d.ts.map +1 -1
  37. package/dest/orchestrator/tx-proving-state.js +23 -29
  38. package/dest/prover-client/factory.d.ts +1 -1
  39. package/dest/prover-client/index.d.ts +1 -1
  40. package/dest/prover-client/prover-client.d.ts +1 -1
  41. package/dest/prover-client/prover-client.d.ts.map +1 -1
  42. package/dest/prover-client/server-epoch-prover.d.ts +13 -11
  43. package/dest/prover-client/server-epoch-prover.d.ts.map +1 -1
  44. package/dest/prover-client/server-epoch-prover.js +9 -9
  45. package/dest/proving_broker/broker_prover_facade.d.ts +23 -18
  46. package/dest/proving_broker/broker_prover_facade.d.ts.map +1 -1
  47. package/dest/proving_broker/broker_prover_facade.js +41 -25
  48. package/dest/proving_broker/config.d.ts +18 -14
  49. package/dest/proving_broker/config.d.ts.map +1 -1
  50. package/dest/proving_broker/config.js +13 -7
  51. package/dest/proving_broker/factory.d.ts +1 -1
  52. package/dest/proving_broker/factory.js +1 -1
  53. package/dest/proving_broker/fixtures.d.ts +3 -2
  54. package/dest/proving_broker/fixtures.d.ts.map +1 -1
  55. package/dest/proving_broker/fixtures.js +3 -2
  56. package/dest/proving_broker/index.d.ts +1 -1
  57. package/dest/proving_broker/proof_store/factory.d.ts +2 -2
  58. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts +1 -1
  59. package/dest/proving_broker/proof_store/gcs_proof_store.d.ts.map +1 -1
  60. package/dest/proving_broker/proof_store/index.d.ts +2 -1
  61. package/dest/proving_broker/proof_store/index.d.ts.map +1 -1
  62. package/dest/proving_broker/proof_store/index.js +1 -0
  63. package/dest/proving_broker/proof_store/inline_proof_store.d.ts +1 -1
  64. package/dest/proving_broker/proof_store/inline_proof_store.d.ts.map +1 -1
  65. package/dest/proving_broker/proof_store/proof_store.d.ts +1 -1
  66. package/dest/proving_broker/proving_agent.d.ts +1 -1
  67. package/dest/proving_broker/proving_agent.d.ts.map +1 -1
  68. package/dest/proving_broker/proving_agent_instrumentation.d.ts +1 -1
  69. package/dest/proving_broker/proving_agent_instrumentation.d.ts.map +1 -1
  70. package/dest/proving_broker/proving_broker.d.ts +2 -2
  71. package/dest/proving_broker/proving_broker.d.ts.map +1 -1
  72. package/dest/proving_broker/proving_broker.js +31 -19
  73. package/dest/proving_broker/proving_broker_database/memory.d.ts +3 -2
  74. package/dest/proving_broker/proving_broker_database/memory.d.ts.map +1 -1
  75. package/dest/proving_broker/proving_broker_database/persisted.d.ts +3 -2
  76. package/dest/proving_broker/proving_broker_database/persisted.d.ts.map +1 -1
  77. package/dest/proving_broker/proving_broker_database/persisted.js +8 -7
  78. package/dest/proving_broker/proving_broker_database.d.ts +3 -2
  79. package/dest/proving_broker/proving_broker_database.d.ts.map +1 -1
  80. package/dest/proving_broker/proving_broker_instrumentation.d.ts +1 -1
  81. package/dest/proving_broker/proving_broker_instrumentation.d.ts.map +1 -1
  82. package/dest/proving_broker/proving_job_controller.d.ts +3 -2
  83. package/dest/proving_broker/proving_job_controller.d.ts.map +1 -1
  84. package/dest/proving_broker/proving_job_controller.js +39 -19
  85. package/dest/proving_broker/rpc.d.ts +4 -4
  86. package/dest/test/mock_proof_store.d.ts +3 -3
  87. package/dest/test/mock_proof_store.d.ts.map +1 -1
  88. package/dest/test/mock_prover.d.ts +23 -19
  89. package/dest/test/mock_prover.d.ts.map +1 -1
  90. package/dest/test/mock_prover.js +35 -20
  91. package/package.json +19 -19
  92. package/src/block-factory/light.ts +40 -17
  93. package/src/config.ts +1 -1
  94. package/src/light/lightweight_checkpoint_builder.ts +144 -0
  95. package/src/mocks/fixtures.ts +41 -36
  96. package/src/mocks/test_context.ts +188 -114
  97. package/src/orchestrator/block-building-helpers.ts +233 -313
  98. package/src/orchestrator/block-proving-state.ts +315 -247
  99. package/src/orchestrator/checkpoint-proving-state.ts +303 -0
  100. package/src/orchestrator/epoch-proving-state.ts +176 -129
  101. package/src/orchestrator/orchestrator.ts +554 -319
  102. package/src/orchestrator/tx-proving-state.ts +48 -55
  103. package/src/prover-client/server-epoch-prover.ts +30 -21
  104. package/src/proving_broker/broker_prover_facade.ts +175 -103
  105. package/src/proving_broker/config.ts +15 -8
  106. package/src/proving_broker/factory.ts +1 -1
  107. package/src/proving_broker/fixtures.ts +8 -3
  108. package/src/proving_broker/proof_store/index.ts +1 -0
  109. package/src/proving_broker/proving_broker.ts +38 -19
  110. package/src/proving_broker/proving_broker_database/memory.ts +2 -1
  111. package/src/proving_broker/proving_broker_database/persisted.ts +10 -9
  112. package/src/proving_broker/proving_broker_database.ts +2 -1
  113. package/src/proving_broker/proving_job_controller.ts +41 -20
  114. package/src/test/mock_prover.ts +142 -60
  115. package/dest/bin/get-proof-inputs.d.ts +0 -2
  116. package/dest/bin/get-proof-inputs.d.ts.map +0 -1
  117. package/dest/bin/get-proof-inputs.js +0 -51
  118. package/src/bin/get-proof-inputs.ts +0 -59
@@ -0,0 +1,144 @@
1
+ import { SpongeBlob, computeBlobsHashFromBlobs, encodeCheckpointEndMarker, getBlobsPerL1Block } from '@aztec/blob-lib';
2
+ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
3
+ import type { CheckpointNumber } from '@aztec/foundation/branded-types';
4
+ import { padArrayEnd } from '@aztec/foundation/collection';
5
+ import { Fr } from '@aztec/foundation/curves/bn254';
6
+ import { createLogger } from '@aztec/foundation/log';
7
+ import { L2BlockNew } from '@aztec/stdlib/block';
8
+ import { Checkpoint } from '@aztec/stdlib/checkpoint';
9
+ import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
10
+ import { computeCheckpointOutHash, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
11
+ import { CheckpointConstantData, CheckpointHeader, computeBlockHeadersHash } from '@aztec/stdlib/rollup';
12
+ import { AppendOnlyTreeSnapshot, MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { ContentCommitment, type GlobalVariables, type ProcessedTx, StateReference } from '@aztec/stdlib/tx';
14
+
15
+ import {
16
+ buildHeaderAndBodyFromTxs,
17
+ getTreeSnapshot,
18
+ insertSideEffects,
19
+ } from '../orchestrator/block-building-helpers.js';
20
+
21
+ /**
22
+ * Builds a checkpoint and its header and the blocks in it from a set of processed tx without running any circuits.
23
+ *
24
+ * It updates the l1-to-l2 message tree when starting a new checkpoint, inserts the side effects to note hash,
25
+ * nullifier, and public data trees, then updates the archive tree when a block is added.
26
+ */
27
+ export class LightweightCheckpointBuilder {
28
+ private readonly logger = createLogger('lightweight-checkpoint-builder');
29
+ private lastArchives: AppendOnlyTreeSnapshot[] = [];
30
+ private spongeBlob: SpongeBlob;
31
+ private blocks: L2BlockNew[] = [];
32
+ private blobFields: Fr[] = [];
33
+
34
+ constructor(
35
+ private checkpointNumber: CheckpointNumber,
36
+ private constants: CheckpointConstantData,
37
+ private l1ToL2Messages: Fr[],
38
+ private db: MerkleTreeWriteOperations,
39
+ ) {
40
+ this.spongeBlob = SpongeBlob.init();
41
+ this.logger.debug('Starting new checkpoint', { constants: constants.toInspect(), l1ToL2Messages });
42
+ }
43
+
44
+ static async startNewCheckpoint(
45
+ checkpointNumber: CheckpointNumber,
46
+ constants: CheckpointConstantData,
47
+ l1ToL2Messages: Fr[],
48
+ db: MerkleTreeWriteOperations,
49
+ ): Promise<LightweightCheckpointBuilder> {
50
+ // Insert l1-to-l2 messages into the tree.
51
+ await db.appendLeaves(
52
+ MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
53
+ padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
54
+ );
55
+
56
+ return new LightweightCheckpointBuilder(checkpointNumber, constants, l1ToL2Messages, db);
57
+ }
58
+
59
+ async addBlock(globalVariables: GlobalVariables, endState: StateReference, txs: ProcessedTx[]): Promise<L2BlockNew> {
60
+ const isFirstBlock = this.blocks.length === 0;
61
+ if (isFirstBlock) {
62
+ this.lastArchives.push(await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db));
63
+ }
64
+
65
+ const lastArchive = this.lastArchives.at(-1)!;
66
+
67
+ for (const tx of txs) {
68
+ await insertSideEffects(tx, this.db);
69
+ }
70
+
71
+ const { header, body, blockBlobFields } = await buildHeaderAndBodyFromTxs(
72
+ txs,
73
+ lastArchive,
74
+ endState,
75
+ globalVariables,
76
+ this.spongeBlob,
77
+ isFirstBlock,
78
+ );
79
+
80
+ await this.db.updateArchive(header);
81
+ const newArchive = await getTreeSnapshot(MerkleTreeId.ARCHIVE, this.db);
82
+ this.lastArchives.push(newArchive);
83
+
84
+ const indexWithinCheckpoint = this.blocks.length;
85
+ const block = new L2BlockNew(newArchive, header, body, this.checkpointNumber, indexWithinCheckpoint);
86
+ this.blocks.push(block);
87
+
88
+ await this.spongeBlob.absorb(blockBlobFields);
89
+ this.blobFields.push(...blockBlobFields);
90
+
91
+ this.logger.debug(`Built block ${header.getBlockNumber()}`, {
92
+ globalVariables: globalVariables.toInspect(),
93
+ archiveRoot: newArchive.root.toString(),
94
+ stateReference: header.state.toInspect(),
95
+ blockHash: (await block.hash()).toString(),
96
+ txs: block.body.txEffects.map(tx => tx.txHash.toString()),
97
+ });
98
+
99
+ return block;
100
+ }
101
+
102
+ async completeCheckpoint(): Promise<Checkpoint> {
103
+ if (!this.blocks.length) {
104
+ throw new Error('No blocks added to checkpoint.');
105
+ }
106
+
107
+ const numBlobFields = this.blobFields.length + 1; // +1 for the checkpoint end marker.
108
+ const checkpointEndMarker = encodeCheckpointEndMarker({ numBlobFields });
109
+ this.blobFields.push(checkpointEndMarker);
110
+
111
+ const blocks = this.blocks;
112
+ const blockHeadersHash = await computeBlockHeadersHash(blocks.map(block => block.header));
113
+
114
+ const newArchive = this.lastArchives[this.lastArchives.length - 1];
115
+
116
+ const blobs = getBlobsPerL1Block(this.blobFields);
117
+ const blobsHash = computeBlobsHashFromBlobs(blobs);
118
+
119
+ const inHash = computeInHashFromL1ToL2Messages(this.l1ToL2Messages);
120
+
121
+ const outHash = computeCheckpointOutHash(blocks.map(block => block.body.txEffects.map(tx => tx.l2ToL1Msgs)));
122
+
123
+ const constants = this.constants!;
124
+
125
+ // timestamp of a checkpoint is the timestamp of the last block in the checkpoint.
126
+ const timestamp = blocks[blocks.length - 1].timestamp;
127
+
128
+ const totalManaUsed = blocks.reduce((acc, block) => acc.add(block.header.totalManaUsed), Fr.ZERO);
129
+
130
+ const header = CheckpointHeader.from({
131
+ lastArchiveRoot: this.lastArchives[0].root,
132
+ blockHeadersHash,
133
+ contentCommitment: new ContentCommitment(blobsHash, inHash, outHash),
134
+ slotNumber: constants.slotNumber,
135
+ timestamp,
136
+ coinbase: constants.coinbase,
137
+ feeRecipient: constants.feeRecipient,
138
+ gasFees: constants.gasFees,
139
+ totalManaUsed,
140
+ });
141
+
142
+ return new Checkpoint(newArchive, header, blocks, this.checkpointNumber);
143
+ }
144
+ }
@@ -1,16 +1,16 @@
1
- import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_TREE_HEIGHT } from '@aztec/constants';
2
- import { padArrayEnd } from '@aztec/foundation/collection';
3
- import { randomBytes } from '@aztec/foundation/crypto';
1
+ import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
2
+ import { randomBytes } from '@aztec/foundation/crypto/random';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
4
  import { EthAddress } from '@aztec/foundation/eth-address';
5
- import { Fr } from '@aztec/foundation/fields';
6
5
  import type { Logger } from '@aztec/foundation/log';
6
+ import type { FieldsOf } from '@aztec/foundation/types';
7
7
  import { fileURLToPath } from '@aztec/foundation/url';
8
+ import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
9
+ import { protocolContractsHash } from '@aztec/protocol-contracts';
8
10
  import { type CircuitSimulator, NativeACVMSimulator, WASMSimulatorWithBlobs } from '@aztec/simulator/server';
9
11
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
10
12
  import { GasFees } from '@aztec/stdlib/gas';
11
- import type { MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
12
- import { MerkleTreeId } from '@aztec/stdlib/trees';
13
- import type { ProcessedTx } from '@aztec/stdlib/tx';
13
+ import { CheckpointConstantData } from '@aztec/stdlib/rollup';
14
14
  import { GlobalVariables } from '@aztec/stdlib/tx';
15
15
 
16
16
  import { promises as fs } from 'fs';
@@ -32,7 +32,7 @@ export const getEnvironmentConfig = async (logger: Logger) => {
32
32
  try {
33
33
  const expectedBBPath = BB_BINARY_PATH
34
34
  ? BB_BINARY_PATH
35
- : `${path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../barretenberg/', BB_RELEASE_DIR)}/bb`;
35
+ : `${path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../barretenberg/', BB_RELEASE_DIR)}/bb-avm`;
36
36
  await fs.access(expectedBBPath, fs.constants.R_OK);
37
37
  const tempWorkingDirectory = `${TEMP_DIR}/${randomBytes(4).toString('hex')}`;
38
38
  const bbWorkingDirectory = BB_WORKING_DIRECTORY ? BB_WORKING_DIRECTORY : `${tempWorkingDirectory}/bb`;
@@ -84,34 +84,39 @@ export async function getSimulator(
84
84
  return new WASMSimulatorWithBlobs();
85
85
  }
86
86
 
87
- // Updates the expectedDb trees based on the new note hashes, contracts, and nullifiers from these txs
88
- export const updateExpectedTreesFromTxs = async (db: MerkleTreeWriteOperations, txs: ProcessedTx[]) => {
89
- await db.appendLeaves(
90
- MerkleTreeId.NOTE_HASH_TREE,
91
- txs.flatMap(tx => padArrayEnd(tx.txEffect.noteHashes, Fr.zero(), MAX_NOTE_HASHES_PER_TX)),
92
- );
93
- await db.batchInsert(
94
- MerkleTreeId.NULLIFIER_TREE,
95
- txs.flatMap(tx => padArrayEnd(tx.txEffect.nullifiers, Fr.zero(), MAX_NULLIFIERS_PER_TX).map(x => x.toBuffer())),
96
- NULLIFIER_TREE_HEIGHT,
97
- );
98
- for (const tx of txs) {
99
- await db.sequentialInsert(
100
- MerkleTreeId.PUBLIC_DATA_TREE,
101
- tx.txEffect.publicDataWrites.map(write => write.toBuffer()),
102
- );
103
- }
87
+ export const makeGlobals = (
88
+ blockNumber: number,
89
+ slotNumber = blockNumber,
90
+ overrides: Partial<FieldsOf<GlobalVariables> & FieldsOf<CheckpointConstantData>> = {},
91
+ ) => {
92
+ const checkpointConstants = makeCheckpointConstants(slotNumber, overrides);
93
+ return GlobalVariables.from({
94
+ chainId: checkpointConstants.chainId,
95
+ version: checkpointConstants.version,
96
+ blockNumber: BlockNumber(blockNumber) /** block number */,
97
+ slotNumber: SlotNumber(slotNumber) /** slot number */,
98
+ timestamp: BigInt(blockNumber * 123) /** block number * 123 as pseudo-timestamp for testing */,
99
+ coinbase: checkpointConstants.coinbase,
100
+ feeRecipient: checkpointConstants.feeRecipient,
101
+ gasFees: checkpointConstants.gasFees,
102
+ ...overrides,
103
+ });
104
104
  };
105
105
 
106
- export const makeGlobals = (blockNumber: number) => {
107
- return new GlobalVariables(
108
- Fr.ZERO,
109
- Fr.ZERO,
110
- blockNumber /** block number */,
111
- new Fr(blockNumber) /** slot number */,
112
- BigInt(blockNumber) /** block number as pseudo-timestamp for testing */,
113
- EthAddress.ZERO,
114
- AztecAddress.ZERO,
115
- GasFees.empty(),
116
- );
106
+ export const makeCheckpointConstants = (
107
+ slotNumber: number,
108
+ overrides: Partial<FieldsOf<CheckpointConstantData>> = {},
109
+ ) => {
110
+ return CheckpointConstantData.from({
111
+ chainId: Fr.ZERO,
112
+ version: Fr.ZERO,
113
+ vkTreeRoot: getVKTreeRoot(),
114
+ protocolContractsHash,
115
+ proverId: Fr.ZERO,
116
+ slotNumber: SlotNumber(slotNumber),
117
+ coinbase: EthAddress.ZERO,
118
+ feeRecipient: AztecAddress.ZERO,
119
+ gasFees: GasFees.empty(),
120
+ ...overrides,
121
+ });
117
122
  };
@@ -1,52 +1,64 @@
1
1
  import type { BBProverConfig } from '@aztec/bb-prover';
2
+ import { TestCircuitProver } from '@aztec/bb-prover';
2
3
  import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
3
- import { padArrayEnd, times, timesParallel } from '@aztec/foundation/collection';
4
- import { Fr } from '@aztec/foundation/fields';
4
+ import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
5
+ import { padArrayEnd, times, timesAsync } from '@aztec/foundation/collection';
6
+ import { Fr } from '@aztec/foundation/curves/bn254';
5
7
  import type { Logger } from '@aztec/foundation/log';
6
- import { TestDateProvider } from '@aztec/foundation/timer';
8
+ import type { FieldsOf } from '@aztec/foundation/types';
7
9
  import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree';
8
- import { protocolContractTreeRoot } from '@aztec/protocol-contracts';
10
+ import { ProtocolContractsList } from '@aztec/protocol-contracts';
9
11
  import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-juice';
10
- import { SimpleContractDataSource } from '@aztec/simulator/public/fixtures';
11
- import { PublicProcessorFactory } from '@aztec/simulator/server';
12
12
  import { PublicDataWrite } from '@aztec/stdlib/avm';
13
13
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
14
- import { EthAddress, type L2Block } from '@aztec/stdlib/block';
15
- import type { ServerCircuitProver } from '@aztec/stdlib/interfaces/server';
16
- import { makeBloatedProcessedTx } from '@aztec/stdlib/testing';
17
- import { type AppendOnlyTreeSnapshot, MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
18
- import { type BlockHeader, type GlobalVariables, type ProcessedTx, TreeSnapshots, type Tx } from '@aztec/stdlib/tx';
14
+ import { EthAddress } from '@aztec/stdlib/block';
15
+ import type { Checkpoint } from '@aztec/stdlib/checkpoint';
16
+ import type { MerkleTreeWriteOperations, ServerCircuitProver } from '@aztec/stdlib/interfaces/server';
17
+ import type { CheckpointConstantData } from '@aztec/stdlib/rollup';
18
+ import { mockProcessedTx } from '@aztec/stdlib/testing';
19
+ import { MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
20
+ import {
21
+ type BlockHeader,
22
+ type GlobalVariables,
23
+ type ProcessedTx,
24
+ StateReference,
25
+ TreeSnapshots,
26
+ } from '@aztec/stdlib/tx';
19
27
  import type { MerkleTreeAdminDatabase } from '@aztec/world-state';
20
28
  import { NativeWorldStateService } from '@aztec/world-state/native';
21
29
 
22
30
  import { promises as fs } from 'fs';
23
31
 
24
- // TODO(#12613) This means of sharing test code is not ideal.
25
- // eslint-disable-next-line import/no-relative-packages
26
- import { TestCircuitProver } from '../../../bb-prover/src/test/test_circuit_prover.js';
27
- import { buildBlockWithCleanDB } from '../block-factory/light.js';
28
- import { getTreeSnapshot } from '../orchestrator/block-building-helpers.js';
32
+ import { LightweightCheckpointBuilder } from '../light/lightweight_checkpoint_builder.js';
33
+ import {
34
+ buildFinalBlobChallenges,
35
+ getTreeSnapshot,
36
+ insertSideEffects,
37
+ } from '../orchestrator/block-building-helpers.js';
38
+ import type { BlockProvingState } from '../orchestrator/block-proving-state.js';
29
39
  import { ProvingOrchestrator } from '../orchestrator/index.js';
30
40
  import { BrokerCircuitProverFacade } from '../proving_broker/broker_prover_facade.js';
31
41
  import { TestBroker } from '../test/mock_prover.js';
32
- import { getEnvironmentConfig, getSimulator, makeGlobals, updateExpectedTreesFromTxs } from './fixtures.js';
42
+ import { getEnvironmentConfig, getSimulator, makeCheckpointConstants, makeGlobals } from './fixtures.js';
33
43
 
34
44
  export class TestContext {
35
45
  private headers: Map<number, BlockHeader> = new Map();
46
+ private checkpoints: Checkpoint[] = [];
47
+ private nextCheckpointIndex = 0;
48
+ private nextBlockNumber = 1;
49
+ private epochNumber = 1;
36
50
  private feePayerBalance: Fr;
37
51
 
38
52
  constructor(
39
53
  public worldState: MerkleTreeAdminDatabase,
40
- public globalVariables: GlobalVariables,
41
54
  public prover: ServerCircuitProver,
42
55
  public broker: TestBroker,
43
56
  public brokerProverFacade: BrokerCircuitProverFacade,
44
57
  public orchestrator: TestProvingOrchestrator,
45
- public blockNumber: number,
46
- public feePayer: AztecAddress,
58
+ private feePayer: AztecAddress,
47
59
  initialFeePayerBalance: Fr,
48
- public directoriesToCleanup: string[],
49
- public logger: Logger,
60
+ private directoriesToCleanup: string[],
61
+ private logger: Logger,
50
62
  ) {
51
63
  this.feePayerBalance = initialFeePayerBalance;
52
64
  }
@@ -60,15 +72,12 @@ export class TestContext {
60
72
  {
61
73
  proverCount = 4,
62
74
  createProver = async (bbConfig: BBProverConfig) => new TestCircuitProver(await getSimulator(bbConfig, logger)),
63
- blockNumber = 1,
64
75
  }: {
65
76
  proverCount?: number;
66
77
  createProver?: (bbConfig: BBProverConfig) => Promise<ServerCircuitProver>;
67
- blockNumber?: number;
68
78
  } = {},
69
79
  ) {
70
80
  const directoriesToCleanup: string[] = [];
71
- const globalVariables = makeGlobals(blockNumber);
72
81
 
73
82
  const feePayer = AztecAddress.fromNumber(42222);
74
83
  const initialFeePayerBalance = new Fr(10n ** 20n);
@@ -112,12 +121,10 @@ export class TestContext {
112
121
 
113
122
  return new this(
114
123
  ws,
115
- globalVariables,
116
124
  localProver,
117
125
  broker,
118
126
  facade,
119
127
  orchestrator,
120
- blockNumber,
121
128
  feePayer,
122
129
  initialFeePayerBalance,
123
130
  directoriesToCleanup,
@@ -129,20 +136,6 @@ export class TestContext {
129
136
  return this.worldState.fork();
130
137
  }
131
138
 
132
- public getBlockHeader(blockNumber: 0): BlockHeader;
133
- public getBlockHeader(blockNumber: number): BlockHeader | undefined;
134
- public getBlockHeader(blockNumber = 0) {
135
- return blockNumber === 0 ? this.worldState.getCommitted().getInitialHeader() : this.headers.get(blockNumber);
136
- }
137
-
138
- public setBlockHeader(header: BlockHeader, blockNumber: number) {
139
- this.headers.set(blockNumber, header);
140
- }
141
-
142
- public getPreviousBlockHeader(currentBlockNumber = this.blockNumber): BlockHeader {
143
- return this.getBlockHeader(currentBlockNumber - 1)!;
144
- }
145
-
146
139
  async cleanup() {
147
140
  await this.brokerProverFacade.stop();
148
141
  await this.broker.stop();
@@ -155,93 +148,172 @@ export class TestContext {
155
148
  }
156
149
  }
157
150
 
158
- private async makeProcessedTx(opts?: Parameters<typeof makeBloatedProcessedTx>[0]): Promise<ProcessedTx> {
159
- const blockNum = (opts?.globalVariables ?? this.globalVariables).blockNumber;
160
- const header = this.getBlockHeader(blockNum - 1);
161
- const tx = await makeBloatedProcessedTx({
162
- header,
163
- vkTreeRoot: getVKTreeRoot(),
164
- protocolContractTreeRoot,
165
- globalVariables: this.globalVariables,
166
- feePayer: this.feePayer,
167
- ...opts,
168
- });
169
- this.feePayerBalance = new Fr(this.feePayerBalance.toBigInt() - tx.txEffect.transactionFee.toBigInt());
170
- if (opts?.privateOnly) {
171
- const feePayerSlot = await computeFeePayerBalanceLeafSlot(this.feePayer);
172
- tx.txEffect.publicDataWrites[0] = new PublicDataWrite(feePayerSlot, this.feePayerBalance);
173
- }
174
- return tx;
151
+ public startNewEpoch() {
152
+ this.checkpoints = [];
153
+ this.nextCheckpointIndex = 0;
154
+ this.epochNumber++;
175
155
  }
176
156
 
177
- /** Creates a block with the given number of txs and adds it to world-state */
178
- public async makePendingBlock(
179
- numTxs: number,
180
- numL1ToL2Messages: number = 0,
181
- blockNumOrGlobals: GlobalVariables | number = this.globalVariables,
182
- makeProcessedTxOpts: (index: number) => Partial<Parameters<typeof makeBloatedProcessedTx>[0]> = () => ({}),
183
- ) {
184
- const globalVariables = typeof blockNumOrGlobals === 'number' ? makeGlobals(blockNumOrGlobals) : blockNumOrGlobals;
185
- const blockNum = globalVariables.blockNumber;
186
- const db = await this.worldState.fork();
187
- const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(blockNum * 100 + i));
188
- const merkleTrees = await this.worldState.fork();
189
- await merkleTrees.appendLeaves(
190
- MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
191
- padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
192
- );
193
- const newL1ToL2Snapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, merkleTrees);
194
- const txs = await timesParallel(numTxs, i =>
195
- this.makeProcessedTx({
196
- seed: i + blockNum * 1000,
197
- globalVariables,
198
- newL1ToL2Snapshot,
199
- ...makeProcessedTxOpts(i),
200
- }),
201
- );
202
- await this.setTreeRoots(txs);
157
+ // Return blob fields of all checkpoints in the epoch.
158
+ public getBlobFields() {
159
+ return this.checkpoints.map(checkpoint => checkpoint.toBlobFields());
160
+ }
203
161
 
204
- const block = await buildBlockWithCleanDB(txs, globalVariables, l1ToL2Messages, db);
205
- this.headers.set(blockNum, block.header);
206
- await this.worldState.handleL2BlockAndMessages(block, l1ToL2Messages);
207
- return { block, txs, l1ToL2Messages };
162
+ public async getFinalBlobChallenges() {
163
+ const blobFields = this.getBlobFields();
164
+ return await buildFinalBlobChallenges(blobFields);
208
165
  }
209
166
 
210
- public async processPublicFunctions(
211
- txs: Tx[],
167
+ public async makeCheckpoint(
168
+ numBlocks: number,
212
169
  {
213
- maxTransactions = txs.length,
170
+ numTxsPerBlock = 0,
214
171
  numL1ToL2Messages = 0,
215
- contractDataSource,
172
+ makeProcessedTxOpts = () => ({}),
173
+ ...constantOpts
216
174
  }: {
217
- maxTransactions?: number;
175
+ numTxsPerBlock?: number | number[];
218
176
  numL1ToL2Messages?: number;
219
- contractDataSource?: SimpleContractDataSource;
220
- } = {},
177
+ makeProcessedTxOpts?: (
178
+ blockGlobalVariables: GlobalVariables,
179
+ txIndex: number,
180
+ ) => Partial<Parameters<typeof mockProcessedTx>[0]>;
181
+ } & Partial<FieldsOf<CheckpointConstantData>> = {},
221
182
  ) {
222
- const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(this.blockNumber * 100 + i));
223
- const merkleTrees = await this.worldState.fork();
224
- await merkleTrees.appendLeaves(
183
+ if (numBlocks === 0) {
184
+ throw new Error(
185
+ 'Cannot make a checkpoint with 0 blocks. Crate an empty block (numTxsPerBlock = 0) if there are no txs.',
186
+ );
187
+ }
188
+
189
+ const checkpointIndex = this.nextCheckpointIndex++;
190
+ const checkpointNumber = CheckpointNumber(checkpointIndex + 1);
191
+ const slotNumber = checkpointNumber * 15; // times an arbitrary number to make it different to the checkpoint number
192
+
193
+ const constants = makeCheckpointConstants(slotNumber, constantOpts);
194
+
195
+ const fork = await this.worldState.fork();
196
+
197
+ // Build l1 to l2 messages.
198
+ const l1ToL2Messages = times(numL1ToL2Messages, i => new Fr(slotNumber * 100 + i));
199
+ await fork.appendLeaves(
225
200
  MerkleTreeId.L1_TO_L2_MESSAGE_TREE,
226
- padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
201
+ padArrayEnd<Fr, number>(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP),
227
202
  );
203
+ const newL1ToL2Snapshot = await getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, fork);
228
204
 
229
- const processorFactory = new PublicProcessorFactory(
230
- contractDataSource ?? new SimpleContractDataSource(),
231
- new TestDateProvider(),
205
+ const startBlockNumber = this.nextBlockNumber;
206
+ const previousBlockHeader = this.getBlockHeader(BlockNumber(startBlockNumber - 1));
207
+
208
+ // Build global variables.
209
+ const blockGlobalVariables = times(numBlocks, i =>
210
+ makeGlobals(startBlockNumber + i, slotNumber, {
211
+ coinbase: constants.coinbase,
212
+ feeRecipient: constants.feeRecipient,
213
+ gasFees: constants.gasFees,
214
+ }),
232
215
  );
233
- const publicProcessor = processorFactory.create(merkleTrees, this.globalVariables, /*skipFeeEnforcement=*/ false);
216
+ this.nextBlockNumber += numBlocks;
234
217
 
235
- return await publicProcessor.process(txs, { maxTransactions });
218
+ // Build txs.
219
+ let totalTxs = 0;
220
+ const blockEndStates: StateReference[] = [];
221
+ const blockTxs = await timesAsync(numBlocks, async blockIndex => {
222
+ const txIndexOffset = totalTxs;
223
+ const numTxs = typeof numTxsPerBlock === 'number' ? numTxsPerBlock : numTxsPerBlock[blockIndex];
224
+ totalTxs += numTxs;
225
+ const txs = await timesAsync(numTxs, txIndex =>
226
+ this.makeProcessedTx({
227
+ seed: (txIndexOffset + txIndex + 1) * 321 + (checkpointIndex + 1) * 123456 + this.epochNumber * 0x99999,
228
+ globalVariables: blockGlobalVariables[blockIndex],
229
+ anchorBlockHeader: previousBlockHeader,
230
+ newL1ToL2Snapshot,
231
+ ...makeProcessedTxOpts(blockGlobalVariables[blockIndex], txIndexOffset + txIndex),
232
+ }),
233
+ );
234
+
235
+ // Insert side effects into the trees.
236
+ const endState = await this.updateTrees(txs, fork);
237
+ blockEndStates.push(endState);
238
+
239
+ return txs;
240
+ });
241
+
242
+ const cleanFork = await this.worldState.fork();
243
+ const builder = await LightweightCheckpointBuilder.startNewCheckpoint(
244
+ checkpointNumber,
245
+ constants,
246
+ l1ToL2Messages,
247
+ cleanFork,
248
+ );
249
+
250
+ // Add tx effects to db and build block headers.
251
+ const blocks = [];
252
+ for (let i = 0; i < numBlocks; i++) {
253
+ const txs = blockTxs[i];
254
+ const state = blockEndStates[i];
255
+
256
+ const block = await builder.addBlock(blockGlobalVariables[i], state, txs);
257
+
258
+ const header = block.header;
259
+ this.headers.set(block.number, header);
260
+
261
+ const blockMsgs = block.indexWithinCheckpoint === 0 ? l1ToL2Messages : [];
262
+ await this.worldState.handleL2BlockAndMessages(block, blockMsgs);
263
+
264
+ blocks.push({ header, txs });
265
+ }
266
+
267
+ const checkpoint = await builder.completeCheckpoint();
268
+ this.checkpoints.push(checkpoint);
269
+
270
+ return {
271
+ constants,
272
+ header: checkpoint.header,
273
+ blocks,
274
+ l1ToL2Messages,
275
+ previousBlockHeader,
276
+ };
236
277
  }
237
278
 
238
- private async setTreeRoots(txs: ProcessedTx[]) {
239
- const db = await this.worldState.fork();
279
+ private async makeProcessedTx(opts: Parameters<typeof mockProcessedTx>[0] = {}): Promise<ProcessedTx> {
280
+ const tx = await mockProcessedTx({
281
+ vkTreeRoot: getVKTreeRoot(),
282
+ protocolContracts: ProtocolContractsList,
283
+ feePayer: this.feePayer,
284
+ ...opts,
285
+ });
286
+
287
+ this.feePayerBalance = new Fr(this.feePayerBalance.toBigInt() - tx.txEffect.transactionFee.toBigInt());
288
+
289
+ const feePayerSlot = await computeFeePayerBalanceLeafSlot(this.feePayer);
290
+ const feePaymentPublicDataWrite = new PublicDataWrite(feePayerSlot, this.feePayerBalance);
291
+ tx.txEffect.publicDataWrites[0] = feePaymentPublicDataWrite;
292
+ if (tx.avmProvingRequest) {
293
+ tx.avmProvingRequest.inputs.publicInputs.accumulatedData.publicDataWrites[0] = feePaymentPublicDataWrite;
294
+ }
295
+
296
+ return tx;
297
+ }
298
+
299
+ private getBlockHeader(blockNumber: BlockNumber): BlockHeader {
300
+ if (Number(blockNumber) > 0 && Number(blockNumber) >= this.nextBlockNumber) {
301
+ throw new Error(`Block header not built for block number ${blockNumber}.`);
302
+ }
303
+ return Number(blockNumber) === 0
304
+ ? this.worldState.getCommitted().getInitialHeader()
305
+ : this.headers.get(Number(blockNumber))!;
306
+ }
307
+
308
+ private async updateTrees(txs: ProcessedTx[], fork: MerkleTreeWriteOperations) {
309
+ let startStateReference = await fork.getStateReference();
310
+ let endStateReference = startStateReference;
240
311
  for (const tx of txs) {
241
- const startStateReference = await db.getStateReference();
242
- await updateExpectedTreesFromTxs(db, [tx]);
243
- const endStateReference = await db.getStateReference();
312
+ await insertSideEffects(tx, fork);
313
+ endStateReference = await fork.getStateReference();
314
+
244
315
  if (tx.avmProvingRequest) {
316
+ // Update the trees in the avm public inputs so that the proof won't fail.
245
317
  const l1ToL2MessageTree = tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots.l1ToL2MessageTree;
246
318
  tx.avmProvingRequest.inputs.publicInputs.startTreeSnapshots = new TreeSnapshots(
247
319
  l1ToL2MessageTree,
@@ -249,6 +321,7 @@ export class TestContext {
249
321
  startStateReference.partial.nullifierTree,
250
322
  startStateReference.partial.publicDataTree,
251
323
  );
324
+
252
325
  tx.avmProvingRequest.inputs.publicInputs.endTreeSnapshots = new TreeSnapshots(
253
326
  l1ToL2MessageTree,
254
327
  endStateReference.partial.noteHashTree,
@@ -256,7 +329,11 @@ export class TestContext {
256
329
  endStateReference.partial.publicDataTree,
257
330
  );
258
331
  }
332
+
333
+ startStateReference = endStateReference;
259
334
  }
335
+
336
+ return endStateReference;
260
337
  }
261
338
  }
262
339
 
@@ -265,12 +342,9 @@ class TestProvingOrchestrator extends ProvingOrchestrator {
265
342
 
266
343
  // Disable this check by default, since it requires seeding world state with the block being built
267
344
  // This is only enabled in some tests with multiple blocks that populate the pending chain via makePendingBlock
268
- protected override verifyBuiltBlockAgainstSyncedState(
269
- l2Block: L2Block,
270
- newArchive: AppendOnlyTreeSnapshot,
271
- ): Promise<void> {
345
+ protected override verifyBuiltBlockAgainstSyncedState(provingState: BlockProvingState): Promise<void> {
272
346
  if (this.isVerifyBuiltBlockAgainstSyncedStateEnabled) {
273
- return super.verifyBuiltBlockAgainstSyncedState(l2Block, newArchive);
347
+ return super.verifyBuiltBlockAgainstSyncedState(provingState);
274
348
  }
275
349
  return Promise.resolve();
276
350
  }