@aztec/txe 0.0.1-commit.1142ef1 → 0.0.1-commit.18ccd8f0

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 (48) hide show
  1. package/dest/constants.d.ts +1 -2
  2. package/dest/constants.d.ts.map +1 -1
  3. package/dest/constants.js +0 -1
  4. package/dest/oracle/interfaces.d.ts +3 -3
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +3 -3
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +6 -6
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +3 -2
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +30 -22
  12. package/dest/rpc_translator.d.ts +16 -10
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +52 -39
  15. package/dest/state_machine/archiver.d.ts +20 -69
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +34 -178
  18. package/dest/state_machine/index.d.ts +1 -1
  19. package/dest/state_machine/index.d.ts.map +1 -1
  20. package/dest/state_machine/index.js +22 -4
  21. package/dest/state_machine/mock_epoch_cache.d.ts +6 -6
  22. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  23. package/dest/state_machine/mock_epoch_cache.js +7 -7
  24. package/dest/state_machine/synchronizer.d.ts +3 -3
  25. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  26. package/dest/txe_session.d.ts +5 -3
  27. package/dest/txe_session.d.ts.map +1 -1
  28. package/dest/txe_session.js +30 -14
  29. package/dest/util/encoding.d.ts +17 -17
  30. package/dest/utils/block_creation.d.ts +4 -4
  31. package/dest/utils/block_creation.d.ts.map +1 -1
  32. package/dest/utils/block_creation.js +16 -4
  33. package/dest/utils/tx_effect_creation.d.ts +2 -3
  34. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  35. package/dest/utils/tx_effect_creation.js +3 -6
  36. package/package.json +16 -16
  37. package/src/constants.ts +0 -1
  38. package/src/oracle/interfaces.ts +2 -2
  39. package/src/oracle/txe_oracle_public_context.ts +6 -8
  40. package/src/oracle/txe_oracle_top_level_context.ts +50 -22
  41. package/src/rpc_translator.ts +56 -49
  42. package/src/state_machine/archiver.ts +35 -234
  43. package/src/state_machine/index.ts +26 -4
  44. package/src/state_machine/mock_epoch_cache.ts +6 -11
  45. package/src/state_machine/synchronizer.ts +2 -2
  46. package/src/txe_session.ts +32 -12
  47. package/src/utils/block_creation.ts +17 -16
  48. package/src/utils/tx_effect_creation.ts +3 -11
@@ -1,216 +1,48 @@
1
- import { ArchiverStoreHelper, KVArchiverDataStore } from '@aztec/archiver';
1
+ import { ArchiverDataSourceBase, ArchiverDataStoreUpdater, KVArchiverDataStore } from '@aztec/archiver';
2
2
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
3
- import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import type { EthAddress } from '@aztec/foundation/eth-address';
6
- import { isDefined } from '@aztec/foundation/types';
7
6
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
8
- import type { AztecAddress } from '@aztec/stdlib/aztec-address';
9
- import {
10
- type CheckpointId,
11
- CommitteeAttestation,
12
- L2Block,
13
- type L2BlockId,
14
- type L2BlockNew,
15
- type L2BlockSource,
16
- type L2TipId,
17
- type L2Tips,
18
- PublishedL2Block,
19
- type ValidateCheckpointResult,
20
- } from '@aztec/stdlib/block';
21
- import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
22
- import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
7
+ import type { CheckpointId, L2BlockId, L2TipId, L2Tips, ValidateCheckpointResult } from '@aztec/stdlib/block';
8
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
23
9
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
24
- import type { BlockHeader } from '@aztec/stdlib/tx';
25
- import type { UInt64 } from '@aztec/stdlib/types';
26
10
 
