@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.
- package/dest/contract_data_oracle/index.d.ts.map +1 -1
- package/dest/contract_data_oracle/index.js +3 -4
- package/dest/contract_tree/index.d.ts +3 -4
- package/dest/contract_tree/index.d.ts.map +1 -1
- package/dest/contract_tree/index.js +10 -12
- package/dest/database/database.d.ts +12 -0
- package/dest/database/database.d.ts.map +1 -1
- package/dest/database/memory_db.d.ts +3 -0
- package/dest/database/memory_db.d.ts.map +1 -1
- package/dest/database/memory_db.js +15 -3
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +2 -2
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +18 -16
- package/dest/kernel_prover/proof_creator.d.ts +4 -8
- package/dest/kernel_prover/proof_creator.d.ts.map +1 -1
- package/dest/kernel_prover/proof_creator.js +5 -5
- package/dest/note_processor/note_processor.d.ts.map +1 -1
- package/dest/note_processor/note_processor.js +6 -4
- package/dest/pxe_service/create_pxe_service.js +2 -2
- package/dest/pxe_service/pxe_service.d.ts +1 -0
- package/dest/pxe_service/pxe_service.d.ts.map +1 -1
- package/dest/pxe_service/pxe_service.js +25 -17
- package/dest/pxe_service/test/pxe_test_suite.d.ts.map +1 -1
- package/dest/pxe_service/test/pxe_test_suite.js +8 -8
- package/dest/simulator_oracle/index.d.ts +1 -0
- package/dest/simulator_oracle/index.d.ts.map +1 -1
- package/dest/simulator_oracle/index.js +13 -4
- package/dest/synchronizer/synchronizer.d.ts.map +1 -1
- package/dest/synchronizer/synchronizer.js +7 -4
- package/package.json +10 -11
- package/src/contract_data_oracle/index.ts +2 -3
- package/src/contract_tree/index.ts +7 -10
- package/src/database/database.ts +14 -0
- package/src/database/memory_db.ts +19 -3
- package/src/index.ts +1 -1
- package/src/kernel_prover/kernel_prover.ts +27 -21
- package/src/kernel_prover/proof_creator.ts +4 -8
- package/src/note_processor/note_processor.ts +7 -3
- package/src/pxe_service/create_pxe_service.ts +1 -1
- package/src/pxe_service/pxe_service.ts +30 -17
- package/src/pxe_service/test/pxe_test_suite.ts +7 -13
- package/src/simulator_oracle/index.ts +13 -2
- package/src/synchronizer/synchronizer.ts +9 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AztecAddress,
|
|
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
|
-
|
|
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
|
|
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(
|
|
88
|
+
const root = computeFunctionTreeRoot(leaves);
|
|
92
89
|
const functionData = FunctionData.fromAbi(constructorArtifact);
|
|
93
|
-
const vkHash = hashVKStr(constructorArtifact.verificationKey
|
|
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,
|
|
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(
|
|
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(
|
|
197
|
+
this.functionTree = computeFunctionTree(leaves);
|
|
201
198
|
}
|
|
202
199
|
const functionTreeData = computeFunctionTreeData(this.functionTree, functionIndex);
|
|
203
200
|
return Promise.resolve(
|
package/src/database/database.ts
CHANGED
|
@@ -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)
|
|
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)
|
|
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,
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
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
|
|
93
|
-
* to
|
|
94
|
-
*
|
|
95
|
-
*
|
|
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 =
|
|
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))
|
|
206
|
+
if (excludedIndices.has(commitmentIndex)) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
207
209
|
|
|
208
210
|
const commitment = commitments[commitmentIndex];
|
|
209
|
-
if (commitment.equals(Fr.ZERO))
|
|
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(
|
|
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 =
|
|
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))
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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: ${
|
|
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
|
-
|
|
646
|
-
|
|
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(
|
|
16
|
-
const completeAddress =
|
|
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(
|
|
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(
|
|
56
|
-
const completeAddress =
|
|
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(
|
|
62
|
-
await pxe.registerAccount(
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
248
|
+
if (processor) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
245
251
|
|
|
246
252
|
this.noteProcessorsToCatchUp.push(new NoteProcessor(publicKey, keyStore, this.db, this.node, startingBlock));
|
|
247
253
|
}
|