@aztec/txe 0.0.1-commit.f295ac2 → 0.0.1-commit.f8ca9b2f3

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 (43) hide show
  1. package/dest/oracle/interfaces.d.ts +3 -3
  2. package/dest/oracle/interfaces.d.ts.map +1 -1
  3. package/dest/oracle/txe_oracle_public_context.d.ts +5 -5
  4. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  5. package/dest/oracle/txe_oracle_public_context.js +6 -6
  6. package/dest/oracle/txe_oracle_top_level_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_top_level_context.js +83 -21
  9. package/dest/rpc_translator.d.ts +15 -9
  10. package/dest/rpc_translator.d.ts.map +1 -1
  11. package/dest/rpc_translator.js +63 -39
  12. package/dest/state_machine/archiver.d.ts +2 -2
  13. package/dest/state_machine/archiver.d.ts.map +1 -1
  14. package/dest/state_machine/archiver.js +7 -6
  15. package/dest/state_machine/dummy_p2p_client.d.ts +9 -8
  16. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  17. package/dest/state_machine/dummy_p2p_client.js +15 -12
  18. package/dest/state_machine/index.d.ts +7 -7
  19. package/dest/state_machine/index.d.ts.map +1 -1
  20. package/dest/state_machine/index.js +30 -16
  21. package/dest/state_machine/mock_epoch_cache.d.ts +8 -6
  22. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  23. package/dest/state_machine/mock_epoch_cache.js +9 -6
  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 +1 -1
  27. package/dest/txe_session.d.ts.map +1 -1
  28. package/dest/txe_session.js +67 -10
  29. package/dest/utils/block_creation.d.ts +5 -5
  30. package/dest/utils/block_creation.d.ts.map +1 -1
  31. package/dest/utils/block_creation.js +7 -5
  32. package/package.json +15 -15
  33. package/src/oracle/interfaces.ts +2 -2
  34. package/src/oracle/txe_oracle_public_context.ts +8 -10
  35. package/src/oracle/txe_oracle_top_level_context.ts +100 -70
  36. package/src/rpc_translator.ts +65 -37
  37. package/src/state_machine/archiver.ts +6 -8
  38. package/src/state_machine/dummy_p2p_client.ts +21 -15
  39. package/src/state_machine/index.ts +48 -19
  40. package/src/state_machine/mock_epoch_cache.ts +10 -11
  41. package/src/state_machine/synchronizer.ts +2 -2
  42. package/src/txe_session.ts +72 -65
  43. package/src/utils/block_creation.ts +8 -6
@@ -131,13 +131,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
131
131
  }
132
132
 
133
133
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
134
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
134
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
135
135
  if (!LogLevels[level]) {
136
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
137
137
  }
138
138
  const levelName = LogLevels[level];
139
139
 
140
140
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
141
+ return Promise.resolve();
141
142
  }
142
143
 
143
144
  txeGetDefaultAddress(): AztecAddress {
@@ -296,12 +297,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
296
297
  throw new Error(message);
297
298
  }
298
299
 
300
+ // When `from` is the zero address (used when creating a new contract account for example),
301
+ // we disable scope filtering by setting effectiveScopes to undefined. This allows these operations
302
+ // to proceed without requiring keys registered for the zero address.
303
+ const effectiveScopes = from.isZero() ? undefined : [from];
304
+
299
305
  // Sync notes before executing private function to discover notes from previous transactions
300
306
  const utilityExecutor = async (call: FunctionCall) => {
301
- await this.executeUtilityCall(call);
307
+ await this.executeUtilityCall(call, effectiveScopes);
302
308
  };
303
309
 
304
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
310
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
311
+ await this.stateMachine.contractSyncService.ensureContractSynced(
312
+ targetContractAddress,
313
+ functionSelector,
314
+ utilityExecutor,
315
+ blockHeader,
316
+ this.jobId,
317
+ );
305
318
 
306
319
  const blockNumber = await this.txeGetNextBlockNumber();
307
320
 
@@ -313,8 +326,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
313
326
 
314
327
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
315
328
 
316
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
317
-
318
329
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
319
330
  const noteCache = new ExecutionNoteCache(protocolNullifier);
