@aztec/txe 0.0.1-commit.1142ef1 → 0.0.1-commit.1bea0213

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 +2 -2
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +3 -2
  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 +23 -17
  12. package/dest/rpc_translator.d.ts +15 -9
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +49 -35
  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 +1 -1
  39. package/src/oracle/txe_oracle_public_context.ts +3 -3
  40. package/src/oracle/txe_oracle_top_level_context.ts +27 -17
  41. package/src/rpc_translator.ts +53 -45
  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
@@ -101,8 +101,8 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
101
101
  ]);
102
102
  }
103
103
 
104
- async avmOpcodeStorageRead(slot: Fr): Promise<Fr> {
105
- const leafSlot = await computePublicDataTreeLeafSlot(this.contractAddress, slot);
104
+ async avmOpcodeStorageRead(slot: Fr, contractAddress: AztecAddress): Promise<Fr> {
105
+ const leafSlot = await computePublicDataTreeLeafSlot(contractAddress, slot);
106
106
 
107
107
  const lowLeafResult = await this.forkedWorldTrees.getPreviousValueIndex(
108
108
  MerkleTreeId.PUBLIC_DATA_TREE,
@@ -119,7 +119,7 @@ export class TXEOraclePublicContext implements IAvmExecutionOracle {
119
119
  )) as PublicDataTreeLeafPreimage
120
120
  ).leaf.value;
121
121
 
122
- this.logger.debug('AVM storage read', { slot, value });
122
+ this.logger.debug('AVM storage read', { slot, contractAddress, value });
123
123
 
124
124
  return value;
125
125
  }
@@ -22,6 +22,7 @@ import {
22
22
  SenderAddressBookStore,
23
23
  SenderTaggingStore,
24
24
  enrichPublicSimulationError,
25
+ syncState,
25
26
  } from '@aztec/pxe/server';
