@aztec/pxe 0.15.0 → 0.16.0

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 (45) hide show
  1. package/dest/contract_data_oracle/index.d.ts.map +1 -1
  2. package/dest/contract_data_oracle/index.js +3 -4
  3. package/dest/contract_tree/index.d.ts +3 -4
  4. package/dest/contract_tree/index.d.ts.map +1 -1
  5. package/dest/contract_tree/index.js +10 -12
  6. package/dest/database/database.d.ts +12 -0
  7. package/dest/database/database.d.ts.map +1 -1
  8. package/dest/database/memory_db.d.ts +3 -0
  9. package/dest/database/memory_db.d.ts.map +1 -1
  10. package/dest/database/memory_db.js +15 -3
  11. package/dest/index.d.ts +1 -1
  12. package/dest/index.d.ts.map +1 -1
  13. package/dest/index.js +2 -2
  14. package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
  15. package/dest/kernel_prover/kernel_prover.js +18 -16
  16. package/dest/kernel_prover/proof_creator.d.ts +4 -8
  17. package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
  18. package/dest/kernel_prover/proof_creator.js +5 -5
  19. package/dest/note_processor/note_processor.d.ts.map +1 -1
  20. package/dest/note_processor/note_processor.js +6 -4
  21. package/dest/pxe_service/create_pxe_service.js +2 -2
  22. package/dest/pxe_service/pxe_service.d.ts +1 -0
  23. package/dest/pxe_service/pxe_service.d.ts.map +1 -1
  24. package/dest/pxe_service/pxe_service.js +25 -17
  25. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
  26. package/dest/pxe_service/test/pxe_test_suite.js +8 -8
  27. package/dest/simulator_oracle/index.d.ts +1 -0
  28. package/dest/simulator_oracle/index.d.ts.map +1 -1
  29. package/dest/simulator_oracle/index.js +13 -4
  30. package/dest/synchronizer/synchronizer.d.ts.map +1 -1
  31. package/dest/synchronizer/synchronizer.js +7 -4
  32. package/package.json +10 -11
  33. package/src/contract_data_oracle/index.ts +2 -3
  34. package/src/contract_tree/index.ts +7 -10
  35. package/src/database/database.ts +14 -0
  36. package/src/database/memory_db.ts +19 -3
  37. package/src/index.ts +1 -1
  38. package/src/kernel_prover/kernel_prover.ts +27 -21
  39. package/src/kernel_prover/proof_creator.ts +4 -8
  40. package/src/note_processor/note_processor.ts +7 -3
  41. package/src/pxe_service/create_pxe_service.ts +1 -1
  42. package/src/pxe_service/pxe_service.ts +30 -17
  43. package/src/pxe_service/test/pxe_test_suite.ts +7 -13
  44. package/src/simulator_oracle/index.ts +13 -2
  45. package/src/synchronizer/synchronizer.ts +9 -3
@@ -1,4 +1,4 @@
1
- import { AztecAddress, CircuitsWasm, MembershipWitness, VK_TREE_HEIGHT } from '@aztec/circuits.js';
1
+ import { AztecAddress, MembershipWitness, VK_TREE_HEIGHT } from '@aztec/circuits.js';
2
2
  import { FunctionDebugMetadata, FunctionSelector, getFunctionDebugMetadata } from '@aztec/foundation/abi';
3
3
  import { ContractDatabase, StateInfoProvider } from '@aztec/types';
4
4
 
@@ -155,8 +155,7 @@ export class ContractDataOracle {
155
155
  throw new Error(`Unknown contract: ${contractAddress}`);
156
156
  }
157
157
 
158
- const wasm = await CircuitsWasm.get();
159
- tree = new ContractTree(contract, this.stateProvider, wasm);
158
+ tree = new ContractTree(contract, this.stateProvider);
160
159
  this.trees.push(tree);
161
160
  }
162
161
  return tree;
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  CONTRACT_TREE_HEIGHT,
3
- CircuitsWasm,
4
3
  EthAddress,
5
4
  FUNCTION_TREE_HEIGHT,
6
5
  Fr,
