@aztec/pxe 0.73.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2
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/bin/index.js +3 -5
- package/dest/config/index.js +18 -21
- package/dest/config/package_info.js +4 -2
- package/dest/contract_data_oracle/index.js +69 -79
- package/dest/contract_data_oracle/private_functions_tree.js +44 -50
- package/dest/database/contracts/contract_artifact_db.js +3 -2
- package/dest/database/contracts/contract_instance_db.js +3 -2
- package/dest/database/index.js +0 -1
- package/dest/database/kv_pxe_database.js +243 -259
- package/dest/database/note_dao.js +28 -43
- package/dest/database/outgoing_note_dao.js +20 -34
- package/dest/database/pxe_database.js +4 -2
- package/dest/database/pxe_database_test_suite.js +296 -151
- package/dest/index.js +0 -1
- package/dest/kernel_oracle/index.js +9 -6
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +68 -66
- package/dest/kernel_prover/hints/index.js +0 -1
- package/dest/kernel_prover/index.js +0 -1
- package/dest/kernel_prover/kernel_prover.js +60 -65
- package/dest/kernel_prover/proving_data_oracle.js +4 -2
- package/dest/note_decryption_utils/add_public_values_to_payload.js +8 -9
- package/dest/pxe_http/index.js +0 -1
- package/dest/pxe_http/pxe_http_server.js +8 -6
- package/dest/pxe_service/error_enriching.js +10 -13
- package/dest/pxe_service/index.js +0 -1
- package/dest/pxe_service/pxe_service.js +283 -288
- package/dest/pxe_service/test/pxe_test_suite.js +40 -27
- package/dest/simulator/index.js +1 -3
- package/dest/simulator_oracle/index.js +266 -231
- package/dest/simulator_oracle/tagging_utils.js +4 -6
- package/dest/synchronizer/index.js +0 -1
- package/dest/synchronizer/synchronizer.js +42 -39
- package/dest/utils/create_pxe_service.js +9 -9
- package/package.json +15 -15
- package/src/pxe_service/pxe_service.ts +12 -14
- package/src/synchronizer/synchronizer.ts +5 -2
- package/dest/bin/index.d.ts +0 -3
- package/dest/bin/index.d.ts.map +0 -1
- package/dest/config/index.d.ts +0 -46
- package/dest/config/index.d.ts.map +0 -1
- package/dest/config/package_info.d.ts +0 -5
- package/dest/config/package_info.d.ts.map +0 -1
- package/dest/contract_data_oracle/index.d.ts +0 -104
- package/dest/contract_data_oracle/index.d.ts.map +0 -1
- package/dest/contract_data_oracle/private_functions_tree.d.ts +0 -65
- package/dest/contract_data_oracle/private_functions_tree.d.ts.map +0 -1
- package/dest/database/contracts/contract_artifact_db.d.ts +0 -20
- package/dest/database/contracts/contract_artifact_db.d.ts.map +0 -1
- package/dest/database/contracts/contract_instance_db.d.ts +0 -19
- package/dest/database/contracts/contract_instance_db.d.ts.map +0 -1
- package/dest/database/index.d.ts +0 -3
- package/dest/database/index.d.ts.map +0 -1
- package/dest/database/kv_pxe_database.d.ts +0 -55
- package/dest/database/kv_pxe_database.d.ts.map +0 -1
- package/dest/database/note_dao.d.ts +0 -103
- package/dest/database/note_dao.d.ts.map +0 -1
- package/dest/database/outgoing_note_dao.d.ts +0 -73
- package/dest/database/outgoing_note_dao.d.ts.map +0 -1
- package/dest/database/pxe_database.d.ts +0 -216
- package/dest/database/pxe_database.d.ts.map +0 -1
- package/dest/database/pxe_database_test_suite.d.ts +0 -7
- package/dest/database/pxe_database_test_suite.d.ts.map +0 -1
- package/dest/index.d.ts +0 -15
- package/dest/index.d.ts.map +0 -1
- package/dest/kernel_oracle/index.d.ts +0 -34
- package/dest/kernel_oracle/index.d.ts.map +0 -1
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +0 -28
- package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +0 -1
- package/dest/kernel_prover/hints/index.d.ts +0 -2
- package/dest/kernel_prover/hints/index.d.ts.map +0 -1
- package/dest/kernel_prover/index.d.ts +0 -3
- package/dest/kernel_prover/index.d.ts.map +0 -1
- package/dest/kernel_prover/kernel_prover.d.ts +0 -38
- package/dest/kernel_prover/kernel_prover.d.ts.map +0 -1
- package/dest/kernel_prover/proving_data_oracle.d.ts +0 -65
- package/dest/kernel_prover/proving_data_oracle.d.ts.map +0 -1
- package/dest/note_decryption_utils/add_public_values_to_payload.d.ts +0 -10
- package/dest/note_decryption_utils/add_public_values_to_payload.d.ts.map +0 -1
- package/dest/pxe_http/index.d.ts +0 -2
- package/dest/pxe_http/index.d.ts.map +0 -1
- package/dest/pxe_http/pxe_http_server.d.ts +0 -16
- package/dest/pxe_http/pxe_http_server.d.ts.map +0 -1
- package/dest/pxe_service/error_enriching.d.ts +0 -11
- package/dest/pxe_service/error_enriching.d.ts.map +0 -1
- package/dest/pxe_service/index.d.ts +0 -4
- package/dest/pxe_service/index.d.ts.map +0 -1
- package/dest/pxe_service/pxe_service.d.ts +0 -97
- package/dest/pxe_service/pxe_service.d.ts.map +0 -1
- package/dest/pxe_service/test/pxe_test_suite.d.ts +0 -3
- package/dest/pxe_service/test/pxe_test_suite.d.ts.map +0 -1
- package/dest/simulator/index.d.ts +0 -10
- package/dest/simulator/index.d.ts.map +0 -1
- package/dest/simulator_oracle/index.d.ts +0 -129
- package/dest/simulator_oracle/index.d.ts.map +0 -1
- package/dest/simulator_oracle/tagging_utils.d.ts +0 -16
- package/dest/simulator_oracle/tagging_utils.d.ts.map +0 -1
- package/dest/synchronizer/index.d.ts +0 -2
- package/dest/synchronizer/index.d.ts.map +0 -1
- package/dest/synchronizer/synchronizer.d.ts +0 -29
- package/dest/synchronizer/synchronizer.d.ts.map +0 -1
- package/dest/utils/create_pxe_service.d.ts +0 -16
- package/dest/utils/create_pxe_service.d.ts.map +0 -1
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import { EventMetadata, L1EventPayload, MerkleTreeId, PrivateSimulationResult, SimulationError, TxProvingResult, TxSimulationResult, UniqueNote, getNonNullifiedL1ToL2MessageWitness, } from '@aztec/circuit-types';
|
|
4
|
-
import { computeContractAddressFromInstance, computeContractClassId, getContractClassFromArtifact, } from '@aztec/circuits.js/contract';
|
|
1
|
+
import { EventMetadata, L1EventPayload, MerkleTreeId, PrivateSimulationResult, SimulationError, TxProvingResult, TxSimulationResult, UniqueNote, getNonNullifiedL1ToL2MessageWitness } from '@aztec/circuit-types';
|
|
2
|
+
import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js/contract';
|
|
5
3
|
import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash';
|
|
6
4
|
import { computeAddressSecret } from '@aztec/circuits.js/keys';
|
|
7
|
-
import { EventSelector, FunctionSelector, FunctionType, decodeFunctionSignature, encodeArguments
|
|
5
|
+
import { EventSelector, FunctionSelector, FunctionType, decodeFunctionSignature, encodeArguments } from '@aztec/foundation/abi';
|
|
8
6
|
import { Fr } from '@aztec/foundation/fields';
|
|
9
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
10
8
|
import { Timer } from '@aztec/foundation/timer';
|
|
@@ -21,37 +19,44 @@ import { Synchronizer } from '../synchronizer/index.js';
|
|
|
21
19
|
import { enrichPublicSimulationError, enrichSimulationError } from './error_enriching.js';
|
|
22
20
|
/**
|
|
23
21
|
* A Private eXecution Environment (PXE) implementation.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
*/ export class PXEService {
|
|
23
|
+
keyStore;
|
|
24
|
+
node;
|
|
25
|
+
db;
|
|
26
|
+
proofCreator;
|
|
27
|
+
simulationProvider;
|
|
28
|
+
synchronizer;
|
|
29
|
+
contractDataOracle;
|
|
30
|
+
simulator;
|
|
31
|
+
log;
|
|
32
|
+
packageVersion;
|
|
33
|
+
proverEnabled;
|
|
34
|
+
constructor(keyStore, node, db, tipsStore, proofCreator, simulationProvider, config, loggerOrSuffix){
|
|
28
35
|
this.keyStore = keyStore;
|
|
29
36
|
this.node = node;
|
|
30
37
|
this.db = db;
|
|
31
38
|
this.proofCreator = proofCreator;
|
|
32
39
|
this.simulationProvider = simulationProvider;
|
|
33
|
-
this.log = createLogger(
|
|
34
|
-
this.synchronizer = new Synchronizer(node, db, tipsStore, config,
|
|
40
|
+
this.log = !loggerOrSuffix || typeof loggerOrSuffix === 'string' ? createLogger(loggerOrSuffix ? `pxe:service:${loggerOrSuffix}` : `pxe:service`) : loggerOrSuffix;
|
|
41
|
+
this.synchronizer = new Synchronizer(node, db, tipsStore, config, loggerOrSuffix);
|
|
35
42
|
this.contractDataOracle = new ContractDataOracle(db);
|
|
36
43
|
this.simulator = getAcirSimulator(db, node, keyStore, this.simulationProvider, this.contractDataOracle);
|
|
37
44
|
this.packageVersion = getPackageInfo().version;
|
|
38
45
|
this.proverEnabled = !!config.proverEnabled;
|
|
39
46
|
}
|
|
40
47
|
/**
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await __classPrivateFieldGet(this, _PXEService_instances, "m", _PXEService_registerProtocolContracts).call(this);
|
|
48
|
+
* Starts the PXE Service by beginning the synchronization process between the Aztec node and the database.
|
|
49
|
+
*
|
|
50
|
+
* @returns A promise that resolves when the server has started successfully.
|
|
51
|
+
*/ async init() {
|
|
52
|
+
await this.#registerProtocolContracts();
|
|
47
53
|
const info = await this.getNodeInfo();
|
|
48
54
|
this.log.info(`Started PXE connected to chain ${info.l1ChainId} version ${info.protocolVersion}`);
|
|
49
55
|
}
|
|
50
56
|
isL1ToL2MessageSynced(l1ToL2Message) {
|
|
51
57
|
return this.node.isL1ToL2MessageSynced(l1ToL2Message);
|
|
52
58
|
}
|
|
53
|
-
/** Returns an estimate of the db size in bytes. */
|
|
54
|
-
estimateDbSize() {
|
|
59
|
+
/** Returns an estimate of the db size in bytes. */ estimateDbSize() {
|
|
55
60
|
return this.db.estimateSize();
|
|
56
61
|
}
|
|
57
62
|
addAuthWitness(witness) {
|
|
@@ -69,16 +74,16 @@ export class PXEService {
|
|
|
69
74
|
async getContractClassMetadata(id, includeArtifact = false) {
|
|
70
75
|
const artifact = await this.db.getContractArtifact(id);
|
|
71
76
|
return {
|
|
72
|
-
contractClass: artifact &&
|
|
73
|
-
isContractClassPubliclyRegistered: await
|
|
74
|
-
artifact: includeArtifact ? artifact : undefined
|
|
77
|
+
contractClass: artifact && await getContractClassFromArtifact(artifact),
|
|
78
|
+
isContractClassPubliclyRegistered: await this.#isContractClassPubliclyRegistered(id),
|
|
79
|
+
artifact: includeArtifact ? artifact : undefined
|
|
75
80
|
};
|
|
76
81
|
}
|
|
77
82
|
async getContractMetadata(address) {
|
|
78
83
|
return {
|
|
79
84
|
contractInstance: await this.db.getContractInstance(address),
|
|
80
|
-
isContractInitialized: await
|
|
81
|
-
isContractPubliclyDeployed: await
|
|
85
|
+
isContractInitialized: await this.#isContractInitialized(address),
|
|
86
|
+
isContractPubliclyDeployed: await this.#isContractPubliclyDeployed(address)
|
|
82
87
|
};
|
|
83
88
|
}
|
|
84
89
|
async registerAccount(secretKey, partialAddress) {
|
|
@@ -87,8 +92,7 @@ export class PXEService {
|
|
|
87
92
|
if (accounts.includes(accountCompleteAddress.address)) {
|
|
88
93
|
this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`);
|
|
89
94
|
return accountCompleteAddress;
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
95
|
+
} else {
|
|
92
96
|
this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`);
|
|
93
97
|
this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`);
|
|
94
98
|
}
|
|
@@ -104,8 +108,7 @@ export class PXEService {
|
|
|
104
108
|
const wasAdded = await this.db.addSenderAddress(address);
|
|
105
109
|
if (wasAdded) {
|
|
106
110
|
this.log.info(`Added sender:\n ${address.toString()}`);
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
111
|
+
} else {
|
|
109
112
|
this.log.info(`Sender:\n "${address.toString()}"\n already registered.`);
|
|
110
113
|
}
|
|
111
114
|
return address;
|
|
@@ -118,8 +121,7 @@ export class PXEService {
|
|
|
118
121
|
const wasRemoved = await this.db.removeSenderAddress(address);
|
|
119
122
|
if (wasRemoved) {
|
|
120
123
|
this.log.info(`Removed sender:\n ${address.toString()}`);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
124
|
+
} else {
|
|
123
125
|
this.log.info(`Sender:\n "${address.toString()}"\n not in address book.`);
|
|
124
126
|
}
|
|
125
127
|
return Promise.resolve();
|
|
@@ -129,10 +131,10 @@ export class PXEService {
|
|
|
129
131
|
const completeAddresses = await this.db.getCompleteAddresses();
|
|
130
132
|
// Filter out the addresses not corresponding to accounts
|
|
131
133
|
const accounts = await this.keyStore.getAccounts();
|
|
132
|
-
return completeAddresses.filter(completeAddress
|
|
134
|
+
return completeAddresses.filter((completeAddress)=>accounts.find((address)=>address.equals(completeAddress.address)));
|
|
133
135
|
}
|
|
134
136
|
async registerContractClass(artifact) {
|
|
135
|
-
const contractClassId = await
|
|
137
|
+
const { id: contractClassId } = await getContractClassFromArtifact(artifact);
|
|
136
138
|
await this.db.addContractArtifact(contractClassId, artifact);
|
|
137
139
|
this.log.info(`Added contract class ${artifact.name} with id ${contractClassId}`);
|
|
138
140
|
}
|
|
@@ -142,23 +144,23 @@ export class PXEService {
|
|
|
142
144
|
if (artifact) {
|
|
143
145
|
// If the user provides an artifact, validate it against the expected class id and register it
|
|
144
146
|
const contractClass = await getContractClassFromArtifact(artifact);
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
throw new Error(`Artifact does not match expected class id (computed ${contractClassId} but instance refers to ${instance.contractClassId})`);
|
|
147
|
+
if (!contractClass.id.equals(instance.contractClassId)) {
|
|
148
|
+
throw new Error(`Artifact does not match expected class id (computed ${contractClass.id} but instance refers to ${instance.contractClassId})`);
|
|
148
149
|
}
|
|
149
150
|
const computedAddress = await computeContractAddressFromInstance(instance);
|
|
150
151
|
if (!computedAddress.equals(instance.address)) {
|
|
151
152
|
throw new Error('Added a contract in which the address does not match the contract instance.');
|
|
152
153
|
}
|
|
153
|
-
await this.db.addContractArtifact(
|
|
154
|
-
const publicFunctionSignatures = artifact.functions
|
|
155
|
-
.filter(fn => fn.functionType === FunctionType.PUBLIC)
|
|
156
|
-
.map(fn => decodeFunctionSignature(fn.name, fn.parameters));
|
|
154
|
+
await this.db.addContractArtifact(contractClass.id, artifact);
|
|
155
|
+
const publicFunctionSignatures = artifact.functions.filter((fn)=>fn.functionType === FunctionType.PUBLIC).map((fn)=>decodeFunctionSignature(fn.name, fn.parameters));
|
|
157
156
|
await this.node.registerContractFunctionSignatures(instance.address, publicFunctionSignatures);
|
|
158
157
|
// TODO(#10007): Node should get public contract class from the registration event, not from PXE registration
|
|
159
|
-
await this.node.addContractClass({
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
await this.node.addContractClass({
|
|
159
|
+
...contractClass,
|
|
160
|
+
privateFunctions: [],
|
|
161
|
+
unconstrainedFunctions: []
|
|
162
|
+
});
|
|
163
|
+
} else {
|
|
162
164
|
// Otherwise, make sure there is an artifact already registered for that class id
|
|
163
165
|
artifact = await this.db.getContractArtifact(instance.contractClassId);
|
|
164
166
|
if (!artifact) {
|
|
@@ -172,18 +174,18 @@ export class PXEService {
|
|
|
172
174
|
return this.db.getContractsAddresses();
|
|
173
175
|
}
|
|
174
176
|
async getPublicStorageAt(contract, slot) {
|
|
175
|
-
if (!
|
|
177
|
+
if (!await this.getContractInstance(contract)) {
|
|
176
178
|
throw new Error(`Contract ${contract.toString()} is not deployed`);
|
|
177
179
|
}
|
|
178
180
|
return await this.node.getPublicStorageAt(contract, slot, 'latest');
|
|
179
181
|
}
|
|
180
182
|
async getNotes(filter) {
|
|
181
183
|
const noteDaos = await this.db.getNotes(filter);
|
|
182
|
-
const extendedNotes = noteDaos.map(async (dao)
|
|
184
|
+
const extendedNotes = noteDaos.map(async (dao)=>{
|
|
183
185
|
let owner = filter.owner;
|
|
184
186
|
if (owner === undefined) {
|
|
185
187
|
const completeAddresses = await this.db.getCompleteAddresses();
|
|
186
|
-
const completeAddressIndex = (await Promise.all(completeAddresses.map(completeAddresses
|
|
188
|
+
const completeAddressIndex = (await Promise.all(completeAddresses.map((completeAddresses)=>completeAddresses.address.toAddressPoint()))).findIndex((addressPoint)=>addressPoint.equals(dao.addressPoint));
|
|
187
189
|
const completeAddress = completeAddresses[completeAddressIndex];
|
|
188
190
|
if (completeAddress === undefined) {
|
|
189
191
|
throw new Error(`Cannot find complete address for addressPoint ${dao.addressPoint.toString()}`);
|
|
@@ -205,19 +207,21 @@ export class PXEService {
|
|
|
205
207
|
if (!owner) {
|
|
206
208
|
throw new Error(`Unknown account: ${note.owner.toString()}`);
|
|
207
209
|
}
|
|
208
|
-
const { data: nonces, l2BlockNumber, l2BlockHash } = await
|
|
210
|
+
const { data: nonces, l2BlockNumber, l2BlockHash } = await this.#getNoteNonces(note);
|
|
209
211
|
if (nonces.length === 0) {
|
|
210
212
|
throw new Error(`Cannot find the note in tx: ${note.txHash}.`);
|
|
211
213
|
}
|
|
212
|
-
for (const nonce of nonces)
|
|
214
|
+
for (const nonce of nonces){
|
|
213
215
|
const { noteHash, uniqueNoteHash, innerNullifier } = await this.simulator.computeNoteHashAndOptionallyANullifier(note.contractAddress, nonce, note.storageSlot, note.noteTypeId, true, note.note);
|
|
214
|
-
const [index] = await this.node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [
|
|
216
|
+
const [index] = await this.node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [
|
|
217
|
+
uniqueNoteHash
|
|
218
|
+
]);
|
|
215
219
|
if (index === undefined) {
|
|
216
220
|
throw new Error('Note does not exist.');
|
|
217
221
|
}
|
|
218
222
|
const siloedNullifier = await siloNullifier(note.contractAddress, innerNullifier);
|
|
219
223
|
const [nullifierIndex] = await this.node.findLeavesIndexes('latest', MerkleTreeId.NULLIFIER_TREE, [
|
|
220
|
-
siloedNullifier
|
|
224
|
+
siloedNullifier
|
|
221
225
|
]);
|
|
222
226
|
if (nullifierIndex !== undefined) {
|
|
223
227
|
throw new Error('The note has been destroyed.');
|
|
@@ -226,23 +230,54 @@ export class PXEService {
|
|
|
226
230
|
}
|
|
227
231
|
}
|
|
228
232
|
async addNullifiedNote(note) {
|
|
229
|
-
const { data: nonces, l2BlockHash, l2BlockNumber } = await
|
|
233
|
+
const { data: nonces, l2BlockHash, l2BlockNumber } = await this.#getNoteNonces(note);
|
|
230
234
|
if (nonces.length === 0) {
|
|
231
235
|
throw new Error(`Cannot find the note in tx: ${note.txHash}.`);
|
|
232
236
|
}
|
|
233
|
-
for (const nonce of nonces)
|
|
237
|
+
for (const nonce of nonces){
|
|
234
238
|
const { noteHash, uniqueNoteHash, innerNullifier } = await this.simulator.computeNoteHashAndOptionallyANullifier(note.contractAddress, nonce, note.storageSlot, note.noteTypeId, false, note.note);
|
|
235
239
|
if (!innerNullifier.equals(Fr.ZERO)) {
|
|
236
240
|
throw new Error('Unexpectedly received non-zero nullifier.');
|
|
237
241
|
}
|
|
238
|
-
const [index] = await this.node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [
|
|
242
|
+
const [index] = await this.node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [
|
|
243
|
+
uniqueNoteHash
|
|
244
|
+
]);
|
|
239
245
|
if (index === undefined) {
|
|
240
246
|
throw new Error('Note does not exist.');
|
|
241
247
|
}
|
|
242
|
-
await this.db.addNullifiedNote(new NoteDao(note.note, note.contractAddress, note.storageSlot, nonce, noteHash, Fr.ZERO,
|
|
243
|
-
note.txHash, l2BlockNumber, l2BlockHash, index, await note.owner.toAddressPoint(), note.noteTypeId));
|
|
248
|
+
await this.db.addNullifiedNote(new NoteDao(note.note, note.contractAddress, note.storageSlot, nonce, noteHash, Fr.ZERO, note.txHash, l2BlockNumber, l2BlockHash, index, await note.owner.toAddressPoint(), note.noteTypeId));
|
|
244
249
|
}
|
|
245
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* Finds the nonce(s) for a given note.
|
|
253
|
+
* @param note - The note to find the nonces for.
|
|
254
|
+
* @returns The nonces of the note.
|
|
255
|
+
* @remarks More than a single nonce may be returned since there might be more than one nonce for a given note.
|
|
256
|
+
*/ async #getNoteNonces(note) {
|
|
257
|
+
const tx = await this.node.getTxEffect(note.txHash);
|
|
258
|
+
if (!tx) {
|
|
259
|
+
throw new Error(`Unknown tx: ${note.txHash}`);
|
|
260
|
+
}
|
|
261
|
+
const nonces = [];
|
|
262
|
+
const firstNullifier = tx.data.nullifiers[0];
|
|
263
|
+
const hashes = tx.data.noteHashes;
|
|
264
|
+
for(let i = 0; i < hashes.length; ++i){
|
|
265
|
+
const hash = hashes[i];
|
|
266
|
+
if (hash.equals(Fr.ZERO)) {
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
const nonce = await computeNoteHashNonce(firstNullifier, i);
|
|
270
|
+
const { uniqueNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(note.contractAddress, nonce, note.storageSlot, note.noteTypeId, false, note.note);
|
|
271
|
+
if (hash.equals(uniqueNoteHash)) {
|
|
272
|
+
nonces.push(nonce);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
l2BlockHash: tx.l2BlockHash,
|
|
277
|
+
l2BlockNumber: tx.l2BlockNumber,
|
|
278
|
+
data: nonces
|
|
279
|
+
};
|
|
280
|
+
}
|
|
246
281
|
async getBlock(blockNumber) {
|
|
247
282
|
// If a negative block number is provided the current block number is fetched.
|
|
248
283
|
if (blockNumber < 0) {
|
|
@@ -255,14 +290,13 @@ export class PXEService {
|
|
|
255
290
|
}
|
|
256
291
|
async proveTx(txRequest, privateExecutionResult) {
|
|
257
292
|
try {
|
|
258
|
-
const { publicInputs, clientIvcProof } = await
|
|
293
|
+
const { publicInputs, clientIvcProof } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
|
|
259
294
|
simulate: false,
|
|
260
295
|
profile: false,
|
|
261
|
-
dryRun: false
|
|
296
|
+
dryRun: false
|
|
262
297
|
});
|
|
263
298
|
return new TxProvingResult(privateExecutionResult, publicInputs, clientIvcProof);
|
|
264
|
-
}
|
|
265
|
-
catch (err) {
|
|
299
|
+
} catch (err) {
|
|
266
300
|
throw this.contextualizeError(err, inspect(txRequest), inspect(privateExecutionResult));
|
|
267
301
|
}
|
|
268
302
|
}
|
|
@@ -276,25 +310,25 @@ export class PXEService {
|
|
|
276
310
|
msgSender,
|
|
277
311
|
chainId: txRequest.txContext.chainId,
|
|
278
312
|
version: txRequest.txContext.version,
|
|
279
|
-
authWitnesses: txRequest.authWitnesses.map(w
|
|
313
|
+
authWitnesses: txRequest.authWitnesses.map((w)=>w.requestHash)
|
|
280
314
|
};
|
|
281
315
|
this.log.info(`Simulating transaction execution request to ${txRequest.functionSelector} at ${txRequest.origin}`, txInfo);
|
|
282
316
|
const timer = new Timer();
|
|
283
317
|
await this.synchronizer.sync();
|
|
284
|
-
const privateExecutionResult = await
|
|
285
|
-
const { publicInputs, profileResult } = await
|
|
318
|
+
const privateExecutionResult = await this.#executePrivate(txRequest, msgSender, scopes);
|
|
319
|
+
const { publicInputs, profileResult } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
|
|
286
320
|
simulate: !profile,
|
|
287
321
|
profile,
|
|
288
|
-
dryRun: true
|
|
322
|
+
dryRun: true
|
|
289
323
|
});
|
|
290
324
|
const privateSimulationResult = new PrivateSimulationResult(privateExecutionResult, publicInputs);
|
|
291
325
|
const simulatedTx = privateSimulationResult.toSimulatedTx();
|
|
292
326
|
let publicOutput;
|
|
293
327
|
if (simulatePublic) {
|
|
294
|
-
publicOutput = await
|
|
328
|
+
publicOutput = await this.#simulatePublicCalls(simulatedTx, enforceFeePayment);
|
|
295
329
|
}
|
|
296
330
|
if (!skipTxValidation) {
|
|
297
|
-
if (!
|
|
331
|
+
if (!await this.node.isValidTx(simulatedTx, true)) {
|
|
298
332
|
throw new Error('The simulated transaction is unable to be added to state and is invalid.');
|
|
299
333
|
}
|
|
300
334
|
}
|
|
@@ -302,19 +336,18 @@ export class PXEService {
|
|
|
302
336
|
this.log.info(`Simulation completed for ${txHash.toString()} in ${timer.ms()}ms`, {
|
|
303
337
|
txHash,
|
|
304
338
|
...txInfo,
|
|
305
|
-
...
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
339
|
+
...profileResult ? {
|
|
340
|
+
gateCounts: profileResult.gateCounts
|
|
341
|
+
} : {},
|
|
342
|
+
...publicOutput ? {
|
|
343
|
+
gasUsed: publicOutput.gasUsed,
|
|
344
|
+
revertCode: publicOutput.txEffect.revertCode.getCode(),
|
|
345
|
+
revertReason: publicOutput.revertReason
|
|
346
|
+
} : {}
|
|
313
347
|
});
|
|
314
348
|
return TxSimulationResult.fromPrivateSimulationResultAndPublicOutput(privateSimulationResult, publicOutput, profileResult);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
throw this.contextualizeError(err, inspect(txRequest), `simulatePublic=${simulatePublic}`, `msgSender=${msgSender?.toString() ?? 'undefined'}`, `skipTxValidation=${skipTxValidation}`, `profile=${profile}`, `scopes=${scopes?.map(s => s.toString()).join(', ') ?? 'undefined'}`);
|
|
349
|
+
} catch (err) {
|
|
350
|
+
throw this.contextualizeError(err, inspect(txRequest), `simulatePublic=${simulatePublic}`, `msgSender=${msgSender?.toString() ?? 'undefined'}`, `skipTxValidation=${skipTxValidation}`, `profile=${profile}`, `scopes=${scopes?.map((s)=>s.toString()).join(', ') ?? 'undefined'}`);
|
|
318
351
|
}
|
|
319
352
|
}
|
|
320
353
|
async sendTx(tx) {
|
|
@@ -323,7 +356,7 @@ export class PXEService {
|
|
|
323
356
|
throw new Error(`A settled tx with equal hash ${txHash.toString()} exists.`);
|
|
324
357
|
}
|
|
325
358
|
this.log.debug(`Sending transaction ${txHash}`);
|
|
326
|
-
await this.node.sendTx(tx).catch(err
|
|
359
|
+
await this.node.sendTx(tx).catch((err)=>{
|
|
327
360
|
throw this.contextualizeError(err, inspect(tx));
|
|
328
361
|
});
|
|
329
362
|
this.log.info(`Sent transaction ${txHash}`);
|
|
@@ -333,14 +366,13 @@ export class PXEService {
|
|
|
333
366
|
try {
|
|
334
367
|
await this.synchronizer.sync();
|
|
335
368
|
// TODO - Should check if `from` has the permission to call the view function.
|
|
336
|
-
const functionCall = await
|
|
337
|
-
const executionResult = await
|
|
369
|
+
const functionCall = await this.#getFunctionCall(functionName, args, to);
|
|
370
|
+
const executionResult = await this.#simulateUnconstrained(functionCall, scopes);
|
|
338
371
|
// TODO - Return typed result based on the function artifact.
|
|
339
372
|
return executionResult;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
throw this.contextualizeError(err, `simulateUnconstrained ${to}:${functionName}(${stringifiedArgs})`, `scopes=${scopes?.map(s => s.toString()).join(', ') ?? 'undefined'}`);
|
|
373
|
+
} catch (err) {
|
|
374
|
+
const stringifiedArgs = args.map((arg)=>arg.toString()).join(', ');
|
|
375
|
+
throw this.contextualizeError(err, `simulateUnconstrained ${to}:${functionName}(${stringifiedArgs})`, `scopes=${scopes?.map((s)=>s.toString()).join(', ') ?? 'undefined'}`);
|
|
344
376
|
}
|
|
345
377
|
}
|
|
346
378
|
getTxReceipt(txHash) {
|
|
@@ -356,21 +388,38 @@ export class PXEService {
|
|
|
356
388
|
return await this.node.getProvenBlockNumber();
|
|
357
389
|
}
|
|
358
390
|
/**
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
getPublicLogs(filter) {
|
|
391
|
+
* Gets public logs based on the provided filter.
|
|
392
|
+
* @param filter - The filter to apply to the logs.
|
|
393
|
+
* @returns The requested logs.
|
|
394
|
+
*/ getPublicLogs(filter) {
|
|
364
395
|
return this.node.getPublicLogs(filter);
|
|
365
396
|
}
|
|
366
397
|
/**
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
getContractClassLogs(filter) {
|
|
398
|
+
* Gets contract class logs based on the provided filter.
|
|
399
|
+
* @param filter - The filter to apply to the logs.
|
|
400
|
+
* @returns The requested logs.
|
|
401
|
+
*/ getContractClassLogs(filter) {
|
|
372
402
|
return this.node.getContractClassLogs(filter);
|
|
373
403
|
}
|
|
404
|
+
async #getFunctionCall(functionName, args, to) {
|
|
405
|
+
const contract = await this.db.getContract(to);
|
|
406
|
+
if (!contract) {
|
|
407
|
+
throw new Error(`Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/developers/reference/debugging/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`);
|
|
408
|
+
}
|
|
409
|
+
const functionDao = contract.functions.find((f)=>f.name === functionName);
|
|
410
|
+
if (!functionDao) {
|
|
411
|
+
throw new Error(`Unknown function ${functionName} in contract ${contract.name}.`);
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
name: functionDao.name,
|
|
415
|
+
args: encodeArguments(functionDao, args),
|
|
416
|
+
selector: await FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
|
|
417
|
+
type: functionDao.functionType,
|
|
418
|
+
to,
|
|
419
|
+
isStatic: functionDao.isStatic,
|
|
420
|
+
returnTypes: functionDao.returnTypes
|
|
421
|
+
};
|
|
422
|
+
}
|
|
374
423
|
async getNodeInfo() {
|
|
375
424
|
const [nodeVersion, protocolVersion, chainId, enr, contractAddresses, protocolContractAddresses] = await Promise.all([
|
|
376
425
|
this.node.getNodeVersion(),
|
|
@@ -378,7 +427,7 @@ export class PXEService {
|
|
|
378
427
|
this.node.getChainId(),
|
|
379
428
|
this.node.getEncodedEnr(),
|
|
380
429
|
this.node.getL1ContractAddresses(),
|
|
381
|
-
this.node.getProtocolContractAddresses()
|
|
430
|
+
this.node.getProtocolContractAddresses()
|
|
382
431
|
]);
|
|
383
432
|
const nodeInfo = {
|
|
384
433
|
nodeVersion,
|
|
@@ -386,7 +435,7 @@ export class PXEService {
|
|
|
386
435
|
protocolVersion,
|
|
387
436
|
enr,
|
|
388
437
|
l1ContractAddresses: contractAddresses,
|
|
389
|
-
protocolContractAddresses: protocolContractAddresses
|
|
438
|
+
protocolContractAddresses: protocolContractAddresses
|
|
390
439
|
};
|
|
391
440
|
return nodeInfo;
|
|
392
441
|
}
|
|
@@ -397,25 +446,145 @@ export class PXEService {
|
|
|
397
446
|
classRegisterer: ProtocolContractAddress.ContractClassRegisterer,
|
|
398
447
|
feeJuice: ProtocolContractAddress.FeeJuice,
|
|
399
448
|
instanceDeployer: ProtocolContractAddress.ContractInstanceDeployer,
|
|
400
|
-
multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint
|
|
401
|
-
}
|
|
449
|
+
multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
async #registerProtocolContracts() {
|
|
454
|
+
const registered = {};
|
|
455
|
+
for (const name of protocolContractNames){
|
|
456
|
+
const { address, contractClass, instance, artifact } = await getCanonicalProtocolContract(name);
|
|
457
|
+
await this.db.addContractArtifact(contractClass.id, artifact);
|
|
458
|
+
await this.db.addContractInstance(instance);
|
|
459
|
+
registered[name] = address.toString();
|
|
460
|
+
}
|
|
461
|
+
this.log.verbose(`Registered protocol contracts in pxe`, registered);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Retrieves the simulation parameters required to run an ACIR simulation.
|
|
465
|
+
* This includes the contract address, function artifact, and historical tree roots.
|
|
466
|
+
*
|
|
467
|
+
* @param execRequest - The transaction request object containing details of the contract call.
|
|
468
|
+
* @returns An object containing the contract address, function artifact, and historical tree roots.
|
|
469
|
+
*/ async #getSimulationParameters(execRequest) {
|
|
470
|
+
const contractAddress = execRequest.to ?? execRequest.origin;
|
|
471
|
+
const functionSelector = execRequest.selector ?? execRequest.functionSelector;
|
|
472
|
+
const functionArtifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, functionSelector);
|
|
473
|
+
const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, functionSelector);
|
|
474
|
+
return {
|
|
475
|
+
contractAddress,
|
|
476
|
+
functionArtifact: {
|
|
477
|
+
...functionArtifact,
|
|
478
|
+
debug
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
async #executePrivate(txRequest, msgSender, scopes) {
|
|
483
|
+
// TODO - Pause syncing while simulating.
|
|
484
|
+
const { contractAddress, functionArtifact } = await this.#getSimulationParameters(txRequest);
|
|
485
|
+
try {
|
|
486
|
+
const result = await this.simulator.run(txRequest, functionArtifact, contractAddress, msgSender, scopes);
|
|
487
|
+
this.log.debug(`Private simulation completed for ${contractAddress.toString()}:${functionArtifact.name}`);
|
|
488
|
+
return result;
|
|
489
|
+
} catch (err) {
|
|
490
|
+
if (err instanceof SimulationError) {
|
|
491
|
+
await enrichSimulationError(err, this.db, this.log);
|
|
492
|
+
}
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Simulate an unconstrained transaction on the given contract, without considering constraints set by ACIR.
|
|
498
|
+
* The simulation parameters are fetched using ContractDataOracle and executed using AcirSimulator.
|
|
499
|
+
* Returns the simulation result containing the outputs of the unconstrained function.
|
|
500
|
+
*
|
|
501
|
+
* @param execRequest - The transaction request object containing the target contract and function data.
|
|
502
|
+
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
|
|
503
|
+
* @returns The simulation result containing the outputs of the unconstrained function.
|
|
504
|
+
*/ async #simulateUnconstrained(execRequest, scopes) {
|
|
505
|
+
const { contractAddress, functionArtifact } = await this.#getSimulationParameters(execRequest);
|
|
506
|
+
this.log.debug('Executing unconstrained simulator...');
|
|
507
|
+
try {
|
|
508
|
+
const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress, scopes);
|
|
509
|
+
this.log.verbose(`Unconstrained simulation for ${contractAddress}.${functionArtifact.name} completed`);
|
|
510
|
+
return result;
|
|
511
|
+
} catch (err) {
|
|
512
|
+
if (err instanceof SimulationError) {
|
|
513
|
+
await enrichSimulationError(err, this.db, this.log);
|
|
514
|
+
}
|
|
515
|
+
throw err;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Simulate the public part of a transaction.
|
|
520
|
+
* This allows to catch public execution errors before submitting the transaction.
|
|
521
|
+
* It can also be used for estimating gas in the future.
|
|
522
|
+
* @param tx - The transaction to be simulated.
|
|
523
|
+
*/ async #simulatePublicCalls(tx, enforceFeePayment) {
|
|
524
|
+
// Simulating public calls can throw if the TX fails in a phase that doesn't allow reverts (setup)
|
|
525
|
+
// Or return as reverted if it fails in a phase that allows reverts (app logic, teardown)
|
|
526
|
+
try {
|
|
527
|
+
const result = await this.node.simulatePublicCalls(tx, enforceFeePayment);
|
|
528
|
+
if (result.revertReason) {
|
|
529
|
+
throw result.revertReason;
|
|
530
|
+
}
|
|
531
|
+
return result;
|
|
532
|
+
} catch (err) {
|
|
533
|
+
if (err instanceof SimulationError) {
|
|
534
|
+
try {
|
|
535
|
+
await enrichPublicSimulationError(err, this.contractDataOracle, this.db, this.log);
|
|
536
|
+
} catch (enrichErr) {
|
|
537
|
+
this.log.error(`Failed to enrich public simulation error: ${enrichErr}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
throw err;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Generate a kernel proof, and create a private kernel output.
|
|
545
|
+
* The function takes in a transaction execution request, and the result of private execution
|
|
546
|
+
* and then generates a kernel proof.
|
|
547
|
+
*
|
|
548
|
+
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
549
|
+
* @param proofCreator - The proof creator to use for proving the execution.
|
|
550
|
+
* @param privateExecutionResult - The result of the private execution
|
|
551
|
+
* @returns An object that contains the output of the kernel execution, including the ClientIvcProof if proving is enabled.
|
|
552
|
+
*/ async #prove(txExecutionRequest, proofCreator, privateExecutionResult, { simulate, profile, dryRun }) {
|
|
553
|
+
// use the block the tx was simulated against
|
|
554
|
+
const block = privateExecutionResult.entrypoint.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
|
|
555
|
+
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block);
|
|
556
|
+
const kernelProver = new KernelProver(kernelOracle, proofCreator, !this.proverEnabled);
|
|
557
|
+
this.log.debug(`Executing kernel prover (simulate: ${simulate}, profile: ${profile}, dryRun: ${dryRun})...`);
|
|
558
|
+
return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, {
|
|
559
|
+
simulate,
|
|
560
|
+
profile,
|
|
561
|
+
dryRun
|
|
402
562
|
});
|
|
403
563
|
}
|
|
404
|
-
async
|
|
405
|
-
|
|
564
|
+
async #isContractClassPubliclyRegistered(id) {
|
|
565
|
+
return !!await this.node.getContractClass(id);
|
|
566
|
+
}
|
|
567
|
+
async #isContractPubliclyDeployed(address) {
|
|
568
|
+
return !!await this.node.getContract(address);
|
|
569
|
+
}
|
|
570
|
+
async #isContractInitialized(address) {
|
|
571
|
+
const initNullifier = await siloNullifier(address, address.toField());
|
|
572
|
+
return !!await this.node.getNullifierMembershipWitness('latest', initNullifier);
|
|
573
|
+
}
|
|
574
|
+
async getPrivateEvents(eventMetadataDef, from, limit, // TODO (#9272): Make this better, we should be able to only pass an address now
|
|
406
575
|
vpks) {
|
|
407
576
|
const eventMetadata = new EventMetadata(eventMetadataDef);
|
|
408
577
|
if (vpks.length === 0) {
|
|
409
578
|
throw new Error('Tried to get encrypted events without supplying any viewing public keys');
|
|
410
579
|
}
|
|
411
580
|
const blocks = await this.node.getBlocks(from, limit);
|
|
412
|
-
const txEffects = blocks.flatMap(block
|
|
413
|
-
const privateLogs = txEffects.flatMap(txEffect
|
|
414
|
-
const vsks = await Promise.all(vpks.map(async (vpk)
|
|
581
|
+
const txEffects = blocks.flatMap((block)=>block.body.txEffects);
|
|
582
|
+
const privateLogs = txEffects.flatMap((txEffect)=>txEffect.privateLogs);
|
|
583
|
+
const vsks = await Promise.all(vpks.map(async (vpk)=>{
|
|
415
584
|
const [keyPrefix, account] = await this.keyStore.getKeyPrefixAndAccount(vpk);
|
|
416
585
|
let secretKey = await this.keyStore.getMasterSecretKey(vpk);
|
|
417
586
|
if (keyPrefix === 'iv') {
|
|
418
|
-
const registeredAccount = (await this.getRegisteredAccounts()).find(completeAddress
|
|
587
|
+
const registeredAccount = (await this.getRegisteredAccounts()).find((completeAddress)=>completeAddress.address.equals(account));
|
|
419
588
|
if (!registeredAccount) {
|
|
420
589
|
throw new Error('No registered account');
|
|
421
590
|
}
|
|
@@ -424,19 +593,20 @@ export class PXEService {
|
|
|
424
593
|
}
|
|
425
594
|
return secretKey;
|
|
426
595
|
}));
|
|
427
|
-
const visibleEvents = (await Promise.all(privateLogs.map(async (log)
|
|
428
|
-
for (const sk of vsks)
|
|
596
|
+
const visibleEvents = (await Promise.all(privateLogs.map(async (log)=>{
|
|
597
|
+
for (const sk of vsks){
|
|
429
598
|
// TODO: Verify that the first field of the log is the tag siloed with contract address.
|
|
430
599
|
// Or use tags to query logs, like we do with notes.
|
|
431
600
|
const decryptedEvent = await L1EventPayload.decryptAsIncoming(log, sk);
|
|
432
601
|
if (decryptedEvent !== undefined) {
|
|
433
|
-
return [
|
|
602
|
+
return [
|
|
603
|
+
decryptedEvent
|
|
604
|
+
];
|
|
434
605
|
}
|
|
435
606
|
}
|
|
436
607
|
return [];
|
|
437
608
|
}))).flat();
|
|
438
|
-
const decodedEvents = visibleEvents
|
|
439
|
-
.map(visibleEvent => {
|
|
609
|
+
const decodedEvents = visibleEvents.map((visibleEvent)=>{
|
|
440
610
|
if (visibleEvent === undefined) {
|
|
441
611
|
return undefined;
|
|
442
612
|
}
|
|
@@ -444,18 +614,16 @@ export class PXEService {
|
|
|
444
614
|
return undefined;
|
|
445
615
|
}
|
|
446
616
|
return eventMetadata.decode(visibleEvent);
|
|
447
|
-
})
|
|
448
|
-
.filter(visibleEvent => visibleEvent !== undefined);
|
|
617
|
+
}).filter((visibleEvent)=>visibleEvent !== undefined);
|
|
449
618
|
return decodedEvents;
|
|
450
619
|
}
|
|
451
620
|
async getPublicEvents(eventMetadataDef, from, limit) {
|
|
452
621
|
const eventMetadata = new EventMetadata(eventMetadataDef);
|
|
453
622
|
const { logs } = await this.node.getPublicLogs({
|
|
454
623
|
fromBlock: from,
|
|
455
|
-
toBlock: from + limit
|
|
624
|
+
toBlock: from + limit
|
|
456
625
|
});
|
|
457
|
-
const decodedEvents = logs
|
|
458
|
-
.map(log => {
|
|
626
|
+
const decodedEvents = logs.map((log)=>{
|
|
459
627
|
// +1 for the event selector
|
|
460
628
|
const expectedLength = eventMetadata.fieldNames.length + 1;
|
|
461
629
|
const logFields = log.log.log.slice(0, expectedLength);
|
|
@@ -464,12 +632,11 @@ export class PXEService {
|
|
|
464
632
|
return undefined;
|
|
465
633
|
}
|
|
466
634
|
// If any of the remaining fields, are non-zero, the payload does match expected:
|
|
467
|
-
if (log.log.log.slice(expectedLength + 1).find(f
|
|
635
|
+
if (log.log.log.slice(expectedLength + 1).find((f)=>!f.isZero())) {
|
|
468
636
|
throw new Error('Something is weird here, we have matching EventSelectors, but the actual payload has mismatched length');
|
|
469
637
|
}
|
|
470
638
|
return eventMetadata.decode(log.log);
|
|
471
|
-
})
|
|
472
|
-
.filter(log => log !== undefined);
|
|
639
|
+
}).filter((log)=>log !== undefined);
|
|
473
640
|
return decodedEvents;
|
|
474
641
|
}
|
|
475
642
|
async resetNoteSyncData() {
|
|
@@ -482,182 +649,10 @@ export class PXEService {
|
|
|
482
649
|
}
|
|
483
650
|
if (err instanceof SimulationError) {
|
|
484
651
|
err.setAztecContext(contextStr);
|
|
485
|
-
}
|
|
486
|
-
else {
|
|
652
|
+
} else {
|
|
487
653
|
this.log.error(err.name, err);
|
|
488
654
|
this.log.debug(contextStr);
|
|
489
655
|
}
|
|
490
656
|
return err;
|
|
491
657
|
}
|
|
492
658
|
}
|
|
493
|
-
_PXEService_instances = new WeakSet(), _PXEService_getNoteNonces =
|
|
494
|
-
/**
|
|
495
|
-
* Finds the nonce(s) for a given note.
|
|
496
|
-
* @param note - The note to find the nonces for.
|
|
497
|
-
* @returns The nonces of the note.
|
|
498
|
-
* @remarks More than a single nonce may be returned since there might be more than one nonce for a given note.
|
|
499
|
-
*/
|
|
500
|
-
async function _PXEService_getNoteNonces(note) {
|
|
501
|
-
const tx = await this.node.getTxEffect(note.txHash);
|
|
502
|
-
if (!tx) {
|
|
503
|
-
throw new Error(`Unknown tx: ${note.txHash}`);
|
|
504
|
-
}
|
|
505
|
-
const nonces = [];
|
|
506
|
-
const firstNullifier = tx.data.nullifiers[0];
|
|
507
|
-
const hashes = tx.data.noteHashes;
|
|
508
|
-
for (let i = 0; i < hashes.length; ++i) {
|
|
509
|
-
const hash = hashes[i];
|
|
510
|
-
if (hash.equals(Fr.ZERO)) {
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
const nonce = await computeNoteHashNonce(firstNullifier, i);
|
|
514
|
-
const { uniqueNoteHash } = await this.simulator.computeNoteHashAndOptionallyANullifier(note.contractAddress, nonce, note.storageSlot, note.noteTypeId, false, note.note);
|
|
515
|
-
if (hash.equals(uniqueNoteHash)) {
|
|
516
|
-
nonces.push(nonce);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
return { l2BlockHash: tx.l2BlockHash, l2BlockNumber: tx.l2BlockNumber, data: nonces };
|
|
520
|
-
}, _PXEService_getFunctionCall = async function _PXEService_getFunctionCall(functionName, args, to) {
|
|
521
|
-
const contract = await this.db.getContract(to);
|
|
522
|
-
if (!contract) {
|
|
523
|
-
throw new Error(`Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/reference/common_errors/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`);
|
|
524
|
-
}
|
|
525
|
-
const functionDao = contract.functions.find(f => f.name === functionName);
|
|
526
|
-
if (!functionDao) {
|
|
527
|
-
throw new Error(`Unknown function ${functionName} in contract ${contract.name}.`);
|
|
528
|
-
}
|
|
529
|
-
return {
|
|
530
|
-
name: functionDao.name,
|
|
531
|
-
args: encodeArguments(functionDao, args),
|
|
532
|
-
selector: await FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
|
|
533
|
-
type: functionDao.functionType,
|
|
534
|
-
to,
|
|
535
|
-
isStatic: functionDao.isStatic,
|
|
536
|
-
returnTypes: functionDao.returnTypes,
|
|
537
|
-
};
|
|
538
|
-
}, _PXEService_registerProtocolContracts = async function _PXEService_registerProtocolContracts() {
|
|
539
|
-
const registered = {};
|
|
540
|
-
for (const name of protocolContractNames) {
|
|
541
|
-
const { address, contractClass, instance, artifact } = await getCanonicalProtocolContract(name);
|
|
542
|
-
await this.db.addContractArtifact(contractClass.id, artifact);
|
|
543
|
-
await this.db.addContractInstance(instance);
|
|
544
|
-
registered[name] = address.toString();
|
|
545
|
-
}
|
|
546
|
-
this.log.verbose(`Registered protocol contracts in pxe`, registered);
|
|
547
|
-
}, _PXEService_getSimulationParameters =
|
|
548
|
-
/**
|
|
549
|
-
* Retrieves the simulation parameters required to run an ACIR simulation.
|
|
550
|
-
* This includes the contract address, function artifact, and historical tree roots.
|
|
551
|
-
*
|
|
552
|
-
* @param execRequest - The transaction request object containing details of the contract call.
|
|
553
|
-
* @returns An object containing the contract address, function artifact, and historical tree roots.
|
|
554
|
-
*/
|
|
555
|
-
async function _PXEService_getSimulationParameters(execRequest) {
|
|
556
|
-
const contractAddress = execRequest.to ?? execRequest.origin;
|
|
557
|
-
const functionSelector = execRequest.selector ?? execRequest.functionSelector;
|
|
558
|
-
const functionArtifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, functionSelector);
|
|
559
|
-
const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, functionSelector);
|
|
560
|
-
return {
|
|
561
|
-
contractAddress,
|
|
562
|
-
functionArtifact: {
|
|
563
|
-
...functionArtifact,
|
|
564
|
-
debug,
|
|
565
|
-
},
|
|
566
|
-
};
|
|
567
|
-
}, _PXEService_executePrivate = async function _PXEService_executePrivate(txRequest, msgSender, scopes) {
|
|
568
|
-
// TODO - Pause syncing while simulating.
|
|
569
|
-
const { contractAddress, functionArtifact } = await __classPrivateFieldGet(this, _PXEService_instances, "m", _PXEService_getSimulationParameters).call(this, txRequest);
|
|
570
|
-
try {
|
|
571
|
-
const result = await this.simulator.run(txRequest, functionArtifact, contractAddress, msgSender, scopes);
|
|
572
|
-
this.log.debug(`Private simulation completed for ${contractAddress.toString()}:${functionArtifact.name}`);
|
|
573
|
-
return result;
|
|
574
|
-
}
|
|
575
|
-
catch (err) {
|
|
576
|
-
if (err instanceof SimulationError) {
|
|
577
|
-
await enrichSimulationError(err, this.db, this.log);
|
|
578
|
-
}
|
|
579
|
-
throw err;
|
|
580
|
-
}
|
|
581
|
-
}, _PXEService_simulateUnconstrained =
|
|
582
|
-
/**
|
|
583
|
-
* Simulate an unconstrained transaction on the given contract, without considering constraints set by ACIR.
|
|
584
|
-
* The simulation parameters are fetched using ContractDataOracle and executed using AcirSimulator.
|
|
585
|
-
* Returns the simulation result containing the outputs of the unconstrained function.
|
|
586
|
-
*
|
|
587
|
-
* @param execRequest - The transaction request object containing the target contract and function data.
|
|
588
|
-
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
|
|
589
|
-
* @returns The simulation result containing the outputs of the unconstrained function.
|
|
590
|
-
*/
|
|
591
|
-
async function _PXEService_simulateUnconstrained(execRequest, scopes) {
|
|
592
|
-
const { contractAddress, functionArtifact } = await __classPrivateFieldGet(this, _PXEService_instances, "m", _PXEService_getSimulationParameters).call(this, execRequest);
|
|
593
|
-
this.log.debug('Executing unconstrained simulator...');
|
|
594
|
-
try {
|
|
595
|
-
const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress, scopes);
|
|
596
|
-
this.log.verbose(`Unconstrained simulation for ${contractAddress}.${functionArtifact.name} completed`);
|
|
597
|
-
return result;
|
|
598
|
-
}
|
|
599
|
-
catch (err) {
|
|
600
|
-
if (err instanceof SimulationError) {
|
|
601
|
-
await enrichSimulationError(err, this.db, this.log);
|
|
602
|
-
}
|
|
603
|
-
throw err;
|
|
604
|
-
}
|
|
605
|
-
}, _PXEService_simulatePublicCalls =
|
|
606
|
-
/**
|
|
607
|
-
* Simulate the public part of a transaction.
|
|
608
|
-
* This allows to catch public execution errors before submitting the transaction.
|
|
609
|
-
* It can also be used for estimating gas in the future.
|
|
610
|
-
* @param tx - The transaction to be simulated.
|
|
611
|
-
*/
|
|
612
|
-
async function _PXEService_simulatePublicCalls(tx, enforceFeePayment) {
|
|
613
|
-
// Simulating public calls can throw if the TX fails in a phase that doesn't allow reverts (setup)
|
|
614
|
-
// Or return as reverted if it fails in a phase that allows reverts (app logic, teardown)
|
|
615
|
-
try {
|
|
616
|
-
const result = await this.node.simulatePublicCalls(tx, enforceFeePayment);
|
|
617
|
-
if (result.revertReason) {
|
|
618
|
-
throw result.revertReason;
|
|
619
|
-
}
|
|
620
|
-
return result;
|
|
621
|
-
}
|
|
622
|
-
catch (err) {
|
|
623
|
-
if (err instanceof SimulationError) {
|
|
624
|
-
try {
|
|
625
|
-
await enrichPublicSimulationError(err, this.contractDataOracle, this.db, this.log);
|
|
626
|
-
}
|
|
627
|
-
catch (enrichErr) {
|
|
628
|
-
this.log.error(`Failed to enrich public simulation error: ${enrichErr}`);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
throw err;
|
|
632
|
-
}
|
|
633
|
-
}, _PXEService_prove =
|
|
634
|
-
/**
|
|
635
|
-
* Generate a kernel proof, and create a private kernel output.
|
|
636
|
-
* The function takes in a transaction execution request, and the result of private execution
|
|
637
|
-
* and then generates a kernel proof.
|
|
638
|
-
*
|
|
639
|
-
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
640
|
-
* @param proofCreator - The proof creator to use for proving the execution.
|
|
641
|
-
* @param privateExecutionResult - The result of the private execution
|
|
642
|
-
* @returns An object that contains the output of the kernel execution, including the ClientIvcProof if proving is enabled.
|
|
643
|
-
*/
|
|
644
|
-
async function _PXEService_prove(txExecutionRequest, proofCreator, privateExecutionResult, { simulate, profile, dryRun }) {
|
|
645
|
-
// use the block the tx was simulated against
|
|
646
|
-
const block = privateExecutionResult.entrypoint.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
|
|
647
|
-
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block);
|
|
648
|
-
const kernelProver = new KernelProver(kernelOracle, proofCreator, !this.proverEnabled);
|
|
649
|
-
this.log.debug(`Executing kernel prover (simulate: ${simulate}, profile: ${profile}, dryRun: ${dryRun})...`);
|
|
650
|
-
return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, {
|
|
651
|
-
simulate,
|
|
652
|
-
profile,
|
|
653
|
-
dryRun,
|
|
654
|
-
});
|
|
655
|
-
}, _PXEService_isContractClassPubliclyRegistered = async function _PXEService_isContractClassPubliclyRegistered(id) {
|
|
656
|
-
return !!(await this.node.getContractClass(id));
|
|
657
|
-
}, _PXEService_isContractPubliclyDeployed = async function _PXEService_isContractPubliclyDeployed(address) {
|
|
658
|
-
return !!(await this.node.getContract(address));
|
|
659
|
-
}, _PXEService_isContractInitialized = async function _PXEService_isContractInitialized(address) {
|
|
660
|
-
const initNullifier = await siloNullifier(address, address.toField());
|
|
661
|
-
return !!(await this.node.getNullifierMembershipWitness('latest', initNullifier));
|
|
662
|
-
};
|
|
663
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHhlX3NlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHhlX3NlcnZpY2UvcHhlX3NlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxPQUFPLEVBR0wsYUFBYSxFQU9iLGNBQWMsRUFHZCxZQUFZLEVBT1osdUJBQXVCLEVBR3ZCLGVBQWUsRUFLZixlQUFlLEVBRWYsa0JBQWtCLEVBQ2xCLFVBQVUsRUFDVixtQ0FBbUMsR0FDcEMsTUFBTSxzQkFBc0IsQ0FBQztBQVc5QixPQUFPLEVBQ0wsa0NBQWtDLEVBQ2xDLHNCQUFzQixFQUN0Qiw0QkFBNEIsR0FDN0IsTUFBTSw2QkFBNkIsQ0FBQztBQUNyQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDOUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDL0QsT0FBTyxFQUdMLGFBQWEsRUFDYixnQkFBZ0IsRUFDaEIsWUFBWSxFQUNaLHVCQUF1QixFQUN2QixlQUFlLEdBQ2hCLE1BQU0sdUJBQXVCLENBQUM7QUFFL0IsT0FBTyxFQUFFLEVBQUUsRUFBYyxNQUFNLDBCQUEwQixDQUFDO0FBQzFELE9BQU8sRUFBZSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFHaEQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLHFCQUFxQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0YsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFHaEYsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUcvQixPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDM0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFFdEUsT0FBTyxFQUFFLE9B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
|