26
27
  import {
27
28
  ExecutionNoteCache,
@@ -80,7 +81,7 @@ import {
80
81
  import type { UInt64 } from '@aztec/stdlib/types';
81
82
  import { ForkCheckpoint } from '@aztec/world-state';
82
83
 
83
- import { DEFAULT_ADDRESS, TXE_JOB_ID } from '../constants.js';
84
+ import { DEFAULT_ADDRESS } from '../constants.js';
84
85
  import type { TXEStateMachine } from '../state_machine/index.js';
85
86
  import type { TXEAccountStore } from '../util/txe_account_store.js';
86
87
  import type { TXEContractStore } from '../util/txe_contract_store.js';
@@ -106,6 +107,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
106
107
  private senderAddressBookStore: SenderAddressBookStore,
107
108
  private capsuleStore: CapsuleStore,
108
109
  private privateEventStore: PrivateEventStore,
110
+ private jobId: string,
109
111
  private nextBlockTimestamp: bigint,
110
112
  private version: Fr,
111
113
  private chainId: Fr,
@@ -156,7 +158,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
156
158
  }
157
159
 
158
160
  async txeGetLastTxEffects() {
159
- const block = await this.stateMachine.archiver.getL2Block('latest');
161
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
162
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
160
163
 
161
164
  if (block!.body.txEffects.length != 1) {
162
165
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -299,7 +302,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
299
302
  await this.executeUtilityCall(call);
300
303
  };
301
304
 
302
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
305
+ await syncState(targetContractAddress, this.contractStore, functionSelector, utilityExecutor);
303
306
 
304
307
  const blockNumber = await this.txeGetNextBlockNumber();
305
308
 
@@ -315,6 +318,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
315
318
 
316
319
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
317
320
  const noteCache = new ExecutionNoteCache(protocolNullifier);
321
+ // In production, the account contract sets the min revertible counter before calling the app function.
322
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
323
+ // marking all side effects as revertible.
324
+ const minRevertibleSideEffectCounter = 1;
325
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
318
326
  const taggingIndexCache = new ExecutionTaggingIndexCache();
319
327
 
320
328
  const simulator = new WASMSimulator();
@@ -344,9 +352,9 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
344
352
  this.senderAddressBookStore,
345
353
  this.capsuleStore,
346
354
  this.privateEventStore,
347
- TXE_JOB_ID,
348
- 0,
349
- 1,
355
+ this.jobId,
356
+ 0, // totalPublicArgsCount
357
+ minRevertibleSideEffectCounter, // (start) sideEffectCounter
350
358
  undefined, // log
351
359
  undefined, // scopes
352
360
  /**
@@ -382,19 +390,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
382
390
  }),
383
391
  );
384
392
 
385
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
386
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
387
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
388
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
393
+ noteCache.finish();
394
+ const nonceGenerator = noteCache.getNonceGenerator();
395
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
389
396
  } catch (err) {
390
397
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
391
398
  }
392
399
 
393
- // According to the protocol rules, the nonce generator for the note hashes
394
- // can either be the first nullifier in the tx or the hash of the initial tx request
395
- // if there are none.
396
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
397
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractStore);
400
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
401
+ // the nonce generator for the note hashes.
402
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
403
+ const { publicInputs } = await generateSimulatedProvingResult(
404
+ result,
405
+ this.contractStore,
406
+ minRevertibleSideEffectCounter,
407
+ );
398
408
 
399
409
  const globals = makeGlobalVariables();
400
410
  globals.blockNumber = blockNumber;
@@ -636,7 +646,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
636
646
  }
637
647
 
638
648
  // Sync notes before executing utility function to discover notes from previous transactions
639
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async call => {
649
+ await syncState(targetContractAddress, this.contractStore, functionSelector, async call => {
640
650
  await this.executeUtilityCall(call);
641
651
  });
642
652
 
@@ -682,7 +692,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
682
692
  this.senderAddressBookStore,
683
693
  this.capsuleStore,
684
694
  this.privateEventStore,
685
- TXE_JOB_ID,
695
+ this.jobId,
686
696
  );
687
697
  const acirExecutionResult = await new WASMSimulator()
688
698
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
@@ -6,11 +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 { MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { BlockHash } from '@aztec/stdlib/block';
14
14
 
15
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
16
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -346,34 +346,34 @@ export class RPCTranslator {
346
346
  }
347
347
 
348
348
  async utilityStorageRead(
349
+ foreignBlockHash: ForeignCallSingle,
349
350
  foreignContractAddress: ForeignCallSingle,
350
351
  foreignStartStorageSlot: ForeignCallSingle,
351
- foreignBlockNumber: ForeignCallSingle,
352
352
  foreignNumberOfElements: ForeignCallSingle,
353
353
  ) {
354
+ const blockHash = BlockHash.fromString(foreignBlockHash);
354
355
  const contractAddress = addressFromSingle(foreignContractAddress);
355
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
356
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
357
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
358
358
 
359
359
  const values = await this.handlerAsUtility().utilityStorageRead(
360
+ blockHash,
360
361
  contractAddress,
361
362
  startStorageSlot,
362
- blockNumber,
363
363
  numberOfElements,
364
364
  );
365
365
 
366
366
  return toForeignCallResult([toArray(values)]);
367
367
  }
368
368
 
369
- async utilityGetPublicDataWitness(foreignBlockNumber: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
369
+ async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
+ const blockHash = BlockHash.fromString(foreignBlockHash);
371
371
  const leafSlot = fromSingle(foreignLeafSlot);
372
372
 
373
- const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockNumber, leafSlot);
373
+ const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
374
374
 
375
375
  if (!witness) {
376
- throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockNumber}.`);
376
+ throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockHash.toString()}.`);
377
377
  }
378
378
  return toForeignCallResult(witness.toNoirRepresentation());
379
379
  }
@@ -396,7 +396,7 @@ export class RPCTranslator {
396
396
  foreignOffset: ForeignCallSingle,
397
397
  foreignStatus: ForeignCallSingle,
398
398
  foreignMaxNotes: ForeignCallSingle,
399
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
399
+ foreignPackedHintedNoteLength: ForeignCallSingle,
400
400
  ) {
401
401
  // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
402
402
  const owner = fromSingle(foreignOwnerIsSome).toBool()
@@ -417,7 +417,7 @@ export class RPCTranslator {
417
417
  const offset = fromSingle(foreignOffset).toNumber();
418
418
  const status = fromSingle(foreignStatus).toNumber();
419
419
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
420
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
420
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
421
421
 
422
422
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
423
423
  owner,
@@ -438,13 +438,13 @@ export class RPCTranslator {
438
438
  );
439
439
 
440
440
  const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
441
- packAsRetrievedNote({
441
+ packAsHintedNote({
442
442
  contractAddress: noteData.contractAddress,
443
443
  owner: noteData.owner,
444
444
  randomness: noteData.randomness,
445
445
  storageSlot: noteData.storageSlot,
446
446
  noteNonce: noteData.noteNonce,
447
- index: noteData.index,
447
+ isPending: noteData.isPending,
448
448
  note: noteData.note,
449
449
  }),
450
450
  );
@@ -456,11 +456,7 @@ export class RPCTranslator {
456
456
 
457
457
  // At last we convert the array of arrays to a bounded vec of arrays
458
458
  return toForeignCallResult(
459
- arrayOfArraysToBoundedVecOfArrays(
460
- returnDataAsArrayOfForeignCallSingleArrays,
461
- maxNotes,
462
- packedRetrievedNoteLength,
463
- ),
459
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
464
460
  );
465
461
  }
466
462
 
@@ -516,6 +512,15 @@ export class RPCTranslator {
516
512
  return toForeignCallResult([]);
517
513
  }
518
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
+
519
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
520
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
521
526
 
@@ -568,17 +573,14 @@ export class RPCTranslator {
568
573
  );
569
574
  }
570
575
 
571
- async utilityGetNullifierMembershipWitness(
572
- foreignBlockNumber: ForeignCallSingle,
573
- foreignNullifier: ForeignCallSingle,
574
- ) {
575
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
576
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
577
+ const blockHash = BlockHash.fromString(foreignBlockHash);
576
578
  const nullifier = fromSingle(foreignNullifier);
577
579
 
578
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
580
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
579
581
 
580
582
  if (!witness) {
581
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
583
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
582
584
  }
583
585
  return toForeignCallResult(witness.toNoirRepresentation());
584
586
  }
@@ -639,36 +641,41 @@ export class RPCTranslator {
639
641
  return toForeignCallResult(header.toFields().map(toSingle));
640
642
  }
641
643
 
642
- async utilityGetMembershipWitness(
643
- foreignBlockNumber: ForeignCallSingle,
644
- foreignTreeId: ForeignCallSingle,
645
- foreignLeafValue: ForeignCallSingle,
646
- ) {
647
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
648
- const treeId = fromSingle(foreignTreeId).toNumber();
644
+ async utilityGetNoteHashMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
645
+ const blockHash = BlockHash.fromString(foreignBlockHash);
646
+ const leafValue = fromSingle(foreignLeafValue);
647
+
648
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, leafValue);
649
+
650
+ if (!witness) {
651
+ throw new Error(`Note hash ${leafValue} not found in the note hash tree at block ${blockHash.toString()}.`);
652
+ }
653
+ return toForeignCallResult(witness.toNoirRepresentation());
654
+ }
655
+
656
+ async utilityGetArchiveMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
657
+ const blockHash = BlockHash.fromString(foreignBlockHash);
649
658
  const leafValue = fromSingle(foreignLeafValue);
650
659
 
651
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockNumber, treeId, leafValue);
660
+ const witness = await this.handlerAsUtility().utilityGetArchiveMembershipWitness(blockHash, leafValue);
652
661
 
653
662
  if (!witness) {
654
- throw new Error(
655
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockNumber}.`,
656
- );
663
+ throw new Error(`Block hash ${leafValue} not found in the archive tree at block ${blockHash.toString()}.`);
657
664
  }
658
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
665
+ return toForeignCallResult(witness.toNoirRepresentation());
659
666
  }
660
667
 
661
668
  async utilityGetLowNullifierMembershipWitness(
662
- foreignBlockNumber: ForeignCallSingle,
669
+ foreignBlockHash: ForeignCallSingle,
663
670
  foreignNullifier: ForeignCallSingle,
664
671
  ) {
665
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
672
+ const blockHash = BlockHash.fromString(foreignBlockHash);
666
673
  const nullifier = fromSingle(foreignNullifier);
667
674
 
668
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
675
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
669
676
 
670
677
  if (!witness) {
671
- throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockNumber}.`);
678
+ throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockHash}.`);
672
679
  }
673
680
  return toForeignCallResult(witness.toNoirRepresentation());
674
681
  }
@@ -681,7 +688,7 @@ export class RPCTranslator {
681
688
  return toForeignCallResult([]);
682
689
  }
683
690
 
684
- public async utilityValidateEnqueuedNotesAndEvents(
691
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
685
692
  foreignContractAddress: ForeignCallSingle,
686
693
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
687
694
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -690,7 +697,7 @@ export class RPCTranslator {
690
697
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
691
698
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
692
699
 
693
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
700
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
694
701
  contractAddress,
695
702
  noteValidationRequestsArrayBaseSlot,
696
703
  eventValidationRequestsArrayBaseSlot,
@@ -828,10 +835,11 @@ export class RPCTranslator {
828
835
  return toForeignCallResult([]);
829
836
  }
830
837
 
831
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
838
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
832
839
  const slot = fromSingle(foreignSlot);
840
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
833
841
 
834
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
842
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
835
843
 
836
844
  return toForeignCallResult([toSingle(new Fr(value))]);
837
845
  }