320
331
  // In production, the account contract sets the min revertible counter before calling the app function.
@@ -326,43 +337,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
326
337
 
327
338
  const simulator = new WASMSimulator();
328
339
 
329
- const privateExecutionOracle = new PrivateExecutionOracle(
340
+ const privateExecutionOracle = new PrivateExecutionOracle({
330
341
  argsHash,
331
342
  txContext,
332
343
  callContext,
333
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
334
- blockHeader,
344
+ anchorBlockHeader: blockHeader,
335
345
  utilityExecutor,
336
- /** List of transient auth witnesses to be used during this simulation */
337
- Array.from(this.authwits.values()),
338
- /** List of transient auth witnesses to be used during this simulation */
339
- [],
340
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
346
+ authWitnesses: Array.from(this.authwits.values()),
347
+ capsules: [],
348
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
341
349
  noteCache,
342
350
  taggingIndexCache,
343
- this.contractStore,
344
- this.noteStore,
345
- this.keyStore,
346
- this.addressStore,
347
- this.stateMachine.node,
348
- this.stateMachine.anchorBlockStore,
349
- this.senderTaggingStore,
350
- this.recipientTaggingStore,
351
- this.senderAddressBookStore,
352
- this.capsuleStore,
353
- this.privateEventStore,
354
- this.jobId,
355
- 0, // totalPublicArgsCount
356
- minRevertibleSideEffectCounter, // (start) sideEffectCounter
357
- undefined, // log
358
- undefined, // scopes
359
- /**
360
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
361
- * contract would perform, including setting senderForTags.
362
- */
363
- from,
351
+ contractStore: this.contractStore,
352
+ noteStore: this.noteStore,
353
+ keyStore: this.keyStore,
354
+ addressStore: this.addressStore,
355
+ aztecNode: this.stateMachine.node,
356
+ senderTaggingStore: this.senderTaggingStore,
357
+ recipientTaggingStore: this.recipientTaggingStore,
358
+ senderAddressBookStore: this.senderAddressBookStore,
359
+ capsuleStore: this.capsuleStore,
360
+ privateEventStore: this.privateEventStore,
361
+ contractSyncService: this.stateMachine.contractSyncService,
362
+ jobId: this.jobId,
363
+ totalPublicCalldataCount: 0,
364
+ sideEffectCounter: minRevertibleSideEffectCounter,
365
+ scopes: effectiveScopes,
366
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
367
+ // contract would perform, including setting senderForTags.
368
+ senderForTags: from,
364
369
  simulator,
365
- );
370
+ });
366
371
 
367
372
  // Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
368
373
  let result: PrivateExecutionResult;
@@ -401,7 +406,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
401
406
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
402
407
  const { publicInputs } = await generateSimulatedProvingResult(
403
408
  result,
404
- this.contractStore,
409
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
405
410
  minRevertibleSideEffectCounter,
406
411
  );
407
412
 
@@ -414,7 +419,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
414
419
 
415
420
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
416
421
 