27
- // We are extending the ArchiverDataStoreHelper here because it provides most of the endpoints needed by the
28
- // node for reading from and writing to state, without needing any of the extra overhead that the Archiver itself
29
- // requires (i.e. an L1 client)
30
- export class TXEArchiver extends ArchiverStoreHelper implements L2BlockSource {
31
- constructor(db: AztecAsyncKVStore) {
32
- super(new KVArchiverDataStore(db, 9999));
33
- }
34
-
35
- public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
36
- if (number === 0) {
37
- return undefined;
38
- }
39
- const publishedBlocks = await this.getPublishedBlocks(number, 1);
40
- if (publishedBlocks.length === 0) {
41
- return undefined;
42
- }
43
- return publishedBlocks[0].block;
44
- }
45
-
46
- public async getBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<L2Block[]> {
47
- const publishedBlocks = await this.getPublishedBlocks(from, limit, proven);
48
- return publishedBlocks.map(x => x.block);
49
- }
50
-
51
- public override async addCheckpoints(
52
- checkpoints: PublishedCheckpoint[],
53
- _result?: ValidateCheckpointResult,
54
- ): Promise<boolean> {
55
- const allBlocks = checkpoints.flatMap(ch => ch.checkpoint.blocks);
56
- const opResults = await Promise.all([this.store.addLogs(allBlocks), this.store.addCheckpoints(checkpoints)]);
57
-
58
- return opResults.every(Boolean);
59
- }
60
-
61
- /**
62
- * Gets the number of the latest L2 block processed by the block source implementation.
63
- * @returns The number of the latest L2 block processed by the block source implementation.
64
- */
65
- public getBlockNumber(): Promise<BlockNumber> {
66
- return this.store.getLatestBlockNumber();
67
- }
68
-
69
- /**
70
- * Gets the number of the latest L2 block proven seen by the block source implementation.
71
- * @returns The number of the latest L2 block proven seen by the block source implementation.
72
- */
73
- public override getProvenBlockNumber(): Promise<BlockNumber> {
74
- return this.store.getProvenBlockNumber();
75
- }
76
-
77
- /**
78
- * Gets a published l2 block. If a negative number is passed, the block returned is the most recent.
79
- * @param number - The block number to return (inclusive).
80
- * @returns The requested L2 block.
81
- */
82
- public async getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
83
- // If the number provided is -ve, then return the latest block.
84
- if (number < 0) {
85
- number = await this.store.getLatestBlockNumber();
86
- }
87
- if (number == 0) {
88
- return undefined;
89
- }
90
- const publishedBlocks = await this.retrievePublishedBlocks(BlockNumber(number), 1);
91
- return publishedBlocks.length === 0 ? undefined : publishedBlocks[0];
92
- }
93
-
94
- getPublishedBlocks(from: BlockNumber, limit: number, proven?: boolean): Promise<PublishedL2Block[]> {
95
- return this.retrievePublishedBlocks(from, limit, proven);
96
- }
97
-
98
- async getL2BlocksNew(from: BlockNumber, limit: number, proven?: boolean): Promise<L2BlockNew[]> {
99
- const blocks = await this.store.getBlocks(from, limit);
11
+ /**
12
+ * TXE Archiver implementation.
13
+ * Provides most of the endpoints needed by the node for reading from and writing to state,
14
+ * without needing any of the extra overhead that the Archiver itself requires (i.e. an L1 client).
15
+ */
16
+ export class TXEArchiver extends ArchiverDataSourceBase {
17
+ private readonly updater = new ArchiverDataStoreUpdater(this.store);
100
18
 
101
- if (proven === true) {
102
- const provenBlockNumber = await this.store.getProvenBlockNumber();
103
- return blocks.filter(b => b.number <= provenBlockNumber);
104
- }
105
- return blocks;
106
- }
107
-
108
- private async retrievePublishedBlocks(
109
- from: BlockNumber,
110
- limit: number,
111
- proven?: boolean,
112
- ): Promise<PublishedL2Block[]> {
113
- const checkpoints = await this.store.getRangeOfCheckpoints(CheckpointNumber(from), limit);
114
- const provenCheckpointNumber = await this.store.getProvenCheckpointNumber();
115
- const blocks = (
116
- await Promise.all(checkpoints.map(ch => this.store.getBlocksForCheckpoint(ch.checkpointNumber)))
117
- ).filter(isDefined);
118
-
119
- const olbBlocks: PublishedL2Block[] = [];
120
- for (let i = 0; i < checkpoints.length; i++) {
121
- const blockForCheckpoint = blocks[i][0];
122
- const checkpoint = checkpoints[i];
123
- if (proven === true && checkpoint.checkpointNumber > provenCheckpointNumber) {
124
- continue;
125
- }
126
- const oldCheckpoint = new Checkpoint(
127
- blockForCheckpoint.archive,
128
- checkpoint.header,
129
- [blockForCheckpoint],
130
- checkpoint.checkpointNumber,
131
- );
132
- const oldBlock = L2Block.fromCheckpoint(oldCheckpoint);
133
- const publishedBlock = new PublishedL2Block(
134
- oldBlock,
135
- checkpoint.l1,
136
- checkpoint.attestations.map(x => CommitteeAttestation.fromBuffer(x)),
137
- );
138
- olbBlocks.push(publishedBlock);
139
- }
140
- return olbBlocks;
141
- }
142
-
143
- /**
144
- * Gets an l2 block. If a negative number is passed, the block returned is the most recent.
145
- * @param number - The block number to return (inclusive).
146
- * @returns The requested L2 block.
147
- */
148
- public getL2Block(number: BlockNumber | 'latest'): Promise<L2Block | undefined> {
149
- return this.getPublishedBlock(number != 'latest' ? number : -1).then(b => b?.block);
150
- }
151
-
152
- /**
153
- * Gets an L2 block (new format).
154
- * @param number - The block number to return.
155
- * @returns The requested L2 block.
156
- */
157
- public getL2BlockNew(number: BlockNumber): Promise<L2BlockNew | undefined> {
158
- if (number === 0) {
159
- return Promise.resolve(undefined);
160
- }
161
- return this.store.getBlock(number);
162
- }
163
-
164
- /**
165
- * Gets an l2 block header.
166
- * @param number - The block number to return or 'latest' for the most recent one.
167
- * @returns The requested L2 block header.
168
- */
169
- public async getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
170
- if (number === 'latest') {
171
- number = await this.store.getLatestBlockNumber();
172
- }
173
- if (number === 0) {
174
- return undefined;
175
- }
176
- const headers = await this.store.getBlockHeaders(BlockNumber(number), 1);
177
- return headers.length === 0 ? undefined : headers[0];
178
- }
179
-
180
- public getBlockRange(from: number, limit: number, _proven?: boolean): Promise<L2Block[]> {
181
- return this.getPublishedBlocks(BlockNumber(from), limit).then(blocks => blocks.map(b => b.block));
182
- }
183
-
184
- public getPublishedCheckpoints(_from: CheckpointNumber, _limit: number): Promise<PublishedCheckpoint[]> {
185
- throw new Error('TXE Archiver does not implement "getPublishedCheckpoints"');
186
- }
187
-
188
- public getCheckpointByArchive(_archive: Fr): Promise<Checkpoint | undefined> {
189
- throw new Error('TXE Archiver does not implement "getCheckpointByArchive"');
19
+ constructor(db: AztecAsyncKVStore) {
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
+ super(store);
190
22
  }
191
23
 
192
- public getL2SlotNumber(): Promise<SlotNumber | undefined> {
193
- throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
194
26
  }
195
27
 
196
- public getL2EpochNumber(): Promise<EpochNumber> {
197
- throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
28
+ public getRollupAddress(): Promise<EthAddress> {
29
+ throw new Error('TXE Archiver does not implement "getRollupAddress"');
198
30
  }
199
31
 
200
- public getCheckpointsForEpoch(_epochNumber: EpochNumber): Promise<Checkpoint[]> {
201
- throw new Error('TXE Archiver does not implement "getCheckpointsForEpoch"');
32
+ public getRegistryAddress(): Promise<EthAddress> {
33
+ throw new Error('TXE Archiver does not implement "getRegistryAddress"');
202
34
  }
203
35
 
204
- public getBlocksForEpoch(_epochNumber: EpochNumber): Promise<L2Block[]> {
205
- throw new Error('TXE Archiver does not implement "getBlocksForEpoch"');
36
+ public getL1Constants(): Promise<L1RollupConstants> {
37
+ throw new Error('TXE Archiver does not implement "getL1Constants"');
206
38
  }
207
39
 
208
- public getBlockHeadersForEpoch(_epochNumber: EpochNumber): Promise<BlockHeader[]> {
209
- throw new Error('TXE Archiver does not implement "getBlockHeadersForEpoch"');
40
+ public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
41
+ return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
210
42
  }
211
43
 
212
- public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
213
- throw new Error('TXE Archiver does not implement "isEpochComplete"');
44
+ public getL1Timestamp(): Promise<bigint | undefined> {
45
+ throw new Error('TXE Archiver does not implement "getL1Timestamp"');
214
46
  }
215
47
 
216
48
  public async getL2Tips(): Promise<L2Tips> {
@@ -227,7 +59,7 @@ export class TXEArchiver extends ArchiverStoreHelper implements L2BlockSource {
227
59
  if (!checkpointedBlock) {
228
60
  throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
229
61
  }
230
- const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber(number), 1);
62
+ const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
231
63
  if (checkpoint.length === 0) {
232
64
  throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
233
65
  }
@@ -245,50 +77,19 @@ export class TXEArchiver extends ArchiverStoreHelper implements L2BlockSource {
245
77
  };
246
78
  }
247
79
 
248
- public getL1Constants(): Promise<L1RollupConstants> {
249
- throw new Error('TXE Archiver does not implement "getL2Constants"');
250
- }
251
-
252
- public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
253
- return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
254
- }
255
-
256
- public syncImmediate(): Promise<void> {
257
- throw new Error('TXE Archiver does not implement "syncImmediate"');
258
- }
259
-
260
- public getContract(_address: AztecAddress, _timestamp?: UInt64): Promise<ContractInstanceWithAddress | undefined> {
261
- throw new Error('TXE Archiver does not implement "getContract"');
262
- }
263
-
264
- public getRollupAddress(): Promise<EthAddress> {
265
- throw new Error('TXE Archiver does not implement "getRollupAddress"');
266
- }
267
-
268
- public getRegistryAddress(): Promise<EthAddress> {
269
- throw new Error('TXE Archiver does not implement "getRegistryAddress"');
270
- }
271
-
272
- public getL1Timestamp(): Promise<bigint> {
273
- throw new Error('TXE Archiver does not implement "getL1Timestamp"');
274
- }
275
-
276
- public isPendingChainInvalid(): Promise<boolean> {
277
- return Promise.resolve(false);
80
+ public getL2SlotNumber(): Promise<SlotNumber | undefined> {
81
+ throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
278
82
  }
279
83
 
280
- public override getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
281
- return Promise.resolve({ valid: true });
84
+ public getL2EpochNumber(): Promise<EpochNumber | undefined> {
85
+ throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
282
86
  }
283
87
 
284
- getPublishedBlockByHash(_blockHash: Fr): Promise<PublishedL2Block | undefined> {
285
- throw new Error('Method not implemented.');
286
- }
287
- getPublishedBlockByArchive(_archive: Fr): Promise<PublishedL2Block | undefined> {
288
- throw new Error('Method not implemented.');
88
+ public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
89
+ throw new Error('TXE Archiver does not implement "isEpochComplete"');
289
90
  }
290
91
 
291
- getCheckpointedBlocks(_from: BlockNumber, _limit: number, _proven?: boolean): Promise<never[]> {
292
- throw new Error('TXE Archiver does not implement "getCheckpointedBlocks"');
92
+ public syncImmediate(): Promise<void> {
93
+ throw new Error('TXE Archiver does not implement "syncImmediate"');
293
94
  }
294
95
  }
@@ -1,11 +1,14 @@
1
1
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
2
2
  import { TestCircuitVerifier } from '@aztec/bb-prover/test';
3
+ import { CheckpointNumber } from '@aztec/foundation/branded-types';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
5
  import { createLogger } from '@aztec/foundation/log';
4
6
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
5
7
  import { AnchorBlockStore } from '@aztec/pxe/server';
6
8
  import { L2Block } from '@aztec/stdlib/block';
7
- import { L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
9
+ import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
8
10
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
11
+ import { CheckpointHeader } from '@aztec/stdlib/rollup';
9
12
  import { getPackageVersion } from '@aztec/stdlib/update-checker';
10
13
 
11
14
  import { TXEArchiver } from './archiver.js';
@@ -59,7 +62,26 @@ export class TXEStateMachine {
59
62
  }
60
63
 
61
64
  public async handleL2Block(block: L2Block) {
62
- const checkpoint = block.toCheckpoint();
65
+ // Create a checkpoint from the block manually
66
+ const checkpoint = new Checkpoint(
67
+ block.archive,
68
+ CheckpointHeader.from({
69
+ lastArchiveRoot: block.header.lastArchive.root,
70
+ inHash: Fr.ZERO,
71
+ blobsHash: Fr.ZERO,
72
+ blockHeadersHash: Fr.ZERO,
73
+ epochOutHash: Fr.ZERO,
74
+ slotNumber: block.header.globalVariables.slotNumber,
75
+ timestamp: block.header.globalVariables.timestamp,
76
+ coinbase: block.header.globalVariables.coinbase,
77
+ feeRecipient: block.header.globalVariables.feeRecipient,
78
+ gasFees: block.header.globalVariables.gasFees,
79
+ totalManaUsed: block.header.totalManaUsed,
80
+ }),
81
+ [block],
82
+ CheckpointNumber.fromBlockNumber(block.number),
83
+ );
84
+
63
85
  const publishedCheckpoint = new PublishedCheckpoint(
64
86
  checkpoint,
65
87
  new L1PublishedData(
@@ -70,9 +92,9 @@ export class TXEStateMachine {
70
92
  [],
71
93
  );
72
94
  await Promise.all([
73
- this.synchronizer.handleL2Block(block.toL2Block()),
95
+ this.synchronizer.handleL2Block(block),
74
96
  this.archiver.addCheckpoints([publishedCheckpoint], undefined),
75
- this.anchorBlockStore.setHeader(block.getBlockHeader()),
97
+ this.anchorBlockStore.setHeader(block.header),
76
98
  ]);
77
99
  }
78
100
  }
@@ -12,14 +12,16 @@ export class MockEpochCache implements EpochCacheInterface {
12
12
  committee: undefined,
13
13
  seed: 0n,
14
14
  epoch: EpochNumber.ZERO,
15
+ isEscapeHatchOpen: false,
15
16
  });
16
17
  }
17
18
 
18
- getEpochAndSlotNow(): EpochAndSlot {
19
+ getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
19
20
  return {
20
21
  epoch: EpochNumber.ZERO,
21
22
  slot: SlotNumber(0),
22
23
  ts: 0n,
24
+ nowMs: 0n,
23
25
  };
24
26
  }
25
27
 
@@ -40,18 +42,11 @@ export class MockEpochCache implements EpochCacheInterface {
40
42
  return 0n;
41
43
  }
42
44
 
43
- getProposerAttesterAddressInCurrentOrNextSlot(): Promise<{
44
- currentProposer: EthAddress | undefined;
45
- nextProposer: EthAddress | undefined;
46
- currentSlot: SlotNumber;
47
- nextSlot: SlotNumber;
48
- }> {
49
- return Promise.resolve({
50
- currentProposer: undefined,
51
- nextProposer: undefined,
45
+ getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber } {
46
+ return {
52
47
  currentSlot: SlotNumber(0),
53
48
  nextSlot: SlotNumber(0),
54
- });
49
+ };
55
50
  }
56
51
 
57
52
  getProposerAttesterAddressInSlot(_slot: SlotNumber): Promise<EthAddress | undefined> {
@@ -1,7 +1,7 @@
1
1
  import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
- import type { L2BlockNew } from '@aztec/stdlib/block';
4
+ import type { L2Block } from '@aztec/stdlib/block';
5
5
  import type {
6
6
  MerkleTreeReadOperations,
7
7
  MerkleTreeWriteOperations,
@@ -23,7 +23,7 @@ export class TXESynchronizer implements WorldStateSynchronizer {
23
23
  return new this(nativeWorldStateService);
24
24
  }
25
25
 
26
- public async handleL2Block(block: L2BlockNew) {
26
+ public async handleL2Block(block: L2Block) {
27
27
  await this.nativeWorldStateService.handleL2BlockAndMessages(
28
28
  block,
29
29
  Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero),
@@ -7,6 +7,7 @@ import type { ProtocolContract } from '@aztec/protocol-contracts';
7
7
  import {
8
8
  AddressStore,
9
9
  CapsuleStore,
10
+ JobCoordinator,
10
11
  NoteService,
11
12
  NoteStore,
12
13
  PrivateEventStore,
@@ -43,7 +44,7 @@ import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
43
44
 
44
45
  import { z } from 'zod';
45
46
 
46
- import { DEFAULT_ADDRESS, TXE_JOB_ID } from './constants.js';
47
+ import { DEFAULT_ADDRESS } from './constants.js';
47
48
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
48
49
  import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
49
50
  import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
@@ -74,7 +75,6 @@ type SessionState =
74
75
  | {
75
76
  name: 'PRIVATE';
76
77
  nextBlockGlobalVariables: GlobalVariables;
77
- protocolNullifier: Fr;
78
78
  noteCache: ExecutionNoteCache;
79
79
  taggingIndexCache: ExecutionTaggingIndexCache;
80
80
  }
@@ -139,6 +139,8 @@ export class TXESession implements TXESessionStateHandler {
139
139
  private senderAddressBookStore: SenderAddressBookStore,
140
140
  private capsuleStore: CapsuleStore,
141
141
  private privateEventStore: PrivateEventStore,
142
+ private jobCoordinator: JobCoordinator,
143
+ private currentJobId: string,
142
144
  private chainId: Fr,
143
145
  private version: Fr,
144
146
  private nextBlockTimestamp: bigint,
@@ -150,7 +152,7 @@ export class TXESession implements TXESessionStateHandler {
150
152
  const addressStore = new AddressStore(store);
151
153
  const privateEventStore = new PrivateEventStore(store);
152
154
  const contractStore = new TXEContractStore(store);
153
- const noteStore = await NoteStore.create(store);
155
+ const noteStore = new NoteStore(store);
154
156
  const senderTaggingStore = new SenderTaggingStore(store);
155
157
  const recipientTaggingStore = new RecipientTaggingStore(store);
156
158
  const senderAddressBookStore = new SenderAddressBookStore(store);
@@ -158,6 +160,16 @@ export class TXESession implements TXESessionStateHandler {
158
160
  const keyStore = new KeyStore(store);
159
161
  const accountStore = new TXEAccountStore(store);
160
162
 
163
+ // Create job coordinator and register staged stores
164
+ const jobCoordinator = new JobCoordinator(store);
165
+ jobCoordinator.registerStores([
166
+ capsuleStore,
167
+ senderTaggingStore,
168
+ recipientTaggingStore,
169
+ privateEventStore,
170
+ noteStore,
171
+ ]);
172
+
161
173
  // Register protocol contracts.
162
174
  for (const { contractClass, instance, artifact } of protocolContracts) {
163
175
  await contractStore.addContractArtifact(contractClass.id, artifact);
@@ -170,6 +182,8 @@ export class TXESession implements TXESessionStateHandler {
170
182
  const version = new Fr(await stateMachine.node.getVersion());
171
183
  const chainId = new Fr(await stateMachine.node.getChainId());
172
184
 
185
+ const initialJobId = jobCoordinator.beginJob();
186
+
173
187
  const topLevelOracleHandler = new TXEOracleTopLevelContext(
174
188
  stateMachine,
175
189
  contractStore,
@@ -182,6 +196,7 @@ export class TXESession implements TXESessionStateHandler {
182
196
  senderAddressBookStore,
183
197
  capsuleStore,
184
198
  privateEventStore,
199
+ initialJobId,
185
200
  nextBlockTimestamp,
186
201
  version,
187
202
  chainId,
@@ -203,6 +218,8 @@ export class TXESession implements TXESessionStateHandler {
203
218
  senderAddressBookStore,
204
219
  capsuleStore,
205
220
  privateEventStore,
221
+ jobCoordinator,
222
+ initialJobId,
206
223
  version,
207
224
  chainId,
208
225
  nextBlockTimestamp,
@@ -262,6 +279,10 @@ export class TXESession implements TXESessionStateHandler {
262
279
  }
263
280
  }
264
281
 
282
+ // Commit all staged stores from the job that was just completed, then begin a new job
283
+ await this.jobCoordinator.commitJob(this.currentJobId);
284
+ this.currentJobId = this.jobCoordinator.beginJob();
285
+
265
286
  this.oracleHandler = new TXEOracleTopLevelContext(
266
287
  this.stateMachine,
267
288
  this.contractStore,
@@ -274,6 +295,7 @@ export class TXESession implements TXESessionStateHandler {
274
295
  this.senderAddressBookStore,
275
296
  this.capsuleStore,
276
297
  this.privateEventStore,
298
+ this.currentJobId,
277
299
  this.nextBlockTimestamp,
278
300
  this.version,
279
301
  this.chainId,
@@ -294,6 +316,7 @@ export class TXESession implements TXESessionStateHandler {
294
316
  this.noteStore,
295
317
  this.stateMachine.node,
296
318
  this.stateMachine.anchorBlockStore,
319
+ this.currentJobId,
297
320
  ).syncNoteNullifiers(contractAddress);
298
321
 
299
322
  // Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
@@ -337,7 +360,7 @@ export class TXESession implements TXESessionStateHandler {
337
360
  this.senderAddressBookStore,
338
361
  this.capsuleStore,
339
362
  this.privateEventStore,
340
- TXE_JOB_ID,
363
+ this.currentJobId,
341
364
  );
342
365
 
343
366
  // We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
@@ -345,7 +368,7 @@ export class TXESession implements TXESessionStateHandler {
345
368
  // difference resides in that the simulator has all information needed in order to run the simulation, while ours
346
369
  // will be ongoing as the different oracles will be invoked from the Noir test, until eventually the private
347
370
  // execution finishes.
348
- this.state = { name: 'PRIVATE', nextBlockGlobalVariables, protocolNullifier, noteCache, taggingIndexCache };
371
+ this.state = { name: 'PRIVATE', nextBlockGlobalVariables, noteCache, taggingIndexCache };
349
372
  this.logger.debug(`Entered state ${this.state.name}`);
350
373
 
351
374
  return (this.oracleHandler as PrivateExecutionOracle).getPrivateContextInputs();
@@ -387,6 +410,7 @@ export class TXESession implements TXESessionStateHandler {
387
410
  this.noteStore,
388
411
  this.stateMachine.node,
389
412
  this.stateMachine.anchorBlockStore,
413
+ this.currentJobId,
390
414
  ).syncNoteNullifiers(contractAddress);
391
415
 
392
416
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
@@ -406,7 +430,7 @@ export class TXESession implements TXESessionStateHandler {
406
430
  this.senderAddressBookStore,
407
431
  this.capsuleStore,
408
432
  this.privateEventStore,
409
- TXE_JOB_ID,
433
+ this.currentJobId,
410
434
  );
411
435
 
412
436
  this.state = { name: 'UTILITY' };
@@ -442,11 +466,7 @@ export class TXESession implements TXESessionStateHandler {
442
466
  // We rely on the note cache to determine the effects of the transaction. This is incomplete as it doesn't private
443
467
  // logs (other effects like enqueued public calls don't need to be considered since those are not allowed).
444
468
 
445
- const txEffect = await makeTxEffect(
446
- this.state.noteCache,
447
- this.state.protocolNullifier,
448
- this.state.nextBlockGlobalVariables.blockNumber,
449
- );
469
+ const txEffect = await makeTxEffect(this.state.noteCache, this.state.nextBlockGlobalVariables.blockNumber);
450
470
 
451
471
  // We build a block holding just this transaction
452
472
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
@@ -501,7 +521,7 @@ export class TXESession implements TXESessionStateHandler {
501
521
  this.senderAddressBookStore,
502
522
  this.capsuleStore,
503
523
  this.privateEventStore,
504
- TXE_JOB_ID,
524
+ this.currentJobId,
505
525
  );
506
526
  await new WASMSimulator()
507
527
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
@@ -4,12 +4,12 @@ import {
4
4
  NULLIFIER_SUBTREE_HEIGHT,
5
5
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
6
6
  } from '@aztec/constants';
7
- import { BlockNumber } from '@aztec/foundation/branded-types';
7
+ import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
8
8
  import { padArrayEnd } from '@aztec/foundation/collection';
9
9
  import { Fr } from '@aztec/foundation/curves/bn254';
10
- import { Body, L2Block, L2BlockHeader } from '@aztec/stdlib/block';
10
+ import { Body, L2Block } from '@aztec/stdlib/block';
11
11
  import { AppendOnlyTreeSnapshot, MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
12
- import { GlobalVariables, TxEffect } from '@aztec/stdlib/tx';
12
+ import { BlockHeader, GlobalVariables, TxEffect } from '@aztec/stdlib/tx';
13
13
 
14
14
  /**
15
15
  * Returns a transaction request hash that is valid for transactions that are the only ones in a block.
@@ -46,21 +46,18 @@ export async function insertTxEffectIntoWorldTrees(
46
46
  export async function makeTXEBlockHeader(
47
47
  worldTrees: MerkleTreeWriteOperations,
48
48
  globalVariables: GlobalVariables,
49
- ): Promise<L2BlockHeader> {
49
+ ): Promise<BlockHeader> {
50
50
  const stateReference = await worldTrees.getStateReference();
51
51
  const archiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
52
52
 
53
- return new L2BlockHeader(
54
- new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
55
- Fr.ZERO,
56
- Fr.ZERO,
57
- stateReference,
53
+ return BlockHeader.from({
54
+ lastArchive: new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
55
+ spongeBlobHash: Fr.ZERO,
56
+ state: stateReference,
58
57
  globalVariables,
59
- Fr.ZERO,
60
- Fr.ZERO,
61
- Fr.ZERO,
62
- Fr.ZERO,
63
- );
58
+ totalFees: Fr.ZERO,
59
+ totalManaUsed: Fr.ZERO,
60
+ });
64
61
  }
65
62
 
66
63
  /**
@@ -84,11 +81,15 @@ export async function makeTXEBlock(
84
81
  const header = await makeTXEBlockHeader(worldTrees, globalVariables);
85
82
 
86
83
  // Update the archive tree with this block's header hash
87
- await worldTrees.updateArchive(header.toBlockHeader());
84
+ await worldTrees.updateArchive(header);
88
85
 
89
86
  // Get the new archive state after updating
90
87
  const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
91
88
  const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size));
92
89
 
93
- return new L2Block(newArchive, header, new Body(txEffects));
90
+ // L2Block requires checkpointNumber and indexWithinCheckpoint
91
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
92
+ const indexWithinCheckpoint = IndexWithinCheckpoint(0);
93
+
94
+ return new L2Block(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
94
95
  }