@@ -8,7 +7,6 @@ import {
8
7
  MembershipWitness,
9
8
  NewContractConstructor,
10
9
  NewContractData,
11
- computeFunctionTree,
12
10
  computeFunctionTreeData,
13
11
  generateFunctionLeaves,
14
12
  hashVKStr,
@@ -18,6 +16,7 @@ import {
18
16
  import {
19
17
  computeCompleteAddress,
20
18
  computeContractLeaf,
19
+ computeFunctionTree,
21
20
  computeFunctionTreeRoot,
22
21
  computeVarArgsHash,
23
22
  hashConstructor,
@@ -44,7 +43,6 @@ export class ContractTree {
44
43
  */
45
44
  public readonly contract: ContractDao,
46
45
  private stateInfoProvider: StateInfoProvider,
47
- private wasm: CircuitsWasm,
48
46
  /**
49
47
  * Data associated with the contract constructor for a new contract.
50
48
  */
@@ -66,7 +64,7 @@ export class ContractTree {
66
64
  * @param node - An instance of the AztecNode class representing the current node.
67
65
  * @returns A new ContractTree instance containing the contract data and computed values.
68
66
  */
69
- public static async new(
67
+ public static new(
70
68
  artifact: ContractArtifact,
71
69
  args: Fr[],
72
70
  portalContract: EthAddress,
@@ -74,7 +72,6 @@ export class ContractTree {
74
72
  from: PublicKey,
75
73
  node: AztecNode,
76
74
  ) {
77
- const wasm = await CircuitsWasm.get();
78
75
  const constructorArtifact = artifact.functions.find(isConstructor);
79
76
  if (!constructorArtifact) {
80
77
  throw new Error('Constructor not found.');
@@ -88,9 +85,9 @@ export class ContractTree {
88
85
  selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters),
89
86
  }));
90
87
  const leaves = generateFunctionLeaves(functions);
91
- const root = computeFunctionTreeRoot(wasm, leaves);
88
+ const root = computeFunctionTreeRoot(leaves);
92
89
  const functionData = FunctionData.fromAbi(constructorArtifact);
93
- const vkHash = hashVKStr(constructorArtifact.verificationKey, wasm);
90
+ const vkHash = hashVKStr(constructorArtifact.verificationKey);
94
91
  const argsHash = computeVarArgsHash(args);
95
92
  const constructorHash = hashConstructor(functionData, argsHash, vkHash);
96
93
 
@@ -106,7 +103,7 @@ export class ContractTree {
106
103
  functionData,
107
104
  vkHash,
108
105
  };
109
- return new ContractTree(contractDao, node, wasm, NewContractConstructor);
106
+ return new ContractTree(contractDao, node, NewContractConstructor);
110
107
  }
111
108
 
112
109
  /**
@@ -172,7 +169,7 @@ export class ContractTree {
172
169
  public getFunctionTreeRoot() {
173
170
  if (!this.functionTreeRoot) {
174
171
  const leaves = this.getFunctionLeaves();
175
- this.functionTreeRoot = computeFunctionTreeRoot(this.wasm, leaves);
172
+ this.functionTreeRoot = computeFunctionTreeRoot(leaves);
176
173
  }
177
174
  return Promise.resolve(this.functionTreeRoot);
178
175
  }
@@ -197,7 +194,7 @@ export class ContractTree {
197
194
 
198
195
  if (!this.functionTree) {
199
196
  const leaves = this.getFunctionLeaves();
200
- this.functionTree = computeFunctionTree(this.wasm, leaves);
197
+ this.functionTree = computeFunctionTree(leaves);
201
198
  }
202
199
  const functionTreeData = computeFunctionTreeData(this.functionTree, functionIndex);
203
200
  return Promise.resolve(
@@ -24,6 +24,20 @@ export interface Database extends ContractDatabase {
24
24
  */
25
25
  getAuthWitness(messageHash: Fr): Promise<Fr[]>;
26
26
 
27
+ /**
28
+ * Adding a capsule to the capsule dispenser.
29
+ * @remarks A capsule is a "blob" of data that is passed to the contract through an oracle.
30
+ * @param capsule - An array of field elements representing the capsule.
31
+ */
32
+ addCapsule(capsule: Fr[]): Promise<void>;
33
+
34
+ /**
35
+ * Get the next capsule from the capsule dispenser.
36
+ * @remarks A capsule is a "blob" of data that is passed to the contract through an oracle.
37
+ * @returns A promise that resolves to an array of field elements representing the capsule.
38
+ */
39
+ popCapsule(): Promise<Fr[] | undefined>;
40
+
27
41
  /**
28
42
  * Gets notes based on the provided filter.
29
43
  * @param filter - The filter to apply to the notes.
@@ -20,6 +20,9 @@ export class MemoryDB extends MemoryContractDatabase implements Database {
20
20
  private globalVariablesHash: Fr | undefined;
21
21
  private addresses: CompleteAddress[] = [];
22
22
  private authWitnesses: Record<string, Fr[]> = {};
23
+ // A capsule is a "blob" of data that is passed to the contract through an oracle.
24
+ // We are using a stack to keep track of the capsules that are passed to the contract.
25
+ private capsuleStack: Fr[][] = [];
23
26
 
24
27
  constructor(logSuffix?: string) {
25
28
  super(createDebugLogger(logSuffix ? 'aztec:memory_db_' + logSuffix : 'aztec:memory_db'));
@@ -44,11 +47,20 @@ export class MemoryDB extends MemoryContractDatabase implements Database {
44
47
  return Promise.resolve(this.authWitnesses[messageHash.toString()]);
45
48
  }
46
49
 
47
- public addNote(note: NoteDao) {
50
+ public addNote(note: NoteDao): Promise<void> {
48
51
  this.notesTable.push(note);
49
52
  return Promise.resolve();
50
53
  }
51
54
 
55
+ public addCapsule(capsule: Fr[]): Promise<void> {
56
+ this.capsuleStack.push(capsule);
57
+ return Promise.resolve();
58
+ }
59
+
60
+ public popCapsule(): Promise<Fr[] | undefined> {
61
+ return Promise.resolve(this.capsuleStack.pop());
62
+ }
63
+
52
64
  public addNotes(notes: NoteDao[]) {
53
65
  this.notesTable.push(...notes);
54
66
  return Promise.resolve();
@@ -95,7 +107,9 @@ export class MemoryDB extends MemoryContractDatabase implements Database {
95
107
 
96
108
  public getTreeRoots(): Record<MerkleTreeId, Fr> {
97
109
  const roots = this.treeRoots;
98
- if (!roots) throw new Error(`Tree roots not set in memory database`);
110
+ if (!roots) {
111
+ throw new Error(`Tree roots not set in memory database`);
112
+ }
99
113
  return roots;
100
114
  }
101
115
 
@@ -106,7 +120,9 @@ export class MemoryDB extends MemoryContractDatabase implements Database {
106
120
 
107
121
  public getHistoricBlockData(): HistoricBlockData {
108
122
  const roots = this.getTreeRoots();
109
- if (!this.globalVariablesHash) throw new Error(`Global variables hash not set in memory database`);
123
+ if (!this.globalVariablesHash) {
124
+ throw new Error(`Global variables hash not set in memory database`);
125
+ }
110
126
  return new HistoricBlockData(
111
127
  roots[MerkleTreeId.NOTE_HASH_TREE],
112
128
  roots[MerkleTreeId.NULLIFIER_TREE],
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export * from './config/index.js';
4
4
 
5
5
  export { Tx, TxHash } from '@aztec/types';
6
6
 
7
- export { TxRequest, CircuitsWasm, PartialAddress } from '@aztec/circuits.js';
7
+ export { TxRequest, PartialAddress } from '@aztec/circuits.js';
8
8
  export * from '@aztec/foundation/fields';
9
9
  export * from '@aztec/foundation/eth-address';
10
10
  export * from '@aztec/foundation/aztec-address';
@@ -2,17 +2,18 @@ import { ExecutionResult, NoteAndSlot } from '@aztec/acir-simulator';
2
2
  import {
3
3
  AztecAddress,
4
4
  CONTRACT_TREE_HEIGHT,
5
+ CallRequest,
5
6
  EMPTY_NULLIFIED_COMMITMENT,
6
7
  Fr,
7
8
  MAX_NEW_COMMITMENTS_PER_TX,
8
9
  MAX_NEW_NULLIFIERS_PER_TX,
9
10
  MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,
11
+ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,
10
12
  MAX_READ_REQUESTS_PER_CALL,
11
13
  MAX_READ_REQUESTS_PER_TX,
12
14
  MembershipWitness,
13
15
  PreviousKernelData,
14
16
  PrivateCallData,
15
- PrivateCallStackItem,
16
17
  PrivateKernelInputsInit,
17
18
  PrivateKernelInputsInner,
18
19
  PrivateKernelInputsOrdering,
@@ -24,6 +25,7 @@ import {
24
25
  makeEmptyProof,
25
26
  makeTuple,
26
27
  } from '@aztec/circuits.js';
28
+ import { padArrayEnd } from '@aztec/foundation/collection';
27
29
  import { Tuple, assertLength } from '@aztec/foundation/serialize';
28
30
 
29
31
  import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js';
@@ -93,28 +95,21 @@ export class KernelProver {
93
95
  while (executionStack.length) {
94
96
  const currentExecution = executionStack.pop()!;
95
97
  executionStack.push(...currentExecution.nestedExecutions);
96
- const privateCallStackPreimages = currentExecution.nestedExecutions.map(result => result.callStackItem);
97
- if (privateCallStackPreimages.length > MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL) {
98
- throw new Error(
99
- `Too many items in the call stack. Maximum amount is ${MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL}. Got ${privateCallStackPreimages.length}.`,
100
- );
101
- }
102
- // Pad with empty items to reach max/const length expected by circuit.
103
- privateCallStackPreimages.push(
104
- ...Array(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL - privateCallStackPreimages.length)
105
- .fill(0)
106
- .map(() => PrivateCallStackItem.empty()),
107
- );
98
+
99
+ const privateCallRequests = currentExecution.nestedExecutions.map(result => result.callStackItem.toCallRequest());
100
+ const publicCallRequests = currentExecution.enqueuedPublicFunctionCalls.map(result => result.toCallRequest());
108
101
 
109
102
  // Start with the partially filled in read request witnesses from the simulator
110
103
  // and fill the non-transient ones in with sibling paths via oracle.
111
104
  const readRequestMembershipWitnesses = currentExecution.readRequestPartialWitnesses;
112
105
  for (let rr = 0; rr < readRequestMembershipWitnesses.length; rr++) {
113
- if (currentExecution.callStackItem.publicInputs.readRequests[rr] == Fr.zero()) {
114
- throw new Error(
115
- 'Number of read requests output from Noir circuit does not match number of read request commitment indices output from simulator.',
116
- );
117
- }
106
+ // Pretty sure this check was forever broken. I made some changes to Fr and this started triggering.
107
+ // The conditional makes no sense to me anyway.
108
+ // if (currentExecution.callStackItem.publicInputs.readRequests[rr] == Fr.ZERO) {
109
+ // throw new Error(
110
+ // 'Number of read requests output from Noir circuit does not match number of read request commitment indices output from simulator.',
111
+ // );
112
+ // }
118
113
  const rrWitness = readRequestMembershipWitnesses[rr];
119
114
  if (!rrWitness.isTransient) {
120
115
  // Non-transient reads must contain full membership witness with sibling path from commitment to root.
@@ -133,8 +128,9 @@ export class KernelProver {
133
128
 
134
129
  const privateCallData = await this.createPrivateCallData(
135
130
  currentExecution,
131
+ privateCallRequests,
132
+ publicCallRequests,
136
133
  readRequestMembershipWitnesses,
137
- makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, i => privateCallStackPreimages[i], 0),
138
134
  );
139
135
 
140
136
  if (firstIteration) {
@@ -194,12 +190,21 @@ export class KernelProver {
194
190
 
195
191
  private async createPrivateCallData(
196
192
  { callStackItem, vk }: ExecutionResult,
193
+ privateCallRequests: CallRequest[],
194
+ publicCallRequests: CallRequest[],
197
195
  readRequestMembershipWitnesses: ReadRequestMembershipWitness[],
198
- privateCallStackPreimages: Tuple<PrivateCallStackItem, typeof MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL>,
199
196
  ) {
200
197
  const { contractAddress, functionData, publicInputs } = callStackItem;
201
198
  const { portalContractAddress } = publicInputs.callContext;
202
199
 
200
+ // Pad with empty items to reach max/const length expected by circuit.
201
+ const privateCallStack = padArrayEnd(
202
+ privateCallRequests,
203
+ CallRequest.empty(),
204
+ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,
205
+ );
206
+ const publicCallStack = padArrayEnd(publicCallRequests, CallRequest.empty(), MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL);
207
+
203
208
  const contractLeafMembershipWitness = functionData.isConstructor
204
209
  ? MembershipWitness.random(CONTRACT_TREE_HEIGHT)
205
210
  : await this.oracle.getContractMembershipWitness(contractAddress);
@@ -218,7 +223,8 @@ export class KernelProver {
218
223
 
219
224
  return new PrivateCallData(
220
225
  callStackItem,
221
- privateCallStackPreimages,
226
+ privateCallStack,
227
+ publicCallStack,
222
228
  proof,
223
229
  VerificationKey.fromBuffer(vk),
224
230
  functionLeafMembershipWitness,
@@ -22,8 +22,6 @@ import { CircuitSimulationStats } from '@aztec/types/stats';
22
22
  export interface ProofOutput {
23
23
  /**
24
24
  * The public inputs required for the proof generation process.
25
- * Note: C++ side does not define the specific data structure PrivateKernelPublicInputs and therefore
26
- * would not generate a binding in circuits.gen.ts.
27
25
  */
28
26
  publicInputs: KernelCircuitPublicInputs;
29
27
  /**
@@ -39,8 +37,6 @@ export interface ProofOutput {
39
37
  export interface ProofOutputFinal {
40
38
  /**
41
39
  * The public inputs required for the proof generation process.
42
- * Note: C++ side does not define the specific data structure PrivateKernelPublicInputsFinal and therefore
43
- * would not generate a binding in circuits.gen.ts.
44
40
  */
45
41
  publicInputs: KernelCircuitPublicInputsFinal;
46
42
  /**
@@ -89,10 +85,10 @@ export interface ProofCreator {
89
85
 
90
86
  /**
91
87
  * The KernelProofCreator class is responsible for generating siloed commitments and zero-knowledge proofs
92
- * for private kernel circuit. It leverages Barretenberg and Circuits Wasm libraries
93
- * to perform cryptographic operations and proof creation. The class provides methods to compute commitments
94
- * based on the given public inputs and to generate proofs based on signed transaction requests, previous kernel
95
- * data, private call data, and a flag indicating whether it's the first iteration or not.
88
+ * for private kernel circuit. It leverages Barretenberg to perform cryptographic operations and proof creation.
89
+ * The class provides methods to compute commitments based on the given public inputs and to generate proofs based on
90
+ * signed transaction requests, previous kernel data, private call data, and a flag indicating whether it's the first
91
+ * iteration or not.
96
92
  */
97
93
  export class KernelProofCreator implements ProofCreator {
98
94
  constructor(private log = createDebugLogger('aztec:kernel_proof_creator')) {}
@@ -94,7 +94,7 @@ export class NoteProcessor {
94
94
  }
95
95
 
96
96
  const blocksAndNotes: ProcessedData[] = [];
97
- const curve = await Grumpkin.new();
97
+ const curve = new Grumpkin();
98
98
 
99
99
  // Iterate over both blocks and encrypted logs.
100
100
  for (let blockIndex = 0; blockIndex < encryptedL2BlockLogs.length; ++blockIndex) {
@@ -203,10 +203,14 @@ export class NoteProcessor {
203
203
  let uniqueSiloedNoteHash: Fr | undefined;
204
204
  let innerNullifier: Fr | undefined;
205
205
  for (; commitmentIndex < commitments.length; ++commitmentIndex) {
206
- if (excludedIndices.has(commitmentIndex)) continue;
206
+ if (excludedIndices.has(commitmentIndex)) {
207
+ continue;
208
+ }
207
209
 
208
210
  const commitment = commitments[commitmentIndex];
209
- if (commitment.equals(Fr.ZERO)) break;
211
+ if (commitment.equals(Fr.ZERO)) {
212
+ break;
213
+ }
210
214
 
211
215
  const expectedNonce = computeCommitmentNonce(firstNullifier, commitmentIndex);
212
216
  ({ innerNoteHash, siloedNoteHash, uniqueSiloedNoteHash, innerNullifier } =
@@ -43,7 +43,7 @@ export async function createPXEService(
43
43
  : undefined
44
44
  : useLogSuffix;
45
45
 
46
- keyStore = keyStore || new TestKeyStore(await Grumpkin.new());
46
+ keyStore = keyStore || new TestKeyStore(new Grumpkin());
47
47
  db = db || new MemoryDB(logSuffix);
48
48
 
49
49
  const server = new PXEService(keyStore, aztecNode, db, config, logSuffix);
@@ -8,6 +8,7 @@ import {
8
8
  } from '@aztec/acir-simulator';
9
9
  import {
10
10
  AztecAddress,
11
+ CallRequest,
11
12
  CompleteAddress,
12
13
  FunctionData,
13
14
  GrumpkinPrivateKey,
@@ -119,8 +120,12 @@ export class PXEService implements PXE {
119
120
  return this.db.addAuthWitness(witness.requestHash, witness.witness);
120
121
  }
121
122
 
123
+ public addCapsule(capsule: Fr[]) {
124
+ return this.db.addCapsule(capsule);
125
+ }
126
+
122
127
  public async registerAccount(privKey: GrumpkinPrivateKey, partialAddress: PartialAddress): Promise<CompleteAddress> {
123
- const completeAddress = await CompleteAddress.fromPrivateKeyAndPartialAddress(privKey, partialAddress);
128
+ const completeAddress = CompleteAddress.fromPrivateKeyAndPartialAddress(privKey, partialAddress);
124
129
  const wasAdded = await this.db.addCompleteAddress(completeAddress);
125
130
  if (wasAdded) {
126
131
  const pubKey = this.keyStore.addAccount(privKey);
@@ -276,7 +281,9 @@ export class PXEService implements PXE {
276
281
  const commitments = tx.newCommitments;
277
282
  for (let i = 0; i < commitments.length; ++i) {
278
283
  const commitment = commitments[i];
279
- if (commitment.equals(Fr.ZERO)) break;
284
+ if (commitment.equals(Fr.ZERO)) {
285
+ break;
286
+ }
280
287
 
281
288
  const nonce = computeCommitmentNonce(firstNullifier, i);
282
289
  const { siloedNoteHash, uniqueSiloedNoteHash } = await this.simulator.computeNoteHashAndNullifier(
@@ -321,7 +328,9 @@ export class PXEService implements PXE {
321
328
  const newContract = deployedContractAddress ? await this.db.getContract(deployedContractAddress) : undefined;
322
329
 
323
330
  const tx = await this.#simulateAndProve(txRequest, newContract);
324
- if (simulatePublic) await this.#simulatePublicCalls(tx);
331
+ if (simulatePublic) {
332
+ await this.#simulatePublicCalls(tx);
333
+ }
325
334
  this.log.info(`Executed local simulation for ${await tx.getTxHash()}`);
326
335
 
327
336
  return tx;
@@ -347,13 +356,23 @@ export class PXEService implements PXE {
347
356
  }
348
357
 
349
358
  public async getTxReceipt(txHash: TxHash): Promise<TxReceipt> {
359
+ let txReceipt = new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.');
360
+
361
+ // We first check if the tx is in pending (instead of first checking if it is mined) because if we first check
362
+ // for mined and then for pending there could be a race condition where the tx is mined between the two checks
363
+ // and we would incorrectly return a TxReceipt with status DROPPED
364
+ const pendingTx = await this.node.getPendingTxByHash(txHash);
365
+ if (pendingTx) {
366
+ txReceipt = new TxReceipt(txHash, TxStatus.PENDING, '');
367
+ }
368
+
350
369
  const settledTx = await this.node.getTx(txHash);
351
370
  if (settledTx) {
352
371
  const deployedContractAddress = settledTx.newContractData.find(
353
372
  c => !c.contractAddress.equals(AztecAddress.ZERO),
354
373
  )?.contractAddress;
355
374
 
356
- return new TxReceipt(
375
+ txReceipt = new TxReceipt(
357
376
  txHash,
358
377
  TxStatus.MINED,
359
378
  '',
@@ -363,12 +382,7 @@ export class PXEService implements PXE {
363
382
  );
364
383
  }
365
384
 
366
- const pendingTx = await this.node.getPendingTxByHash(txHash);
367
- if (pendingTx) {
368
- return new TxReceipt(txHash, TxStatus.PENDING, '');
369
- }
370
-
371
- return new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.');
385
+ return txReceipt;
372
386
  }
373
387
 
374
388
  public async getTx(txHash: TxHash): Promise<L2Tx | undefined> {
@@ -622,28 +636,27 @@ export class PXEService implements PXE {
622
636
  publicInputs: KernelCircuitPublicInputsFinal,
623
637
  enqueuedPublicCalls: PublicCallRequest[],
624
638
  ) {
625
- const callToHash = (call: PublicCallRequest) => call.toPublicCallStackItem().hash();
626
- const enqueuedPublicCallsHashes = await Promise.all(enqueuedPublicCalls.map(callToHash));
639
+ const enqueuedPublicCallStackItems = await Promise.all(enqueuedPublicCalls.map(c => c.toCallRequest()));
627
640
  const { publicCallStack } = publicInputs.end;
628
641
 
629
642
  // Validate all items in enqueued public calls are in the kernel emitted stack
630
- const areEqual = enqueuedPublicCallsHashes.reduce(
643
+ const areEqual = enqueuedPublicCallStackItems.reduce(
631
644
  (accum, enqueued) => accum && !!publicCallStack.find(item => item.equals(enqueued)),
632
645
  true,
633
646
  );
634
647
 
635
648
  if (!areEqual) {
636
649
  throw new Error(
637
- `Enqueued public function calls and public call stack do not match.\nEnqueued calls: ${enqueuedPublicCallsHashes
638
- .map(h => h.toString())
650
+ `Enqueued public function calls and public call stack do not match.\nEnqueued calls: ${enqueuedPublicCallStackItems
651
+ .map(h => h.hash.toString())
639
652
  .join(', ')}\nPublic call stack: ${publicCallStack.map(i => i.toString()).join(', ')}`,
640
653
  );
641
654
  }
642
655
 
643
656
  // Override kernel output
644
657
  publicInputs.end.publicCallStack = padArrayEnd(
645
- enqueuedPublicCallsHashes,
646
- Fr.ZERO,
658
+ enqueuedPublicCallStackItems,
659
+ CallRequest.empty(),
647
660
  MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
648
661
  );
649
662
  }
@@ -12,13 +12,10 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise<PXE>) =>
12
12
  }, 120_000);
13
13
 
14
14
  it('registers an account and returns it as an account only and not as a recipient', async () => {
15
- const keyPair = ConstantKeyPair.random(await Grumpkin.new());
16
- const completeAddress = await CompleteAddress.fromPrivateKeyAndPartialAddress(
17
- await keyPair.getPrivateKey(),
18
- Fr.random(),
19
- );
15
+ const keyPair = ConstantKeyPair.random(new Grumpkin());
16
+ const completeAddress = CompleteAddress.fromPrivateKeyAndPartialAddress(keyPair.getPrivateKey(), Fr.random());
20
17
 
21
- await pxe.registerAccount(await keyPair.getPrivateKey(), completeAddress.partialAddress);
18
+ await pxe.registerAccount(keyPair.getPrivateKey(), completeAddress.partialAddress);
22
19
 
23
20
  // Check that the account is correctly registered using the getAccounts and getRecipients methods
24
21
  const accounts = await pxe.getRegisteredAccounts();
@@ -52,14 +49,11 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise<PXE>) =>
52
49
  });
53
50
 
54
51
  it('does not throw when registering the same account twice (just ignores the second attempt)', async () => {
55
- const keyPair = ConstantKeyPair.random(await Grumpkin.new());
56
- const completeAddress = await CompleteAddress.fromPrivateKeyAndPartialAddress(
57
- await keyPair.getPrivateKey(),
58
- Fr.random(),
59
- );
52
+ const keyPair = ConstantKeyPair.random(new Grumpkin());
53
+ const completeAddress = CompleteAddress.fromPrivateKeyAndPartialAddress(keyPair.getPrivateKey(), Fr.random());
60
54
 
61
- await pxe.registerAccount(await keyPair.getPrivateKey(), completeAddress.partialAddress);
62
- await pxe.registerAccount(await keyPair.getPrivateKey(), completeAddress.partialAddress);
55
+ await pxe.registerAccount(keyPair.getPrivateKey(), completeAddress.partialAddress);
56
+ await pxe.registerAccount(keyPair.getPrivateKey(), completeAddress.partialAddress);
63
57
  });
64
58
 
65
59
  it('cannot register a recipient with the same aztec address but different pub key or partial address', async () => {
@@ -31,19 +31,30 @@ export class SimulatorOracle implements DBOracle {
31
31
 
32
32
  async getCompleteAddress(address: AztecAddress): Promise<CompleteAddress> {
33
33
  const completeAddress = await this.db.getCompleteAddress(address);
34
- if (!completeAddress)
34
+ if (!completeAddress) {
35
35
  throw new Error(
36
36
  `No public key registered for address ${address.toString()}. Register it by calling pxe.registerRecipient(...) or pxe.registerAccount(...).\nSee docs for context: https://docs.aztec.network/dev_docs/contracts/common_errors#no-public-key-registered-error`,
37
37
  );
38
+ }
38
39
  return completeAddress;
39
40
  }
40
41
 
41
42
  async getAuthWitness(messageHash: Fr): Promise<Fr[]> {
42
43
  const witness = await this.db.getAuthWitness(messageHash);
43
- if (!witness) throw new Error(`Unknown auth witness for message hash ${messageHash.toString(true)}`);
44
+ if (!witness) {
45
+ throw new Error(`Unknown auth witness for message hash ${messageHash.toString()}`);
46
+ }
44
47
  return witness;
45
48
  }
46
49
 
50
+ async popCapsule(): Promise<Fr[]> {
51
+ const capsule = await this.db.popCapsule();
52
+ if (!capsule) {
53
+ throw new Error(`No capsules available`);
54
+ }
55
+ return capsule;
56
+ }
57
+
47
58
  async getNotes(contractAddress: AztecAddress, storageSlot: Fr) {
48
59
  const noteDaos = await this.db.getNotes({ contractAddress, storageSlot });
49
60
  return noteDaos.map(({ contractAddress, storageSlot, nonce, note, innerNoteHash, siloedNullifier, index }) => ({
@@ -39,7 +39,9 @@ export class Synchronizer {
39
39
  * @param retryInterval - The time interval (in ms) to wait before retrying if no data is available.
40
40
  */
41
41
  public async start(from = INITIAL_L2_BLOCK_NUM, limit = 1, retryInterval = 1000) {
42
- if (this.running) return;
42
+ if (this.running) {
43
+ return;
44
+ }
43
45
  this.running = true;
44
46
 
45
47
  if (from < this.synchedToBlock + 1) {
@@ -197,7 +199,9 @@ export class Synchronizer {
197
199
 
198
200
  private async setBlockDataFromBlock(latestBlock: L2BlockContext) {
199
201
  const { block } = latestBlock;
200
- if (block.number < this.initialSyncBlockNumber) return;
202
+ if (block.number < this.initialSyncBlockNumber) {
203
+ return;
204
+ }
201
205
 
202
206
  const globalsHash = computeGlobalsHash(latestBlock.block.globalVariables);
203
207
  const blockData = new HistoricBlockData(
@@ -241,7 +245,9 @@ export class Synchronizer {
241
245
  public addAccount(publicKey: PublicKey, keyStore: KeyStore, startingBlock: number) {
242
246
  const predicate = (x: NoteProcessor) => x.publicKey.equals(publicKey);
243
247
  const processor = this.noteProcessors.find(predicate) ?? this.noteProcessorsToCatchUp.find(predicate);
244
- if (processor) return;
248
+ if (processor) {
249
+ return;
250
+ }
245
251
 
246
252
  this.noteProcessorsToCatchUp.push(new NoteProcessor(publicKey, keyStore, this.db, this.node, startingBlock));
247
253
  }