417
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
422
+ const bindings = this.logger.getBindings();
423
+ const contractsDB = new PublicContractsDB(
424
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
425
+ bindings,
426
+ );
418
427
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
419
428
  const config = PublicSimulatorConfig.from({
420
429
  skipFeeEnforcement: true,
@@ -427,8 +436,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
427
436
  globals,
428
437
  guardedMerkleTrees,
429
438
  contractsDB,
430
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
439
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
431
440
  new TestDateProvider(),
441
+ undefined,
442
+ createLogger('simulator:public-processor', bindings),
432
443
  );
433
444
 
434
445
  const tx = await Tx.create({
@@ -525,7 +536,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
525
536
 
526
537
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
527
538
 
528
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
539
+ const bindings2 = this.logger.getBindings();
540
+ const contractsDB = new PublicContractsDB(
541
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
542
+ bindings2,
543
+ );
529
544
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
530
545
  const config = PublicSimulatorConfig.from({
531
546
  skipFeeEnforcement: true,
@@ -534,8 +549,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
534
549
  collectStatistics: false,
535
550
  collectCallMetadata: true,
536
551
  });
537
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
538
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
552
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
553
+ const processor = new PublicProcessor(
554
+ globals,
555
+ guardedMerkleTrees,
556
+ contractsDB,
557
+ simulator,
558
+ new TestDateProvider(),
559
+ undefined,
560
+ createLogger('simulator:public-processor', bindings2),
561
+ );
539
562
 
540
563
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
541
564
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -645,25 +668,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
645
668
  }
646
669
 
647
670
  // Sync notes before executing utility function to discover notes from previous transactions
648
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async call => {
649
- await this.executeUtilityCall(call);
650
- });
651
-
652
- const call = new FunctionCall(
653
- artifact.name,
671
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
672
+ await this.stateMachine.contractSyncService.ensureContractSynced(
654
673
  targetContractAddress,
655
674
  functionSelector,
656
- FunctionType.UTILITY,
657
- false,
658
- false,
659
- args,
660
- [],
675
+ async call => {
676
+ await this.executeUtilityCall(call);
677
+ },
678
+ blockHeader,
679
+ this.jobId,
661
680
  );
662
681
 
682
+ const call = FunctionCall.from({
683
+ name: artifact.name,
684
+ to: targetContractAddress,
685
+ selector: functionSelector,
686
+ type: FunctionType.UTILITY,
687
+ hideMsgSender: false,
688
+ isStatic: false,
689
+ args,
690
+ returnTypes: [],
691
+ });
692
+
663
693
  return this.executeUtilityCall(call);
664
694
  }
665
695
 
666
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
696
+ private async executeUtilityCall(call: FunctionCall, scopes?: AztecAddress[]): Promise<Fr[]> {
667
697
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
668
698
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
669
699
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -676,23 +706,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
676
706
 
677
707
  try {
678
708
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
679
- const oracle = new UtilityExecutionOracle(
680
- call.to,
681
- [],
682
- [],
709
+ const oracle = new UtilityExecutionOracle({
710
+ contractAddress: call.to,
711
+ authWitnesses: [],
712
+ capsules: [],
683
713
  anchorBlockHeader,
684
- this.contractStore,
685
- this.noteStore,
686
- this.keyStore,
687
- this.addressStore,
688
- this.stateMachine.node,
689
- this.stateMachine.anchorBlockStore,
690
- this.recipientTaggingStore,
691
- this.senderAddressBookStore,
692
- this.capsuleStore,
693
- this.privateEventStore,
694
- this.jobId,
695
- );
714
+ contractStore: this.contractStore,
715
+ noteStore: this.noteStore,
716
+ keyStore: this.keyStore,
717
+ addressStore: this.addressStore,
718
+ aztecNode: this.stateMachine.node,
719
+ recipientTaggingStore: this.recipientTaggingStore,
720
+ senderAddressBookStore: this.senderAddressBookStore,
721
+ capsuleStore: this.capsuleStore,
722
+ privateEventStore: this.privateEventStore,
723
+ jobId: this.jobId,
724
+ scopes,
725
+ });
696
726
  const acirExecutionResult = await new WASMSimulator()
697
727
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
698
728
  .catch((err: Error) => {
@@ -6,12 +6,11 @@ import {
6
6
  type IMiscOracle,
7
7
  type IPrivateExecutionOracle,
8
8
  type IUtilityExecutionOracle,
9
- packAsRetrievedNote,
9
+ packAsHintedNote,
10
10
  } from '@aztec/pxe/simulator';
11
11
  import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
12
12
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { L2BlockHash } from '@aztec/stdlib/block';
14
- import { MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { BlockHash } from '@aztec/stdlib/block';
15
14
 
16
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
17
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -329,7 +328,7 @@ export class RPCTranslator {
329
328
 
330
329
  // When the argument is a slice, noir automatically adds a length field to oracle call.
331
330
  // When the argument is an array, we add the field length manually to the signature.
332
- utilityDebugLog(
331
+ async utilityLog(
333
332
  foreignLevel: ForeignCallSingle,
334
333
  foreignMessage: ForeignCallArray,
335
334
  _foreignLength: ForeignCallSingle,
@@ -341,7 +340,7 @@ export class RPCTranslator {
341
340
  .join('');
342
341
  const fields = fromArray(foreignFields);
343
342
 
344
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
343
+ await this.handlerAsMisc().utilityLog(level, message, fields);
345
344
 
346
345
  return toForeignCallResult([]);
347
346
  }
@@ -352,7 +351,7 @@ export class RPCTranslator {
352
351
  foreignStartStorageSlot: ForeignCallSingle,
353
352
  foreignNumberOfElements: ForeignCallSingle,
354
353
  ) {
355
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
354
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
356
355
  const contractAddress = addressFromSingle(foreignContractAddress);
357
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
358
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
@@ -368,7 +367,7 @@ export class RPCTranslator {
368
367
  }
369
368
 
370
369
  async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
371
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
370
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
372
371
  const leafSlot = fromSingle(foreignLeafSlot);
373
372
 
374
373
  const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
@@ -397,7 +396,7 @@ export class RPCTranslator {
397
396
  foreignOffset: ForeignCallSingle,
398
397
  foreignStatus: ForeignCallSingle,
399
398
  foreignMaxNotes: ForeignCallSingle,
400
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
399
+ foreignPackedHintedNoteLength: ForeignCallSingle,
401
400
  ) {
402
401
  // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
403
402
  const owner = fromSingle(foreignOwnerIsSome).toBool()
@@ -418,7 +417,7 @@ export class RPCTranslator {
418
417
  const offset = fromSingle(foreignOffset).toNumber();
419
418
  const status = fromSingle(foreignStatus).toNumber();
420
419
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
421
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
420
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
422
421
 
423
422
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
424
423
  owner,
@@ -439,7 +438,7 @@ export class RPCTranslator {
439
438
  );
440
439
 
441
440
  const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
442
- packAsRetrievedNote({
441
+ packAsHintedNote({
443
442
  contractAddress: noteData.contractAddress,
444
443
  owner: noteData.owner,
445
444
  randomness: noteData.randomness,
@@ -457,11 +456,7 @@ export class RPCTranslator {
457
456
 
458
457
  // At last we convert the array of arrays to a bounded vec of arrays
459
458
  return toForeignCallResult(
460
- arrayOfArraysToBoundedVecOfArrays(
461
- returnDataAsArrayOfForeignCallSingleArrays,
462
- maxNotes,
463
- packedRetrievedNoteLength,
464
- ),
459
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
465
460
  );
466
461
  }
467
462
 
@@ -517,6 +512,15 @@ export class RPCTranslator {
517
512
  return toForeignCallResult([]);
518
513
  }
519
514
 
515
+ async privateIsNullifierPending(foreignInnerNullifier: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
516
+ const innerNullifier = fromSingle(foreignInnerNullifier);
517
+ const contractAddress = addressFromSingle(foreignContractAddress);
518
+
519
+ const isPending = await this.handlerAsPrivate().privateIsNullifierPending(innerNullifier, contractAddress);
520
+
521
+ return toForeignCallResult([toSingle(new Fr(isPending))]);
522
+ }
523
+
520
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
521
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
522
526
 
@@ -541,12 +545,23 @@ export class RPCTranslator {
541
545
  );
542
546
  }
543
547
 
544
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
545
549
  const address = addressFromSingle(foreignAddress);
546
550
 
547
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
548
552
 
549
- return toForeignCallResult([toArray([...publicKeys.toFields(), partialAddress])]);
553
+ // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
554
+ // with two fields: `some` (a boolean) and `value` (a field array in this case).
555
+ if (result === undefined) {
556
+ // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
557
+ return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
558
+ } else {
559
+ // Data was found so we set `some` to 1 and return it along with `value`.
560
+ return toForeignCallResult([
561
+ toSingle(new Fr(1)),
562
+ toArray([...result.publicKeys.toFields(), result.partialAddress]),
563
+ ]);
564
+ }
550
565
  }
551
566
 
552
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -570,7 +585,7 @@ export class RPCTranslator {
570
585
  }
571
586
 
572
587
  async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
573
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
574
589
  const nullifier = fromSingle(foreignNullifier);
575
590
 
576
591
  const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
@@ -637,30 +652,43 @@ export class RPCTranslator {
637
652
  return toForeignCallResult(header.toFields().map(toSingle));
638
653
  }
639
654
 
640
- async utilityGetMembershipWitness(
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
658
+ ) {
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
661
+
662
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
663
+
664
+ if (!witness) {
665
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
666
+ }
667
+ return toForeignCallResult(witness.toNoirRepresentation());
668
+ }
669
+
670
+ async utilityGetBlockHashMembershipWitness(
671
+ foreignAnchorBlockHash: ForeignCallSingle,
641
672
  foreignBlockHash: ForeignCallSingle,
642
- foreignTreeId: ForeignCallSingle,
643
- foreignLeafValue: ForeignCallSingle,
644
673
  ) {
645
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
646
- const treeId = fromSingle(foreignTreeId).toNumber();
647
- const leafValue = fromSingle(foreignLeafValue);
674
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
675
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
648
676
 
649
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockHash, treeId, leafValue);
677
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
650
678
 
651
679
  if (!witness) {
652
680
  throw new Error(
653
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockHash}.`,
681
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
654
682
  );
655
683
  }
656
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
684
+ return toForeignCallResult(witness.toNoirRepresentation());
657
685
  }
658
686
 
659
687
  async utilityGetLowNullifierMembershipWitness(
660
688
  foreignBlockHash: ForeignCallSingle,
661
689
  foreignNullifier: ForeignCallSingle,
662
690
  ) {
663
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
664
692
  const nullifier = fromSingle(foreignNullifier);
665
693
 
666
694
  const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
@@ -679,7 +707,7 @@ export class RPCTranslator {
679
707
  return toForeignCallResult([]);
680
708
  }
681
709
 
682
- public async utilityValidateEnqueuedNotesAndEvents(
710
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
683
711
  foreignContractAddress: ForeignCallSingle,
684
712
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
685
713
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -688,7 +716,7 @@ export class RPCTranslator {
688
716
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
689
717
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
690
718
 
691
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
719
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
692
720
  contractAddress,
693
721
  noteValidationRequestsArrayBaseSlot,
694
722
  eventValidationRequestsArrayBaseSlot,
@@ -826,10 +854,11 @@ export class RPCTranslator {
826
854
  return toForeignCallResult([]);
827
855
  }
828
856
 
829
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
857
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
830
858
  const slot = fromSingle(foreignSlot);
859
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
831
860
 
832
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
861
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
833
862
 
834
863
  return toForeignCallResult([toSingle(new Fr(value))]);
835
864
  }
@@ -901,11 +930,10 @@ export class RPCTranslator {
901
930
  return toForeignCallResult([]);
902
931
  }
903
932
 
904
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
905
- const innerNullifier = fromSingle(foreignInnerNullifier);
906
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
907
935
 
908
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
909
937
 
910
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
911
939
  }
@@ -17,18 +17,14 @@ export class TXEArchiver extends ArchiverDataSourceBase {
17
17
  private readonly updater = new ArchiverDataStoreUpdater(this.store);
18
18
 
19
19
  constructor(db: AztecAsyncKVStore) {
20
- const store = new KVArchiverDataStore(db, 9999);
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
21
  super(store);
22
22
  }
23
23
 
24
- // TXE-specific method for adding checkpoints
25
- public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<boolean> {
26
- await this.updater.setNewCheckpointData(checkpoints, result);
27
- return true;
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
28
26
  }
29
27
 
30
- // Abstract method implementations
31
-
32
28
  public getRollupAddress(): Promise<EthAddress> {
33
29
  throw new Error('TXE Archiver does not implement "getRollupAddress"');
34
30
  }
@@ -63,7 +59,9 @@ export class TXEArchiver extends ArchiverDataSourceBase {
63
59
  if (!checkpointedBlock) {
64
60
  throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
65
61
  }
66
- const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber(number), 1);
62
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
63
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
64
+ const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
67
65
  if (checkpoint.length === 0) {
68
66
  throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
69
67
  }
@@ -6,6 +6,8 @@ import type {
6
6
  P2PBlockReceivedCallback,
7
7
  P2PCheckpointReceivedCallback,
8
8
  P2PConfig,
9
+ P2PDuplicateAttestationCallback,
10
+ P2PDuplicateProposalCallback,
9
11
  P2PSyncState,
10
12
  PeerId,
11
13
  ReqRespSubProtocol,
@@ -16,7 +18,7 @@ import type {
16
18
  import type { EthAddress, L2BlockStreamEvent, L2Tips } from '@aztec/stdlib/block';
17
19
  import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
18
20
  import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
19
- import type { Tx, TxHash } from '@aztec/stdlib/tx';
21
+ import type { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
20
22
 
21
23
  export class DummyP2P implements P2P {
22
24
  public validate(_txs: Tx[]): Promise<void> {
@@ -71,8 +73,8 @@ export class DummyP2P implements P2P {
71
73
  throw new Error('DummyP2P does not implement "sendTx"');
72
74
  }
73
75
 
74
- public deleteTxs(_txHashes: TxHash[]): Promise<void> {
75
- throw new Error('DummyP2P does not implement "deleteTxs"');
76
+ public handleFailedExecution(_txHashes: TxHash[]): Promise<void> {
77
+ throw new Error('DummyP2P does not implement "handleFailedExecution"');
76
78
  }
77
79
 
78
80
  public getTxByHashFromPool(_txHash: TxHash): Promise<Tx | undefined> {
@@ -133,8 +135,8 @@ export class DummyP2P implements P2P {
133
135
  throw new Error('DummyP2P does not implement "getCheckpointAttestationsForSlot"');
134
136
  }
135
137
 
136
- public addCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
137
- throw new Error('DummyP2P does not implement "addCheckpointAttestations"');
138
+ public addOwnCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
139
+ throw new Error('DummyP2P does not implement "addOwnCheckpointAttestations"');
138
140
  }
139
141
 
140
142
  public getL2BlockHash(_number: number): Promise<string | undefined> {
@@ -157,14 +159,6 @@ export class DummyP2P implements P2P {
157
159
  throw new Error('DummyP2P does not implement "sync"');
158
160
  }
159
161
 
160
- public requestTxsByHash(_txHashes: TxHash[]): Promise<Tx[]> {
161
- throw new Error('DummyP2P does not implement "requestTxsByHash"');
162
- }
163
-
164
- public getTxs(_filter: 'all' | 'pending' | 'mined'): Promise<Tx[]> {
165
- throw new Error('DummyP2P does not implement "getTxs"');
166
- }
167
-
168
162
  public getTxsByHashFromPool(_txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
169
163
  throw new Error('DummyP2P does not implement "getTxsByHashFromPool"');
170
164
  }
@@ -189,8 +183,12 @@ export class DummyP2P implements P2P {
189
183
  throw new Error('DummyP2P does not implement "getSyncedLatestSlot"');
190
184
  }
191
185
 
192
- markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
193
- throw new Error('DummyP2P does not implement "markTxsAsNonEvictable".');
186
+ protectTxs(_txHashes: TxHash[], _blockHeader: BlockHeader): Promise<TxHash[]> {
187
+ throw new Error('DummyP2P does not implement "protectTxs".');
188
+ }
189
+
190
+ prepareForSlot(_slotNumber: SlotNumber): Promise<void> {
191
+ return Promise.resolve();
194
192
  }
195
193
 
196
194
  addReqRespSubProtocol(
@@ -206,4 +204,12 @@ export class DummyP2P implements P2P {
206
204
 
207
205
  //This is no-op
208
206
  public registerThisValidatorAddresses(_address: EthAddress[]): void {}
207
+
208
+ public registerDuplicateProposalCallback(_callback: P2PDuplicateProposalCallback): void {
209
+ throw new Error('DummyP2P does not implement "registerDuplicateProposalCallback"');
210
+ }
211
+
212
+ public registerDuplicateAttestationCallback(_callback: P2PDuplicateAttestationCallback): void {
213
+ throw new Error('DummyP2P does not implement "registerDuplicateAttestationCallback"');
214
+ }
209
215
  }