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