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