@aztec/pxe 0.76.4 → 0.77.0-testnet-ignition.21
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 -6
- package/dest/kernel_prover/kernel_prover.d.ts.map +1 -1
- package/dest/kernel_prover/kernel_prover.js +98 -81
- 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 +279 -333
- 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 +18 -19
- 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 +89 -69
- 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 +121 -224
- 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,18 @@ 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,
|
|
262
|
-
|
|
263
|
-
|
|
249
|
+
skipFeeEnforcement: false,
|
|
250
|
+
profile: false
|
|
264
251
|
});
|
|
265
252
|
return new TxProvingResult(privateExecutionResult, publicInputs, clientIvcProof);
|
|
266
|
-
}
|
|
267
|
-
catch (err) {
|
|
253
|
+
} catch (err) {
|
|
268
254
|
throw this.contextualizeError(err, inspect(txRequest), inspect(privateExecutionResult));
|
|
269
255
|
}
|
|
270
256
|
}
|
|
271
257
|
// TODO(#7456) Prevent msgSender being defined here for the first call
|
|
272
|
-
async simulateTx(txRequest, simulatePublic, msgSender = undefined, skipTxValidation = false,
|
|
258
|
+
async simulateTx(txRequest, simulatePublic, msgSender = undefined, skipTxValidation = false, skipFeeEnforcement = false, profile = false, scopes) {
|
|
273
259
|
try {
|
|
274
260
|
const txInfo = {
|
|
275
261
|
origin: txRequest.origin,
|
|
@@ -278,25 +264,29 @@ export class PXEService {
|
|
|
278
264
|
msgSender,
|
|
279
265
|
chainId: txRequest.txContext.chainId,
|
|
280
266
|
version: txRequest.txContext.version,
|
|
281
|
-
authWitnesses: txRequest.authWitnesses.map(w
|
|
267
|
+
authWitnesses: txRequest.authWitnesses.map((w)=>w.requestHash)
|
|
282
268
|
};
|
|
283
269
|
this.log.info(`Simulating transaction execution request to ${txRequest.functionSelector} at ${txRequest.origin}`, txInfo);
|
|
284
270
|
const timer = new Timer();
|
|
285
271
|
await this.synchronizer.sync();
|
|
286
|
-
const privateExecutionResult = await
|
|
287
|
-
const { publicInputs, profileResult } = await
|
|
272
|
+
const privateExecutionResult = await this.#executePrivate(txRequest, msgSender, scopes);
|
|
273
|
+
const { publicInputs, profileResult } = await this.#prove(txRequest, this.proofCreator, privateExecutionResult, {
|
|
288
274
|
simulate: !profile,
|
|
289
|
-
|
|
290
|
-
|
|
275
|
+
skipFeeEnforcement,
|
|
276
|
+
profile
|
|
291
277
|
});
|
|
292
278
|
const privateSimulationResult = new PrivateSimulationResult(privateExecutionResult, publicInputs);
|
|
293
279
|
const simulatedTx = privateSimulationResult.toSimulatedTx();
|
|
294
280
|
let publicOutput;
|
|
295
|
-
if (simulatePublic) {
|
|
296
|
-
publicOutput = await
|
|
281
|
+
if (simulatePublic && publicInputs.forPublic) {
|
|
282
|
+
publicOutput = await this.#simulatePublicCalls(simulatedTx, skipFeeEnforcement);
|
|
297
283
|
}
|
|
298
284
|
if (!skipTxValidation) {
|
|
299
|
-
|
|
285
|
+
const validationResult = await this.node.isValidTx(simulatedTx, {
|
|
286
|
+
isSimulation: true,
|
|
287
|
+
skipFeeEnforcement
|
|
288
|
+
});
|
|
289
|
+
if (validationResult.result === 'invalid') {
|
|
300
290
|
throw new Error('The simulated transaction is unable to be added to state and is invalid.');
|
|
301
291
|
}
|
|
302
292
|
}
|
|
@@ -304,19 +294,18 @@ export class PXEService {
|
|
|
304
294
|
this.log.info(`Simulation completed for ${txHash.toString()} in ${timer.ms()}ms`, {
|
|
305
295
|
txHash,
|
|
306
296
|
...txInfo,
|
|
307
|
-
...
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
297
|
+
...profileResult ? {
|
|
298
|
+
gateCounts: profileResult.gateCounts
|
|
299
|
+
} : {},
|
|
300
|
+
...publicOutput ? {
|
|
301
|
+
gasUsed: publicOutput.gasUsed,
|
|
302
|
+
revertCode: publicOutput.txEffect.revertCode.getCode(),
|
|
303
|
+
revertReason: publicOutput.revertReason
|
|
304
|
+
} : {}
|
|
315
305
|
});
|
|
316
306
|
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'}`);
|
|
307
|
+
} catch (err) {
|
|
308
|
+
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
309
|
}
|
|
321
310
|
}
|
|
322
311
|
async sendTx(tx) {
|
|
@@ -325,7 +314,7 @@ export class PXEService {
|
|
|
325
314
|
throw new Error(`A settled tx with equal hash ${txHash.toString()} exists.`);
|
|
326
315
|
}
|
|
327
316
|
this.log.debug(`Sending transaction ${txHash}`);
|
|
328
|
-
await this.node.sendTx(tx).catch(err
|
|
317
|
+
await this.node.sendTx(tx).catch((err)=>{
|
|
329
318
|
throw this.contextualizeError(err, inspect(tx));
|
|
330
319
|
});
|
|
331
320
|
this.log.info(`Sent transaction ${txHash}`);
|
|
@@ -335,14 +324,13 @@ export class PXEService {
|
|
|
335
324
|
try {
|
|
336
325
|
await this.synchronizer.sync();
|
|
337
326
|
// TODO - Should check if `from` has the permission to call the view function.
|
|
338
|
-
const functionCall = await
|
|
339
|
-
const executionResult = await
|
|
327
|
+
const functionCall = await this.#getFunctionCall(functionName, args, to);
|
|
328
|
+
const executionResult = await this.#simulateUnconstrained(functionCall, scopes);
|
|
340
329
|
// TODO - Return typed result based on the function artifact.
|
|
341
330
|
return executionResult;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
throw this.contextualizeError(err, `simulateUnconstrained ${to}:${functionName}(${stringifiedArgs})`, `scopes=${scopes?.map(s => s.toString()).join(', ') ?? 'undefined'}`);
|
|
331
|
+
} catch (err) {
|
|
332
|
+
const stringifiedArgs = args.map((arg)=>arg.toString()).join(', ');
|
|
333
|
+
throw this.contextualizeError(err, `simulateUnconstrained ${to}:${functionName}(${stringifiedArgs})`, `scopes=${scopes?.map((s)=>s.toString()).join(', ') ?? 'undefined'}`);
|
|
346
334
|
}
|
|
347
335
|
}
|
|
348
336
|
getTxReceipt(txHash) {
|
|
@@ -358,21 +346,38 @@ export class PXEService {
|
|
|
358
346
|
return await this.node.getProvenBlockNumber();
|
|
359
347
|
}
|
|
360
348
|
/**
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
getPublicLogs(filter) {
|
|
349
|
+
* Gets public logs based on the provided filter.
|
|
350
|
+
* @param filter - The filter to apply to the logs.
|
|
351
|
+
* @returns The requested logs.
|
|
352
|
+
*/ getPublicLogs(filter) {
|
|
366
353
|
return this.node.getPublicLogs(filter);
|
|
367
354
|
}
|
|
368
355
|
/**
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
getContractClassLogs(filter) {
|
|
356
|
+
* Gets contract class logs based on the provided filter.
|
|
357
|
+
* @param filter - The filter to apply to the logs.
|
|
358
|
+
* @returns The requested logs.
|
|
359
|
+
*/ getContractClassLogs(filter) {
|
|
374
360
|
return this.node.getContractClassLogs(filter);
|
|
375
361
|
}
|
|
362
|
+
async #getFunctionCall(functionName, args, to) {
|
|
363
|
+
const contract = await this.db.getContract(to);
|
|
364
|
+
if (!contract) {
|
|
365
|
+
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`);
|
|
366
|
+
}
|
|
367
|
+
const functionDao = contract.functions.find((f)=>f.name === functionName);
|
|
368
|
+
if (!functionDao) {
|
|
369
|
+
throw new Error(`Unknown function ${functionName} in contract ${contract.name}.`);
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
name: functionDao.name,
|
|
373
|
+
args: encodeArguments(functionDao, args),
|
|
374
|
+
selector: await FunctionSelector.fromNameAndParameters(functionDao.name, functionDao.parameters),
|
|
375
|
+
type: functionDao.functionType,
|
|
376
|
+
to,
|
|
377
|
+
isStatic: functionDao.isStatic,
|
|
378
|
+
returnTypes: functionDao.returnTypes
|
|
379
|
+
};
|
|
380
|
+
}
|
|
376
381
|
async getNodeInfo() {
|
|
377
382
|
const [nodeVersion, protocolVersion, chainId, enr, contractAddresses, protocolContractAddresses] = await Promise.all([
|
|
378
383
|
this.node.getNodeVersion(),
|
|
@@ -380,7 +385,7 @@ export class PXEService {
|
|
|
380
385
|
this.node.getChainId(),
|
|
381
386
|
this.node.getEncodedEnr(),
|
|
382
387
|
this.node.getL1ContractAddresses(),
|
|
383
|
-
this.node.getProtocolContractAddresses()
|
|
388
|
+
this.node.getProtocolContractAddresses()
|
|
384
389
|
]);
|
|
385
390
|
const nodeInfo = {
|
|
386
391
|
nodeVersion,
|
|
@@ -388,7 +393,7 @@ export class PXEService {
|
|
|
388
393
|
protocolVersion,
|
|
389
394
|
enr,
|
|
390
395
|
l1ContractAddresses: contractAddresses,
|
|
391
|
-
protocolContractAddresses: protocolContractAddresses
|
|
396
|
+
protocolContractAddresses: protocolContractAddresses
|
|
392
397
|
};
|
|
393
398
|
return nodeInfo;
|
|
394
399
|
}
|
|
@@ -399,25 +404,140 @@ export class PXEService {
|
|
|
399
404
|
classRegisterer: ProtocolContractAddress.ContractClassRegisterer,
|
|
400
405
|
feeJuice: ProtocolContractAddress.FeeJuice,
|
|
401
406
|
instanceDeployer: ProtocolContractAddress.ContractInstanceDeployer,
|
|
402
|
-
multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint
|
|
403
|
-
}
|
|
407
|
+
multiCallEntrypoint: ProtocolContractAddress.MultiCallEntrypoint
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
async #registerProtocolContracts() {
|
|
412
|
+
const registered = {};
|
|
413
|
+
for (const name of protocolContractNames){
|
|
414
|
+
const { address, contractClass, instance, artifact } = await this.protocolContractsProvider.getProtocolContractArtifact(name);
|
|
415
|
+
await this.db.addContractArtifact(contractClass.id, artifact);
|
|
416
|
+
await this.db.addContractInstance(instance);
|
|
417
|
+
registered[name] = address.toString();
|
|
418
|
+
}
|
|
419
|
+
this.log.verbose(`Registered protocol contracts in pxe`, registered);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Retrieves the simulation parameters required to run an ACIR simulation.
|
|
423
|
+
* This includes the contract address, function artifact, and historical tree roots.
|
|
424
|
+
*
|
|
425
|
+
* @param execRequest - The transaction request object containing details of the contract call.
|
|
426
|
+
* @returns An object containing the contract address, function artifact, and historical tree roots.
|
|
427
|
+
*/ #getSimulationParameters(execRequest) {
|
|
428
|
+
const contractAddress = execRequest.to ?? execRequest.origin;
|
|
429
|
+
const functionSelector = execRequest.selector ?? execRequest.functionSelector;
|
|
430
|
+
return {
|
|
431
|
+
contractAddress,
|
|
432
|
+
functionSelector
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
async #executePrivate(txRequest, msgSender, scopes) {
|
|
436
|
+
// TODO - Pause syncing while simulating.
|
|
437
|
+
const { contractAddress, functionSelector } = this.#getSimulationParameters(txRequest);
|
|
438
|
+
try {
|
|
439
|
+
const result = await this.simulator.run(txRequest, contractAddress, functionSelector, msgSender, scopes);
|
|
440
|
+
this.log.debug(`Private simulation completed for ${contractAddress.toString()}:${functionSelector}`);
|
|
441
|
+
return result;
|
|
442
|
+
} catch (err) {
|
|
443
|
+
if (err instanceof SimulationError) {
|
|
444
|
+
await enrichSimulationError(err, this.db, this.log);
|
|
445
|
+
}
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Simulate an unconstrained transaction on the given contract, without considering constraints set by ACIR.
|
|
451
|
+
* The simulation parameters are fetched using ContractDataOracle and executed using AcirSimulator.
|
|
452
|
+
* Returns the simulation result containing the outputs of the unconstrained function.
|
|
453
|
+
*
|
|
454
|
+
* @param execRequest - The transaction request object containing the target contract and function data.
|
|
455
|
+
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
|
|
456
|
+
* @returns The simulation result containing the outputs of the unconstrained function.
|
|
457
|
+
*/ async #simulateUnconstrained(execRequest, scopes) {
|
|
458
|
+
const { contractAddress, functionSelector } = this.#getSimulationParameters(execRequest);
|
|
459
|
+
this.log.debug('Executing unconstrained simulator...');
|
|
460
|
+
try {
|
|
461
|
+
const result = await this.simulator.runUnconstrained(execRequest, contractAddress, functionSelector, scopes);
|
|
462
|
+
this.log.verbose(`Unconstrained simulation for ${contractAddress}.${functionSelector} completed`);
|
|
463
|
+
return result;
|
|
464
|
+
} catch (err) {
|
|
465
|
+
if (err instanceof SimulationError) {
|
|
466
|
+
await enrichSimulationError(err, this.db, this.log);
|
|
467
|
+
}
|
|
468
|
+
throw err;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Simulate the public part of a transaction.
|
|
473
|
+
* This allows to catch public execution errors before submitting the transaction.
|
|
474
|
+
* It can also be used for estimating gas in the future.
|
|
475
|
+
* @param tx - The transaction to be simulated.
|
|
476
|
+
*/ async #simulatePublicCalls(tx, skipFeeEnforcement) {
|
|
477
|
+
// Simulating public calls can throw if the TX fails in a phase that doesn't allow reverts (setup)
|
|
478
|
+
// Or return as reverted if it fails in a phase that allows reverts (app logic, teardown)
|
|
479
|
+
try {
|
|
480
|
+
const result = await this.node.simulatePublicCalls(tx, skipFeeEnforcement);
|
|
481
|
+
if (result.revertReason) {
|
|
482
|
+
throw result.revertReason;
|
|
483
|
+
}
|
|
484
|
+
return result;
|
|
485
|
+
} catch (err) {
|
|
486
|
+
if (err instanceof SimulationError) {
|
|
487
|
+
try {
|
|
488
|
+
await enrichPublicSimulationError(err, this.contractDataOracle, this.db, this.log);
|
|
489
|
+
} catch (enrichErr) {
|
|
490
|
+
this.log.error(`Failed to enrich public simulation error: ${enrichErr}`);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Generate a kernel proof, and create a private kernel output.
|
|
498
|
+
* The function takes in a transaction execution request, and the result of private execution
|
|
499
|
+
* and then generates a kernel proof.
|
|
500
|
+
*
|
|
501
|
+
* @param txExecutionRequest - The transaction request to be simulated and proved.
|
|
502
|
+
* @param proofCreator - The proof creator to use for proving the execution.
|
|
503
|
+
* @param privateExecutionResult - The result of the private execution
|
|
504
|
+
* @returns An object that contains the output of the kernel execution, including the ClientIvcProof if proving is enabled.
|
|
505
|
+
*/ async #prove(txExecutionRequest, proofCreator, privateExecutionResult, { simulate, skipFeeEnforcement, profile }) {
|
|
506
|
+
// use the block the tx was simulated against
|
|
507
|
+
const block = privateExecutionResult.entrypoint.publicInputs.historicalHeader.globalVariables.blockNumber.toNumber();
|
|
508
|
+
const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node, block);
|
|
509
|
+
const kernelProver = new KernelProver(kernelOracle, proofCreator, !this.proverEnabled);
|
|
510
|
+
this.log.debug(`Executing kernel prover (simulate: ${simulate}, profile: ${profile})...`);
|
|
511
|
+
return await kernelProver.prove(txExecutionRequest.toTxRequest(), privateExecutionResult, {
|
|
512
|
+
simulate,
|
|
513
|
+
skipFeeEnforcement,
|
|
514
|
+
profile
|
|
404
515
|
});
|
|
405
516
|
}
|
|
406
|
-
async
|
|
407
|
-
|
|
517
|
+
async #isContractClassPubliclyRegistered(id) {
|
|
518
|
+
return !!await this.node.getContractClass(id);
|
|
519
|
+
}
|
|
520
|
+
async #isContractPubliclyDeployed(address) {
|
|
521
|
+
return !!await this.node.getContract(address);
|
|
522
|
+
}
|
|
523
|
+
async #isContractInitialized(address) {
|
|
524
|
+
const initNullifier = await siloNullifier(address, address.toField());
|
|
525
|
+
return !!await this.node.getNullifierMembershipWitness('latest', initNullifier);
|
|
526
|
+
}
|
|
527
|
+
async getPrivateEvents(eventMetadataDef, from, limit, // TODO (#9272): Make this better, we should be able to only pass an address now
|
|
408
528
|
vpks) {
|
|
409
529
|
const eventMetadata = new EventMetadata(eventMetadataDef);
|
|
410
530
|
if (vpks.length === 0) {
|
|
411
531
|
throw new Error('Tried to get encrypted events without supplying any viewing public keys');
|
|
412
532
|
}
|
|
413
533
|
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)
|
|
534
|
+
const txEffects = blocks.flatMap((block)=>block.body.txEffects);
|
|
535
|
+
const privateLogs = txEffects.flatMap((txEffect)=>txEffect.privateLogs);
|
|
536
|
+
const vsks = await Promise.all(vpks.map(async (vpk)=>{
|
|
417
537
|
const [keyPrefix, account] = await this.keyStore.getKeyPrefixAndAccount(vpk);
|
|
418
538
|
let secretKey = await this.keyStore.getMasterSecretKey(vpk);
|
|
419
539
|
if (keyPrefix === 'iv') {
|
|
420
|
-
const registeredAccount = (await this.getRegisteredAccounts()).find(completeAddress
|
|
540
|
+
const registeredAccount = (await this.getRegisteredAccounts()).find((completeAddress)=>completeAddress.address.equals(account));
|
|
421
541
|
if (!registeredAccount) {
|
|
422
542
|
throw new Error('No registered account');
|
|
423
543
|
}
|
|
@@ -426,19 +546,20 @@ export class PXEService {
|
|
|
426
546
|
}
|
|
427
547
|
return secretKey;
|
|
428
548
|
}));
|
|
429
|
-
const visibleEvents = (await Promise.all(privateLogs.map(async (log)
|
|
430
|
-
for (const sk of vsks)
|
|
549
|
+
const visibleEvents = (await Promise.all(privateLogs.map(async (log)=>{
|
|
550
|
+
for (const sk of vsks){
|
|
431
551
|
// TODO: Verify that the first field of the log is the tag siloed with contract address.
|
|
432
552
|
// Or use tags to query logs, like we do with notes.
|
|
433
553
|
const decryptedEvent = await L1EventPayload.decryptAsIncoming(log, sk);
|
|
434
554
|
if (decryptedEvent !== undefined) {
|
|
435
|
-
return [
|
|
555
|
+
return [
|
|
556
|
+
decryptedEvent
|
|
557
|
+
];
|
|
436
558
|
}
|
|
437
559
|
}
|
|
438
560
|
return [];
|
|
439
561
|
}))).flat();
|
|
440
|
-
const decodedEvents = visibleEvents
|
|
441
|
-
.map(visibleEvent => {
|
|
562
|
+
const decodedEvents = visibleEvents.map((visibleEvent)=>{
|
|
442
563
|
if (visibleEvent === undefined) {
|
|
443
564
|
return undefined;
|
|
444
565
|
}
|
|
@@ -446,18 +567,16 @@ export class PXEService {
|
|
|
446
567
|
return undefined;
|
|
447
568
|
}
|
|
448
569
|
return eventMetadata.decode(visibleEvent);
|
|
449
|
-
})
|
|
450
|
-
.filter(visibleEvent => visibleEvent !== undefined);
|
|
570
|
+
}).filter((visibleEvent)=>visibleEvent !== undefined);
|
|
451
571
|
return decodedEvents;
|
|
452
572
|
}
|
|
453
573
|
async getPublicEvents(eventMetadataDef, from, limit) {
|
|
454
574
|
const eventMetadata = new EventMetadata(eventMetadataDef);
|
|
455
575
|
const { logs } = await this.node.getPublicLogs({
|
|
456
576
|
fromBlock: from,
|
|
457
|
-
toBlock: from + limit
|
|
577
|
+
toBlock: from + limit
|
|
458
578
|
});
|
|
459
|
-
const decodedEvents = logs
|
|
460
|
-
.map(log => {
|
|
579
|
+
const decodedEvents = logs.map((log)=>{
|
|
461
580
|
// +1 for the event selector
|
|
462
581
|
const expectedLength = eventMetadata.fieldNames.length + 1;
|
|
463
582
|
const logFields = log.log.log.slice(0, expectedLength);
|
|
@@ -466,12 +585,11 @@ export class PXEService {
|
|
|
466
585
|
return undefined;
|
|
467
586
|
}
|
|
468
587
|
// If any of the remaining fields, are non-zero, the payload does match expected:
|
|
469
|
-
if (log.log.log.slice(expectedLength + 1).find(f
|
|
588
|
+
if (log.log.log.slice(expectedLength + 1).find((f)=>!f.isZero())) {
|
|
470
589
|
throw new Error('Something is weird here, we have matching EventSelectors, but the actual payload has mismatched length');
|
|
471
590
|
}
|
|
472
591
|
return eventMetadata.decode(log.log);
|
|
473
|
-
})
|
|
474
|
-
.filter(log => log !== undefined);
|
|
592
|
+
}).filter((log)=>log !== undefined);
|
|
475
593
|
return decodedEvents;
|
|
476
594
|
}
|
|
477
595
|
async resetNoteSyncData() {
|
|
@@ -484,182 +602,10 @@ export class PXEService {
|
|
|
484
602
|
}
|
|
485
603
|
if (err instanceof SimulationError) {
|
|
486
604
|
err.setAztecContext(contextStr);
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
605
|
+
} else {
|
|
489
606
|
this.log.error(err.name, err);
|
|
490
607
|
this.log.debug(contextStr);
|
|
491
608
|
}
|
|
492
609
|
return err;
|
|
493
610
|
}
|
|
494
611
|
}
|
|
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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
|