@aztec/txe 1.2.0 → 2.0.0-nightly.20250813
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/index.d.ts.map +1 -1
- package/dest/index.js +34 -33
- package/dest/oracle/txe_oracle.d.ts +52 -81
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +167 -408
- package/dest/state_machine/archiver.d.ts +4 -2
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +8 -0
- package/dest/state_machine/dummy_p2p_client.d.ts +6 -3
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +8 -0
- package/dest/state_machine/mock_epoch_cache.d.ts +4 -2
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +7 -1
- package/dest/txe_constants.d.ts +0 -1
- package/dest/txe_constants.d.ts.map +1 -1
- package/dest/txe_constants.js +0 -2
- package/dest/txe_service/txe_service.d.ts +82 -90
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +305 -361
- package/dest/util/txe_public_contract_data_source.js +1 -1
- package/package.json +16 -16
- package/src/index.ts +42 -35
- package/src/oracle/txe_oracle.ts +192 -551
- package/src/state_machine/archiver.ts +10 -2
- package/src/state_machine/dummy_p2p_client.ts +29 -3
- package/src/state_machine/mock_epoch_cache.ts +10 -2
- package/src/txe_constants.ts +0 -2
- package/src/txe_service/txe_service.ts +353 -480
- package/src/util/txe_public_contract_data_source.ts +1 -1
|
@@ -1,34 +1,29 @@
|
|
|
1
1
|
import { Body, L2Block, Note } from '@aztec/aztec.js';
|
|
2
|
-
import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT,
|
|
2
|
+
import { DEFAULT_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_CONTEXT_INPUTS_LENGTH } from '@aztec/constants';
|
|
3
3
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
4
|
-
import { Aes128, Schnorr
|
|
4
|
+
import { Aes128, Schnorr } from '@aztec/foundation/crypto';
|
|
5
5
|
import { Fr } from '@aztec/foundation/fields';
|
|
6
6
|
import { applyStringFormatting } from '@aztec/foundation/log';
|
|
7
|
-
import { TestDateProvider
|
|
7
|
+
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
8
8
|
import { KeyStore } from '@aztec/key-store';
|
|
9
9
|
import { AddressDataProvider, CapsuleDataProvider, NoteDataProvider, PXEOracleInterface, PrivateEventDataProvider, TaggingDataProvider, enrichPublicSimulationError } from '@aztec/pxe/server';
|
|
10
|
-
import { ExecutionNoteCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction,
|
|
10
|
+
import { ExecutionNoteCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult, pickNotes } from '@aztec/pxe/simulator';
|
|
11
11
|
import { WASMSimulator, extractCallStack, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
|
|
12
|
-
import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
|
|
13
12
|
import { ExecutionError, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, PublicTxSimulator, createSimulationError, resolveAssertionMessageFromError } from '@aztec/simulator/server';
|
|
14
13
|
import { FunctionSelector, FunctionType, countArgumentsSize } from '@aztec/stdlib/abi';
|
|
15
14
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
16
15
|
import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
17
16
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
18
|
-
import { SimulationError } from '@aztec/stdlib/errors';
|
|
19
17
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
20
18
|
import { computeCalldataHash, computeNoteHashNonce, computePublicDataTreeLeafSlot, computeUniqueNoteHash, computeVarArgsHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash';
|
|
21
|
-
import { PartialPrivateTailPublicInputsForPublic, PrivateContextInputs, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest
|
|
22
|
-
import { deriveKeys } from '@aztec/stdlib/keys';
|
|
23
|
-
import { PrivateLog } from '@aztec/stdlib/logs';
|
|
24
|
-
import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
|
|
19
|
+
import { PartialPrivateTailPublicInputsForPublic, PrivateContextInputs, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
25
20
|
import { ClientIvcProof } from '@aztec/stdlib/proofs';
|
|
26
21
|
import { makeAppendOnlyTreeSnapshot, makeContentCommitment, makeGlobalVariables, makeHeader } from '@aztec/stdlib/testing';
|
|
27
|
-
import { AppendOnlyTreeSnapshot, MerkleTreeId,
|
|
28
|
-
import { BlockHeader, CallContext,
|
|
22
|
+
import { AppendOnlyTreeSnapshot, MerkleTreeId, PublicDataTreeLeaf } from '@aztec/stdlib/trees';
|
|
23
|
+
import { BlockHeader, CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
29
24
|
import { ForkCheckpoint } from '@aztec/world-state/native';
|
|
30
25
|
import { TXEStateMachine } from '../state_machine/index.js';
|
|
31
|
-
import {
|
|
26
|
+
import { GENESIS_TIMESTAMP } from '../txe_constants.js';
|
|
32
27
|
import { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
|
|
33
28
|
import { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
|
|
34
29
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
@@ -53,10 +48,6 @@ export class TXE {
|
|
|
53
48
|
sideEffectCounter;
|
|
54
49
|
msgSender;
|
|
55
50
|
functionSelector;
|
|
56
|
-
isStaticCall;
|
|
57
|
-
// Return/revert data of the latest nested call.
|
|
58
|
-
nestedCallReturndata;
|
|
59
|
-
nestedCallSuccess;
|
|
60
51
|
pxeOracleInterface;
|
|
61
52
|
publicDataWrites;
|
|
62
53
|
uniqueNoteHashesFromPublic;
|
|
@@ -70,6 +61,8 @@ export class TXE {
|
|
|
70
61
|
simulator;
|
|
71
62
|
noteCache;
|
|
72
63
|
authwits;
|
|
64
|
+
// Used by privateSetSenderForTags and privateGetSenderForTags oracles.
|
|
65
|
+
senderForTags;
|
|
73
66
|
constructor(logger, keyStore, contractDataProvider, noteDataProvider, capsuleDataProvider, syncDataProvider, taggingDataProvider, addressDataProvider, privateEventDataProvider, accountDataProvider, executionCache, contractAddress, nativeWorldStateService, baseFork, stateMachine){
|
|
74
67
|
this.logger = logger;
|
|
75
68
|
this.keyStore = keyStore;
|
|
@@ -90,9 +83,6 @@ export class TXE {
|
|
|
90
83
|
this.timestamp = GENESIS_TIMESTAMP;
|
|
91
84
|
this.sideEffectCounter = 0;
|
|
92
85
|
this.functionSelector = FunctionSelector.fromField(new Fr(0));
|
|
93
|
-
this.isStaticCall = false;
|
|
94
|
-
this.nestedCallReturndata = [];
|
|
95
|
-
this.nestedCallSuccess = false;
|
|
96
86
|
this.publicDataWrites = [];
|
|
97
87
|
this.uniqueNoteHashesFromPublic = [];
|
|
98
88
|
this.siloedNullifiersFromPublic = [];
|
|
@@ -137,38 +127,23 @@ export class TXE {
|
|
|
137
127
|
getBaseFork() {
|
|
138
128
|
return this.baseFork;
|
|
139
129
|
}
|
|
140
|
-
|
|
130
|
+
utilityGetChainId() {
|
|
141
131
|
return Promise.resolve(new Fr(this.CHAIN_ID));
|
|
142
132
|
}
|
|
143
|
-
|
|
133
|
+
utilityGetVersion() {
|
|
144
134
|
return Promise.resolve(new Fr(this.ROLLUP_VERSION));
|
|
145
135
|
}
|
|
146
136
|
getMsgSender() {
|
|
147
137
|
return this.msgSender;
|
|
148
138
|
}
|
|
149
|
-
|
|
150
|
-
return this.functionSelector;
|
|
151
|
-
}
|
|
152
|
-
setMsgSender(msgSender) {
|
|
153
|
-
this.msgSender = msgSender;
|
|
154
|
-
}
|
|
155
|
-
setFunctionSelector(functionSelector) {
|
|
156
|
-
this.functionSelector = functionSelector;
|
|
157
|
-
}
|
|
158
|
-
getSideEffectsCounter() {
|
|
159
|
-
return this.sideEffectCounter;
|
|
160
|
-
}
|
|
161
|
-
setSideEffectsCounter(sideEffectsCounter) {
|
|
162
|
-
this.sideEffectCounter = sideEffectsCounter;
|
|
163
|
-
}
|
|
164
|
-
setContractAddress(contractAddress) {
|
|
139
|
+
txeSetContractAddress(contractAddress) {
|
|
165
140
|
this.contractAddress = contractAddress;
|
|
166
141
|
}
|
|
167
142
|
// TODO: Currently this is only ever used to increment this.blockNumber by 1. Refactor this as `advanceBlock()`.
|
|
168
143
|
setBlockNumber(blockNumber) {
|
|
169
144
|
this.blockNumber = blockNumber;
|
|
170
145
|
}
|
|
171
|
-
|
|
146
|
+
txeAdvanceTimestampBy(duration) {
|
|
172
147
|
this.timestamp = this.timestamp + duration;
|
|
173
148
|
}
|
|
174
149
|
getContractDataProvider() {
|
|
@@ -189,11 +164,10 @@ export class TXE {
|
|
|
189
164
|
async addContractArtifact(contractClassId, artifact) {
|
|
190
165
|
await this.contractDataProvider.addContractArtifact(contractClassId, artifact);
|
|
191
166
|
}
|
|
192
|
-
async
|
|
167
|
+
async txeGetPrivateContextInputs(blockNumber, sideEffectsCounter = this.sideEffectCounter, isStaticCall = false) {
|
|
193
168
|
// If blockNumber or timestamp is null, use the values corresponding to the latest historical block (number of
|
|
194
169
|
// the block being built - 1)
|
|
195
170
|
blockNumber = blockNumber ?? this.blockNumber - 1;
|
|
196
|
-
timestamp = timestamp ?? this.timestamp - AZTEC_SLOT_DURATION;
|
|
197
171
|
const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
|
|
198
172
|
const previousBlockState = this.nativeWorldStateService.getSnapshot(blockNumber - 1);
|
|
199
173
|
const stateReference = await snap.getStateReference();
|
|
@@ -201,17 +175,14 @@ export class TXE {
|
|
|
201
175
|
inputs.txContext.chainId = new Fr(this.CHAIN_ID);
|
|
202
176
|
inputs.txContext.version = new Fr(this.ROLLUP_VERSION);
|
|
203
177
|
inputs.historicalHeader.globalVariables.blockNumber = blockNumber;
|
|
204
|
-
inputs.historicalHeader.globalVariables.timestamp =
|
|
178
|
+
inputs.historicalHeader.globalVariables.timestamp = await this.getBlockTimestamp(blockNumber);
|
|
205
179
|
inputs.historicalHeader.state = stateReference;
|
|
206
180
|
inputs.historicalHeader.lastArchive.root = Fr.fromBuffer((await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root);
|
|
207
181
|
inputs.callContext = new CallContext(this.msgSender, this.contractAddress, this.functionSelector, isStaticCall);
|
|
208
182
|
inputs.startSideEffectCounter = sideEffectsCounter;
|
|
209
183
|
return inputs;
|
|
210
184
|
}
|
|
211
|
-
|
|
212
|
-
return deriveKeys(secret);
|
|
213
|
-
}
|
|
214
|
-
async addAuthWitness(address, messageHash) {
|
|
185
|
+
async txeAddAuthWitness(address, messageHash) {
|
|
215
186
|
const account = await this.accountDataProvider.getAccount(address);
|
|
216
187
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
217
188
|
const schnorr = new Schnorr();
|
|
@@ -239,139 +210,61 @@ export class TXE {
|
|
|
239
210
|
addUniqueNoteHashesFromPublic(siloedNoteHashes) {
|
|
240
211
|
this.uniqueNoteHashesFromPublic.push(...siloedNoteHashes);
|
|
241
212
|
}
|
|
242
|
-
async addPrivateLogs(contractAddress, privateLogs) {
|
|
243
|
-
for (const privateLog of privateLogs){
|
|
244
|
-
privateLog.fields[0] = await poseidon2Hash([
|
|
245
|
-
contractAddress,
|
|
246
|
-
privateLog.fields[0]
|
|
247
|
-
]);
|
|
248
|
-
}
|
|
249
|
-
this.privateLogs.push(...privateLogs);
|
|
250
|
-
}
|
|
251
|
-
addPublicLogs(logs) {
|
|
252
|
-
logs.forEach((log)=>{
|
|
253
|
-
try {
|
|
254
|
-
const tag = log.fields[0];
|
|
255
|
-
this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
256
|
-
this.publicLogs.push(log);
|
|
257
|
-
} catch (err) {
|
|
258
|
-
this.logger.warn(`Failed to add tagged log to store: ${err}`);
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
213
|
// TypedOracle
|
|
263
|
-
|
|
214
|
+
utilityGetBlockNumber() {
|
|
264
215
|
return Promise.resolve(this.blockNumber);
|
|
265
216
|
}
|
|
266
|
-
|
|
217
|
+
utilityGetTimestamp() {
|
|
267
218
|
return Promise.resolve(this.timestamp);
|
|
268
219
|
}
|
|
269
|
-
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
setIsStaticCall(isStatic) {
|
|
273
|
-
this.isStaticCall = isStatic;
|
|
220
|
+
txeGetLastBlockTimestamp() {
|
|
221
|
+
return this.getBlockTimestamp(this.blockNumber - 1);
|
|
274
222
|
}
|
|
275
|
-
|
|
276
|
-
return this.
|
|
223
|
+
utilityGetContractAddress() {
|
|
224
|
+
return Promise.resolve(this.contractAddress);
|
|
277
225
|
}
|
|
278
|
-
|
|
226
|
+
utilityGetRandomField() {
|
|
279
227
|
return Fr.random();
|
|
280
228
|
}
|
|
281
|
-
|
|
229
|
+
privateStoreInExecutionCache(values, hash) {
|
|
282
230
|
return this.executionCache.store(values, hash);
|
|
283
231
|
}
|
|
284
|
-
|
|
232
|
+
privateLoadFromExecutionCache(hash) {
|
|
285
233
|
const preimage = this.executionCache.getPreimage(hash);
|
|
286
234
|
if (!preimage) {
|
|
287
235
|
throw new Error(`Preimage for hash ${hash.toString()} not found in cache`);
|
|
288
236
|
}
|
|
289
237
|
return Promise.resolve(preimage);
|
|
290
238
|
}
|
|
291
|
-
|
|
239
|
+
utilityGetKeyValidationRequest(pkMHash) {
|
|
292
240
|
return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress);
|
|
293
241
|
}
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (!contractInstance) {
|
|
297
|
-
throw new Error(`Contract instance not found for address ${address}`);
|
|
298
|
-
}
|
|
299
|
-
return contractInstance;
|
|
242
|
+
utilityGetContractInstance(address) {
|
|
243
|
+
return this.pxeOracleInterface.getContractInstance(address);
|
|
300
244
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
const index = (await snap.findLeafIndices(treeId, [
|
|
304
|
-
leafValue.toBuffer()
|
|
305
|
-
]))[0];
|
|
306
|
-
if (index === undefined) {
|
|
307
|
-
throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]} at block ${blockNumber}`);
|
|
308
|
-
}
|
|
309
|
-
const siblingPath = await snap.getSiblingPath(treeId, index);
|
|
310
|
-
return [
|
|
311
|
-
new Fr(index),
|
|
312
|
-
...siblingPath.toFields()
|
|
313
|
-
];
|
|
245
|
+
utilityGetMembershipWitness(blockNumber, treeId, leafValue) {
|
|
246
|
+
return this.pxeOracleInterface.getMembershipWitness(blockNumber, treeId, leafValue);
|
|
314
247
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const result = await snap.getSiblingPath(treeId, leafIndex.toBigInt());
|
|
318
|
-
return result.toFields();
|
|
248
|
+
utilityGetNullifierMembershipWitness(blockNumber, nullifier) {
|
|
249
|
+
return this.pxeOracleInterface.getNullifierMembershipWitness(blockNumber, nullifier);
|
|
319
250
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
|
|
323
|
-
nullifier.toBuffer()
|
|
324
|
-
]);
|
|
325
|
-
if (!index) {
|
|
326
|
-
return undefined;
|
|
327
|
-
}
|
|
328
|
-
const leafPreimagePromise = snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
|
|
329
|
-
const siblingPathPromise = snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
330
|
-
const [leafPreimage, siblingPath] = await Promise.all([
|
|
331
|
-
leafPreimagePromise,
|
|
332
|
-
siblingPathPromise
|
|
333
|
-
]);
|
|
334
|
-
if (!leafPreimage) {
|
|
335
|
-
return undefined;
|
|
336
|
-
}
|
|
337
|
-
return new NullifierMembershipWitness(BigInt(index), leafPreimage, siblingPath);
|
|
338
|
-
}
|
|
339
|
-
async getPublicDataWitness(blockNumber, leafSlot) {
|
|
340
|
-
const snap = this.nativeWorldStateService.getSnapshot(blockNumber);
|
|
341
|
-
const lowLeafResult = await snap.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
342
|
-
if (!lowLeafResult) {
|
|
343
|
-
return undefined;
|
|
344
|
-
} else {
|
|
345
|
-
const preimage = await snap.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
346
|
-
const path = await snap.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
347
|
-
return new PublicDataWitness(lowLeafResult.index, preimage, path);
|
|
348
|
-
}
|
|
251
|
+
utilityGetPublicDataWitness(blockNumber, leafSlot) {
|
|
252
|
+
return this.pxeOracleInterface.getPublicDataWitness(blockNumber, leafSlot);
|
|
349
253
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const findResult = await snap.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt());
|
|
353
|
-
if (!findResult) {
|
|
354
|
-
return undefined;
|
|
355
|
-
}
|
|
356
|
-
const { index, alreadyPresent } = findResult;
|
|
357
|
-
if (alreadyPresent) {
|
|
358
|
-
this.logger.warn(`Nullifier ${nullifier.toBigInt()} already exists in the tree`);
|
|
359
|
-
}
|
|
360
|
-
const preimageData = await snap.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index);
|
|
361
|
-
const siblingPath = await snap.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, BigInt(index));
|
|
362
|
-
return new NullifierMembershipWitness(BigInt(index), preimageData, siblingPath);
|
|
254
|
+
utilityGetLowNullifierMembershipWitness(blockNumber, nullifier) {
|
|
255
|
+
return this.pxeOracleInterface.getLowNullifierMembershipWitness(blockNumber, nullifier);
|
|
363
256
|
}
|
|
364
|
-
|
|
257
|
+
utilityGetBlockHeader(blockNumber) {
|
|
365
258
|
return this.stateMachine.archiver.getBlockHeader(blockNumber);
|
|
366
259
|
}
|
|
367
|
-
|
|
260
|
+
utilityGetCompleteAddress(account) {
|
|
368
261
|
return Promise.resolve(this.accountDataProvider.getAccount(account));
|
|
369
262
|
}
|
|
370
|
-
|
|
263
|
+
utilityGetAuthWitness(messageHash) {
|
|
371
264
|
const authwit = this.authwits.get(messageHash.toString());
|
|
372
265
|
return Promise.resolve(authwit?.witness);
|
|
373
266
|
}
|
|
374
|
-
async
|
|
267
|
+
async utilityGetNotes(storageSlot, numSelects, selectByIndexes, selectByOffsets, selectByLengths, selectValues, selectComparators, sortByIndexes, sortByOffsets, sortByLengths, sortOrder, limit, offset, status) {
|
|
375
268
|
// Nullified pending notes are already removed from the list.
|
|
376
269
|
const pendingNotes = this.noteCache.getNotes(this.contractAddress, storageSlot);
|
|
377
270
|
const pendingNullifiers = this.noteCache.getNullifiers(this.contractAddress);
|
|
@@ -404,7 +297,7 @@ export class TXE {
|
|
|
404
297
|
this.logger.debug(`Returning ${notes.length} notes for ${this.contractAddress} at ${storageSlot}: ${notes.map((n)=>`${n.noteNonce.toString()}:[${n.note.items.map((i)=>i.toString()).join(',')}]`).join(', ')}`);
|
|
405
298
|
return notes;
|
|
406
299
|
}
|
|
407
|
-
|
|
300
|
+
privateNotifyCreatedNote(storageSlot, _noteTypeId, noteItems, noteHash, counter) {
|
|
408
301
|
const note = new Note(noteItems);
|
|
409
302
|
this.noteCache.addNewNote({
|
|
410
303
|
contractAddress: this.contractAddress,
|
|
@@ -416,31 +309,32 @@ export class TXE {
|
|
|
416
309
|
}, counter);
|
|
417
310
|
this.sideEffectCounter = counter + 1;
|
|
418
311
|
}
|
|
419
|
-
async
|
|
312
|
+
async privateNotifyNullifiedNote(innerNullifier, noteHash, counter) {
|
|
420
313
|
await this.checkNullifiersNotInTree(this.contractAddress, [
|
|
421
314
|
innerNullifier
|
|
422
315
|
]);
|
|
423
316
|
await this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
|
|
424
317
|
this.sideEffectCounter = counter + 1;
|
|
425
318
|
}
|
|
426
|
-
async
|
|
319
|
+
async privateNotifyCreatedNullifier(innerNullifier) {
|
|
427
320
|
await this.checkNullifiersNotInTree(this.contractAddress, [
|
|
428
321
|
innerNullifier
|
|
429
322
|
]);
|
|
430
323
|
await this.noteCache.nullifierCreated(this.contractAddress, innerNullifier);
|
|
431
324
|
}
|
|
432
|
-
async
|
|
325
|
+
async utilityCheckNullifierExists(innerNullifier) {
|
|
433
326
|
const snap = this.nativeWorldStateService.getSnapshot(this.blockNumber - 1);
|
|
434
327
|
const nullifier = await siloNullifier(this.contractAddress, innerNullifier);
|
|
435
328
|
const [index] = await snap.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
|
|
436
329
|
nullifier.toBuffer()
|
|
437
330
|
]);
|
|
438
|
-
|
|
331
|
+
const inPendingCache = this.noteCache.getNullifiers(this.contractAddress).has(nullifier.toBigInt());
|
|
332
|
+
return index !== undefined || inPendingCache;
|
|
439
333
|
}
|
|
440
334
|
getL1ToL2MembershipWitness(_contractAddress, _messageHash, _secret) {
|
|
441
335
|
throw new Error('Method not implemented.');
|
|
442
336
|
}
|
|
443
|
-
async
|
|
337
|
+
async utilityStorageRead(contractAddress, startStorageSlot, blockNumber, numberOfElements) {
|
|
444
338
|
let db;
|
|
445
339
|
if (blockNumber === this.blockNumber) {
|
|
446
340
|
db = this.baseFork;
|
|
@@ -472,7 +366,7 @@ export class TXE {
|
|
|
472
366
|
return publicDataWrites.map((write)=>write.value);
|
|
473
367
|
}
|
|
474
368
|
async commitState() {
|
|
475
|
-
const blockNumber = await this.
|
|
369
|
+
const blockNumber = await this.utilityGetBlockNumber();
|
|
476
370
|
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
477
371
|
if (this.committedBlocks.has(blockNumber)) {
|
|
478
372
|
throw new Error('Already committed state');
|
|
@@ -524,7 +418,10 @@ export class TXE {
|
|
|
524
418
|
const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
525
419
|
const header = new BlockHeader(new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)), makeContentCommitment(), stateReference, makeGlobalVariables(), Fr.ZERO, Fr.ZERO);
|
|
526
420
|
header.globalVariables.blockNumber = blockNumber;
|
|
527
|
-
header.globalVariables.timestamp = await this.
|
|
421
|
+
header.globalVariables.timestamp = await this.utilityGetTimestamp();
|
|
422
|
+
header.globalVariables.version = new Fr(this.ROLLUP_VERSION);
|
|
423
|
+
header.globalVariables.chainId = new Fr(this.CHAIN_ID);
|
|
424
|
+
this.logger.info(`Created block ${blockNumber} with timestamp ${header.globalVariables.timestamp}`);
|
|
528
425
|
l2Block.header = header;
|
|
529
426
|
await fork.updateArchive(l2Block.header);
|
|
530
427
|
await this.stateMachine.handleL2Block(l2Block);
|
|
@@ -562,7 +459,7 @@ export class TXE {
|
|
|
562
459
|
contract: call.to,
|
|
563
460
|
selector: call.selector
|
|
564
461
|
});
|
|
565
|
-
const args = await this.
|
|
462
|
+
const args = await this.privateLoadFromExecutionCache(argsHash);
|
|
566
463
|
const initialWitness = toACVMWitness(0, args);
|
|
567
464
|
const acirExecutionResult = await this.simulator.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
|
|
568
465
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
@@ -576,69 +473,20 @@ export class TXE {
|
|
|
576
473
|
const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
|
|
577
474
|
this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
|
|
578
475
|
const returnHash = await computeVarArgsHash(returnWitness);
|
|
579
|
-
this.
|
|
476
|
+
this.privateStoreInExecutionCache(returnWitness, returnHash);
|
|
580
477
|
return returnHash;
|
|
581
478
|
} catch (err) {
|
|
582
479
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
583
480
|
}
|
|
584
481
|
}
|
|
585
|
-
async callPrivateFunction(targetContractAddress, functionSelector, argsHash, sideEffectCounter, isStaticCall) {
|
|
586
|
-
this.logger.verbose(`Executing external function ${await this.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
587
|
-
// Store and modify env
|
|
588
|
-
const currentContractAddress = this.contractAddress;
|
|
589
|
-
const currentMessageSender = this.msgSender;
|
|
590
|
-
const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
|
|
591
|
-
this.setMsgSender(this.contractAddress);
|
|
592
|
-
this.setContractAddress(targetContractAddress);
|
|
593
|
-
this.setFunctionSelector(functionSelector);
|
|
594
|
-
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
595
|
-
if (!artifact) {
|
|
596
|
-
throw new Error(`Artifact not found when calling private function. Contract address: ${targetContractAddress}.`);
|
|
597
|
-
}
|
|
598
|
-
const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
|
|
599
|
-
const acvmCallback = new Oracle(this);
|
|
600
|
-
const timer = new Timer();
|
|
601
|
-
const acirExecutionResult = await this.simulator.executeUserCircuit(initialWitness, artifact, acvmCallback.toACIRCallback()).catch((err)=>{
|
|
602
|
-
err.message = resolveAssertionMessageFromError(err, artifact);
|
|
603
|
-
const execError = new ExecutionError(err.message, {
|
|
604
|
-
contractAddress: targetContractAddress,
|
|
605
|
-
functionSelector
|
|
606
|
-
}, extractCallStack(err, artifact.debug), {
|
|
607
|
-
cause: err
|
|
608
|
-
});
|
|
609
|
-
this.logger.debug(`Error executing private function ${targetContractAddress}:${functionSelector}`);
|
|
610
|
-
throw createSimulationError(execError);
|
|
611
|
-
});
|
|
612
|
-
const duration = timer.ms();
|
|
613
|
-
const publicInputs = extractPrivateCircuitPublicInputs(artifact, acirExecutionResult.partialWitness);
|
|
614
|
-
const initialWitnessSize = witnessMapToFields(initialWitness).length * Fr.SIZE_IN_BYTES;
|
|
615
|
-
this.logger.debug(`Ran external function ${targetContractAddress.toString()}:${functionSelector}`, {
|
|
616
|
-
circuitName: 'app-circuit',
|
|
617
|
-
duration,
|
|
618
|
-
eventName: 'circuit-witness-generation',
|
|
619
|
-
inputSize: initialWitnessSize,
|
|
620
|
-
outputSize: publicInputs.toBuffer().length,
|
|
621
|
-
appCircuitName: 'noname'
|
|
622
|
-
});
|
|
623
|
-
// Apply side effects
|
|
624
|
-
const endSideEffectCounter = publicInputs.endSideEffectCounter;
|
|
625
|
-
this.sideEffectCounter = endSideEffectCounter.toNumber() + 1;
|
|
626
|
-
await this.addPrivateLogs(targetContractAddress, publicInputs.privateLogs.filter((privateLog)=>!privateLog.isEmpty()).map((privateLog)=>privateLog.log));
|
|
627
|
-
this.setContractAddress(currentContractAddress);
|
|
628
|
-
this.setMsgSender(currentMessageSender);
|
|
629
|
-
this.setFunctionSelector(currentFunctionSelector);
|
|
630
|
-
return {
|
|
631
|
-
endSideEffectCounter,
|
|
632
|
-
returnsHash: publicInputs.returnsHash
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
482
|
async getInitialWitness(abi, argsHash, sideEffectCounter, isStaticCall) {
|
|
636
483
|
const argumentsSize = countArgumentsSize(abi);
|
|
637
484
|
const args = this.executionCache.getPreimage(argsHash);
|
|
638
485
|
if (args?.length !== argumentsSize) {
|
|
639
486
|
throw new Error('Invalid arguments size');
|
|
640
487
|
}
|
|
641
|
-
const
|
|
488
|
+
const historicalBlockNumber = this.blockNumber - 1; // i.e. last
|
|
489
|
+
const privateContextInputs = await this.txeGetPrivateContextInputs(historicalBlockNumber, sideEffectCounter, isStaticCall);
|
|
642
490
|
const privateContextInputsAsFields = privateContextInputs.toFields();
|
|
643
491
|
if (privateContextInputsAsFields.length !== PRIVATE_CONTEXT_INPUTS_LENGTH) {
|
|
644
492
|
throw new Error('Invalid private context inputs size');
|
|
@@ -652,161 +500,36 @@ export class TXE {
|
|
|
652
500
|
async getDebugFunctionName(address, selector) {
|
|
653
501
|
return await this.contractDataProvider.getDebugFunctionName(address, selector);
|
|
654
502
|
}
|
|
655
|
-
|
|
656
|
-
const callRequest = await PublicCallRequest.fromCalldata(msgSender, contractAddress, isStaticCall, calldata);
|
|
657
|
-
const executionRequest = new PublicCallRequestWithCalldata(callRequest, calldata);
|
|
658
|
-
const db = this.baseFork;
|
|
659
|
-
const globalVariables = GlobalVariables.empty();
|
|
660
|
-
globalVariables.chainId = new Fr(this.CHAIN_ID);
|
|
661
|
-
globalVariables.version = new Fr(this.ROLLUP_VERSION);
|
|
662
|
-
globalVariables.blockNumber = this.blockNumber;
|
|
663
|
-
globalVariables.timestamp = this.timestamp;
|
|
664
|
-
globalVariables.gasFees = new GasFees(1, 1);
|
|
665
|
-
let result;
|
|
666
|
-
// Checkpoint here so that we can revert merkle ops after simulation.
|
|
667
|
-
// See note at revert below.
|
|
668
|
-
const checkpoint = await ForkCheckpoint.new(db);
|
|
669
|
-
try {
|
|
670
|
-
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
|
|
671
|
-
const simulator = new PublicTxSimulator(this.baseFork, contractsDB, globalVariables, /*doMerkleOperations=*/ false, /*skipFeeEnforcement=*/ false, /*clientInitiatedSimulation=*/ true);
|
|
672
|
-
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
673
|
-
const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
674
|
-
// When setting up a teardown call, we tell it that
|
|
675
|
-
// private execution used Gas(1, 1) so it can compute a tx fee.
|
|
676
|
-
const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty();
|
|
677
|
-
const tx = createTxForPublicCalls({
|
|
678
|
-
nonRevertible: {
|
|
679
|
-
nullifiers: [
|
|
680
|
-
firstNullifier
|
|
681
|
-
]
|
|
682
|
-
}
|
|
683
|
-
}, /*setupExecutionRequests=*/ [], /*appExecutionRequests=*/ isTeardown ? [] : [
|
|
684
|
-
executionRequest
|
|
685
|
-
], /*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined, /*feePayer=*/ AztecAddress.zero(), gasUsedByPrivate);
|
|
686
|
-
result = await simulator.simulate(tx);
|
|
687
|
-
} finally{
|
|
688
|
-
// NOTE: Don't accept any merkle updates from the AVM since this was just 1 enqueued call
|
|
689
|
-
// and the TXE will re-apply all txEffects after entire execution (all enqueued calls)
|
|
690
|
-
// complete.
|
|
691
|
-
await checkpoint.revert();
|
|
692
|
-
// If an error is thrown during the above simulation, this revert is the last
|
|
693
|
-
// thing executed and we skip the postprocessing below.
|
|
694
|
-
}
|
|
695
|
-
const noteHashes = result.avmProvingRequest.inputs.publicInputs.accumulatedData.noteHashes.filter((s)=>!s.isEmpty());
|
|
696
|
-
const publicDataWrites = result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicDataWrites.filter((s)=>!s.isEmpty());
|
|
697
|
-
// For now, public data writes are the only merkle operations that are readable by later enqueued calls in the TXE.
|
|
698
|
-
await this.addPublicDataWrites(publicDataWrites);
|
|
699
|
-
this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
700
|
-
this.addPublicLogs(result.avmProvingRequest.inputs.publicInputs.accumulatedData.publicLogs.filter((log)=>!log.contractAddress.equals(AztecAddress.ZERO)));
|
|
701
|
-
return Promise.resolve(result);
|
|
702
|
-
}
|
|
703
|
-
async notifyEnqueuedPublicFunctionCall(targetContractAddress, calldataHash, _sideEffectCounter, isStaticCall, isTeardown = false) {
|
|
704
|
-
// Store and modify env
|
|
705
|
-
const currentContractAddress = this.contractAddress;
|
|
706
|
-
const currentMessageSender = this.msgSender;
|
|
707
|
-
const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
|
|
708
|
-
const calldata = this.executionCache.getPreimage(calldataHash);
|
|
709
|
-
if (!calldata) {
|
|
710
|
-
throw new Error('Calldata for enqueued call not found in cache');
|
|
711
|
-
}
|
|
712
|
-
const functionSelector = FunctionSelector.fromField(calldata[0]);
|
|
713
|
-
this.setMsgSender(this.contractAddress);
|
|
714
|
-
this.setContractAddress(targetContractAddress);
|
|
715
|
-
this.setFunctionSelector(functionSelector);
|
|
716
|
-
const executionResult = await this.executePublicFunction(calldata, /* msgSender */ currentContractAddress, targetContractAddress, isStaticCall, isTeardown);
|
|
717
|
-
// Poor man's revert handling
|
|
718
|
-
if (!executionResult.revertCode.isOK()) {
|
|
719
|
-
if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) {
|
|
720
|
-
await enrichPublicSimulationError(executionResult.revertReason, this.contractDataProvider, this.logger);
|
|
721
|
-
throw new Error(executionResult.revertReason.message);
|
|
722
|
-
} else {
|
|
723
|
-
throw new Error(`Enqueued public function call reverted: ${executionResult.revertReason}`);
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
// Apply side effects
|
|
727
|
-
const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
|
|
728
|
-
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
729
|
-
const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
730
|
-
const nullifiers = sideEffects.nullifiers.filter((s)=>!s.isEmpty()).filter((s)=>!s.equals(firstNullifier));
|
|
731
|
-
// For some reason we cannot move this up to 'executePublicFunction'. It gives us an error of trying to modify the same nullifier twice.
|
|
732
|
-
this.addSiloedNullifiersFromPublic(nullifiers);
|
|
733
|
-
this.setContractAddress(currentContractAddress);
|
|
734
|
-
this.setMsgSender(currentMessageSender);
|
|
735
|
-
this.setFunctionSelector(currentFunctionSelector);
|
|
736
|
-
}
|
|
737
|
-
async notifySetPublicTeardownFunctionCall(targetContractAddress, calldataHash, sideEffectCounter, isStaticCall) {
|
|
738
|
-
// Definitely not right, in that the teardown should always be last.
|
|
739
|
-
// But useful for executing flows.
|
|
740
|
-
await this.notifyEnqueuedPublicFunctionCall(targetContractAddress, calldataHash, sideEffectCounter, isStaticCall, /*isTeardown=*/ true);
|
|
741
|
-
}
|
|
742
|
-
async notifySetMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter) {
|
|
743
|
-
await this.noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
|
|
744
|
-
}
|
|
745
|
-
debugLog(message, fields) {
|
|
503
|
+
utilityDebugLog(message, fields) {
|
|
746
504
|
this.logger.verbose(`${applyStringFormatting(message, fields)}`, {
|
|
747
505
|
module: `${this.logger.module}:debug_log`
|
|
748
506
|
});
|
|
749
507
|
}
|
|
750
|
-
async
|
|
508
|
+
async privateIncrementAppTaggingSecretIndexAsSender(sender, recipient) {
|
|
751
509
|
await this.pxeOracleInterface.incrementAppTaggingSecretIndexAsSender(this.contractAddress, sender, recipient);
|
|
752
510
|
}
|
|
753
|
-
async
|
|
511
|
+
async utilityGetIndexedTaggingSecretAsSender(sender, recipient) {
|
|
754
512
|
return await this.pxeOracleInterface.getIndexedTaggingSecretAsSender(this.contractAddress, sender, recipient);
|
|
755
513
|
}
|
|
756
|
-
async
|
|
514
|
+
async utilityFetchTaggedLogs(pendingTaggedLogArrayBaseSlot) {
|
|
757
515
|
await this.pxeOracleInterface.syncTaggedLogs(this.contractAddress, pendingTaggedLogArrayBaseSlot);
|
|
758
516
|
await this.pxeOracleInterface.removeNullifiedNotes(this.contractAddress);
|
|
759
517
|
return Promise.resolve();
|
|
760
518
|
}
|
|
761
|
-
async
|
|
519
|
+
async utilityValidateEnqueuedNotesAndEvents(contractAddress, noteValidationRequestsArrayBaseSlot, eventValidationRequestsArrayBaseSlot) {
|
|
762
520
|
await this.pxeOracleInterface.validateEnqueuedNotesAndEvents(contractAddress, noteValidationRequestsArrayBaseSlot, eventValidationRequestsArrayBaseSlot);
|
|
763
521
|
}
|
|
764
|
-
async
|
|
522
|
+
async utilityBulkRetrieveLogs(contractAddress, logRetrievalRequestsArrayBaseSlot, logRetrievalResponsesArrayBaseSlot) {
|
|
765
523
|
return await this.pxeOracleInterface.bulkRetrieveLogs(contractAddress, logRetrievalRequestsArrayBaseSlot, logRetrievalResponsesArrayBaseSlot);
|
|
766
524
|
}
|
|
767
|
-
// AVM oracles
|
|
768
|
-
async avmOpcodeCall(targetContractAddress, calldata, isStaticCall) {
|
|
769
|
-
// Store and modify env
|
|
770
|
-
const currentContractAddress = this.contractAddress;
|
|
771
|
-
const currentMessageSender = this.msgSender;
|
|
772
|
-
this.setMsgSender(this.contractAddress);
|
|
773
|
-
this.setContractAddress(targetContractAddress);
|
|
774
|
-
const executionResult = await this.executePublicFunction(calldata, /* msgSender */ currentContractAddress, targetContractAddress, isStaticCall);
|
|
775
|
-
// Save return/revert data for later.
|
|
776
|
-
this.nestedCallReturndata = executionResult.processedPhases[0].returnValues[0].values;
|
|
777
|
-
this.nestedCallSuccess = executionResult.revertCode.isOK();
|
|
778
|
-
// Apply side effects
|
|
779
|
-
if (executionResult.revertCode.isOK()) {
|
|
780
|
-
const sideEffects = executionResult.avmProvingRequest.inputs.publicInputs.accumulatedData;
|
|
781
|
-
const publicDataWrites = sideEffects.publicDataWrites.filter((s)=>!s.isEmpty());
|
|
782
|
-
const noteHashes = sideEffects.noteHashes.filter((s)=>!s.isEmpty());
|
|
783
|
-
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
784
|
-
const firstNullifier = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
785
|
-
const nullifiers = sideEffects.nullifiers.filter((s)=>!s.isEmpty()).filter((s)=>!s.equals(firstNullifier));
|
|
786
|
-
await this.addPublicDataWrites(publicDataWrites);
|
|
787
|
-
this.addUniqueNoteHashesFromPublic(noteHashes);
|
|
788
|
-
this.addSiloedNullifiersFromPublic(nullifiers);
|
|
789
|
-
}
|
|
790
|
-
this.setContractAddress(currentContractAddress);
|
|
791
|
-
this.setMsgSender(currentMessageSender);
|
|
792
|
-
return executionResult;
|
|
793
|
-
}
|
|
794
|
-
avmOpcodeSuccessCopy() {
|
|
795
|
-
return this.nestedCallSuccess;
|
|
796
|
-
}
|
|
797
|
-
avmOpcodeReturndataSize() {
|
|
798
|
-
return this.nestedCallReturndata.length;
|
|
799
|
-
}
|
|
800
|
-
avmOpcodeReturndataCopy(rdOffset, copySize) {
|
|
801
|
-
return this.nestedCallReturndata.slice(rdOffset, rdOffset + copySize);
|
|
802
|
-
}
|
|
803
525
|
async avmOpcodeNullifierExists(innerNullifier, targetAddress) {
|
|
804
526
|
const nullifier = await siloNullifier(targetAddress, innerNullifier);
|
|
805
527
|
const db = this.baseFork;
|
|
806
|
-
const
|
|
528
|
+
const treeIndex = (await db.findLeafIndices(MerkleTreeId.NULLIFIER_TREE, [
|
|
807
529
|
nullifier.toBuffer()
|
|
808
530
|
]))[0];
|
|
809
|
-
|
|
531
|
+
const transientIndex = this.siloedNullifiersFromPublic.find((n)=>n.equals(nullifier));
|
|
532
|
+
return treeIndex !== undefined || transientIndex !== undefined;
|
|
810
533
|
}
|
|
811
534
|
async avmOpcodeEmitNullifier(nullifier) {
|
|
812
535
|
const siloedNullifier = await siloNullifier(this.contractAddress, nullifier);
|
|
@@ -832,50 +555,57 @@ export class TXE {
|
|
|
832
555
|
const preimage = await this.baseFork.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index);
|
|
833
556
|
return preimage.leaf.value;
|
|
834
557
|
}
|
|
835
|
-
|
|
558
|
+
utilityStoreCapsule(contractAddress, slot, capsule) {
|
|
836
559
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
837
560
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
838
561
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
839
562
|
}
|
|
840
563
|
return this.pxeOracleInterface.storeCapsule(this.contractAddress, slot, capsule);
|
|
841
564
|
}
|
|
842
|
-
|
|
565
|
+
utilityLoadCapsule(contractAddress, slot) {
|
|
843
566
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
844
567
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
845
568
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
846
569
|
}
|
|
847
570
|
return this.pxeOracleInterface.loadCapsule(this.contractAddress, slot);
|
|
848
571
|
}
|
|
849
|
-
|
|
572
|
+
utilityDeleteCapsule(contractAddress, slot) {
|
|
850
573
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
851
574
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
852
575
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
853
576
|
}
|
|
854
577
|
return this.pxeOracleInterface.deleteCapsule(this.contractAddress, slot);
|
|
855
578
|
}
|
|
856
|
-
|
|
579
|
+
utilityCopyCapsule(contractAddress, srcSlot, dstSlot, numEntries) {
|
|
857
580
|
if (!contractAddress.equals(this.contractAddress)) {
|
|
858
581
|
// TODO(#10727): instead of this check that this.contractAddress is allowed to access the external DB
|
|
859
582
|
throw new Error(`Contract ${contractAddress} is not allowed to access ${this.contractAddress}'s PXE DB`);
|
|
860
583
|
}
|
|
861
584
|
return this.pxeOracleInterface.copyCapsule(this.contractAddress, srcSlot, dstSlot, numEntries);
|
|
862
585
|
}
|
|
863
|
-
|
|
586
|
+
utilityAes128Decrypt(ciphertext, iv, symKey) {
|
|
864
587
|
const aes128 = new Aes128();
|
|
865
588
|
return aes128.decryptBufferCBC(ciphertext, iv, symKey);
|
|
866
589
|
}
|
|
867
|
-
|
|
590
|
+
utilityGetSharedSecret(address, ephPk) {
|
|
868
591
|
return this.pxeOracleInterface.getSharedSecret(address, ephPk);
|
|
869
592
|
}
|
|
870
|
-
|
|
871
|
-
|
|
593
|
+
privateGetSenderForTags() {
|
|
594
|
+
return Promise.resolve(this.senderForTags);
|
|
595
|
+
}
|
|
596
|
+
privateSetSenderForTags(senderForTags) {
|
|
597
|
+
this.senderForTags = senderForTags;
|
|
872
598
|
return Promise.resolve();
|
|
873
599
|
}
|
|
874
|
-
async
|
|
600
|
+
async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
|
|
875
601
|
this.logger.verbose(`Executing external function ${await this.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
876
602
|
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
877
603
|
if (artifact === undefined) {
|
|
878
|
-
|
|
604
|
+
if (functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))) {
|
|
605
|
+
throw new Error('Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.');
|
|
606
|
+
} else {
|
|
607
|
+
throw new Error('Function Artifact does not exist');
|
|
608
|
+
}
|
|
879
609
|
}
|
|
880
610
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
881
611
|
const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
@@ -884,8 +614,12 @@ export class TXE {
|
|
|
884
614
|
const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
|
|
885
615
|
const blockHeader = await this.pxeOracleInterface.getBlockHeader();
|
|
886
616
|
const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
887
|
-
|
|
888
|
-
context.
|
|
617
|
+
// TODO(benesjan): Fix stale 'context' name.
|
|
618
|
+
const context = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ Array.from(this.authwits.values()), /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create(), noteCache, this.pxeOracleInterface, this.simulator, 0, 1, undefined, undefined, /**
|
|
619
|
+
* In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
620
|
+
* contract would perform, including setting senderForTags.
|
|
621
|
+
*/ from);
|
|
622
|
+
context.privateStoreInExecutionCache(args, argsHash);
|
|
889
623
|
// Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
|
|
890
624
|
let result;
|
|
891
625
|
let executionResult;
|
|
@@ -895,12 +629,11 @@ export class TXE {
|
|
|
895
629
|
const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
|
|
896
630
|
const publicCallRequests = collectNested([
|
|
897
631
|
executionResult
|
|
898
|
-
], (r)=>[
|
|
899
|
-
...r.publicInputs.publicCallRequests.map((r)=>r.inner),
|
|
632
|
+
], (r)=>r.publicInputs.publicCallRequests.getActiveItems().map((r)=>r.inner).concat(r.publicInputs.publicTeardownCallRequest.isEmpty() ? [] : [
|
|
900
633
|
r.publicInputs.publicTeardownCallRequest
|
|
901
|
-
])
|
|
634
|
+
]));
|
|
902
635
|
const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
|
|
903
|
-
const calldata = await context.
|
|
636
|
+
const calldata = await context.privateLoadFromExecutionCache(r.calldataHash);
|
|
904
637
|
return new HashedValues(calldata, r.calldataHash);
|
|
905
638
|
}));
|
|
906
639
|
result = new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
|
|
@@ -912,7 +645,7 @@ export class TXE {
|
|
|
912
645
|
// This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
|
|
913
646
|
// Investigate whether it is faster to do this or return from the oracle directly.
|
|
914
647
|
const returnValuesHash = await computeVarArgsHash(returnValues);
|
|
915
|
-
this.
|
|
648
|
+
this.privateStoreInExecutionCache(returnValues, returnValuesHash);
|
|
916
649
|
}
|
|
917
650
|
// According to the protocol rules, the nonce generator for the note hashes
|
|
918
651
|
// can either be the first nullifier in the tx or the hash of the initial tx request
|
|
@@ -922,12 +655,19 @@ export class TXE {
|
|
|
922
655
|
const globals = makeGlobalVariables();
|
|
923
656
|
globals.blockNumber = this.blockNumber;
|
|
924
657
|
globals.timestamp = this.timestamp;
|
|
658
|
+
globals.chainId = new Fr(this.CHAIN_ID);
|
|
659
|
+
globals.version = new Fr(this.ROLLUP_VERSION);
|
|
925
660
|
globals.gasFees = GasFees.empty();
|
|
926
661
|
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
|
|
927
662
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(this.baseFork);
|
|
928
663
|
const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
|
|
929
664
|
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
|
|
930
|
-
const tx =
|
|
665
|
+
const tx = await Tx.create({
|
|
666
|
+
data: publicInputs,
|
|
667
|
+
clientIvcProof: ClientIvcProof.empty(),
|
|
668
|
+
contractClassLogFields: [],
|
|
669
|
+
publicFunctionCalldata: result.publicFunctionCalldata
|
|
670
|
+
});
|
|
931
671
|
let checkpoint;
|
|
932
672
|
if (isStaticCall) {
|
|
933
673
|
checkpoint = await ForkCheckpoint.new(this.baseFork);
|
|
@@ -935,27 +675,33 @@ export class TXE {
|
|
|
935
675
|
const results = await processor.process([
|
|
936
676
|
tx
|
|
937
677
|
]);
|
|
938
|
-
const
|
|
678
|
+
const [processedTx] = results[0];
|
|
939
679
|
const failedTxs = results[1];
|
|
940
680
|
if (failedTxs.length !== 0) {
|
|
941
|
-
throw new Error(
|
|
681
|
+
throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
|
|
682
|
+
} else if (!processedTx.revertCode.isOK()) {
|
|
683
|
+
if (processedTx.revertReason) {
|
|
684
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
|
|
685
|
+
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
686
|
+
} else {
|
|
687
|
+
throw new Error('Contract execution has reverted');
|
|
688
|
+
}
|
|
942
689
|
}
|
|
943
690
|
if (isStaticCall) {
|
|
944
691
|
await checkpoint.revert();
|
|
945
|
-
const txRequestHash = this.getTxRequestHash();
|
|
946
692
|
return {
|
|
947
693
|
endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
|
|
948
694
|
returnsHash: result.entrypoint.publicInputs.returnsHash,
|
|
949
|
-
txHash:
|
|
695
|
+
txHash: tx.getTxHash()
|
|
950
696
|
};
|
|
951
697
|
}
|
|
952
698
|
const fork = this.baseFork;
|
|
953
699
|
const txEffect = TxEffect.empty();
|
|
954
|
-
txEffect.noteHashes =
|
|
955
|
-
txEffect.nullifiers =
|
|
956
|
-
txEffect.privateLogs =
|
|
957
|
-
txEffect.publicLogs =
|
|
958
|
-
txEffect.publicDataWrites =
|
|
700
|
+
txEffect.noteHashes = processedTx.txEffect.noteHashes;
|
|
701
|
+
txEffect.nullifiers = processedTx.txEffect.nullifiers;
|
|
702
|
+
txEffect.privateLogs = processedTx.txEffect.privateLogs;
|
|
703
|
+
txEffect.publicLogs = processedTx.txEffect.publicLogs;
|
|
704
|
+
txEffect.publicDataWrites = processedTx.txEffect.publicDataWrites;
|
|
959
705
|
txEffect.txHash = new TxHash(new Fr(this.blockNumber));
|
|
960
706
|
const body = new Body([
|
|
961
707
|
txEffect
|
|
@@ -970,53 +716,55 @@ export class TXE {
|
|
|
970
716
|
l2Block.header = header;
|
|
971
717
|
await fork.updateArchive(l2Block.header);
|
|
972
718
|
await this.stateMachine.handleL2Block(l2Block);
|
|
973
|
-
const txRequestHash = this.getTxRequestHash();
|
|
974
719
|
this.setBlockNumber(this.blockNumber + 1);
|
|
975
|
-
this.advanceTimestampBy(AZTEC_SLOT_DURATION);
|
|
976
720
|
return {
|
|
977
721
|
endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
|
|
978
722
|
returnsHash: result.entrypoint.publicInputs.returnsHash,
|
|
979
|
-
txHash:
|
|
723
|
+
txHash: tx.getTxHash()
|
|
980
724
|
};
|
|
981
725
|
}
|
|
982
|
-
async
|
|
726
|
+
async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
|
|
983
727
|
this.logger.verbose(`Executing public function ${await this.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
984
728
|
const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
985
729
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
986
730
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
987
731
|
const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
|
|
988
732
|
const blockHeader = await this.pxeOracleInterface.getBlockHeader();
|
|
989
|
-
const uniqueNoteHashes = [];
|
|
990
|
-
const taggedPrivateLogs = [];
|
|
991
|
-
const nullifiers = !isStaticCall ? [
|
|
992
|
-
this.getTxRequestHash()
|
|
993
|
-
] : [];
|
|
994
|
-
const l2ToL1Messages = [];
|
|
995
|
-
const contractClassLogsHashes = [];
|
|
996
733
|
const calldataHash = await computeCalldataHash(calldata);
|
|
997
734
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
998
|
-
const publicCallRequest = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
999
|
-
const publicCallRequests = [
|
|
1000
|
-
publicCallRequest
|
|
1001
|
-
];
|
|
1002
735
|
const globals = makeGlobalVariables();
|
|
1003
736
|
globals.blockNumber = this.blockNumber;
|
|
1004
737
|
globals.timestamp = this.timestamp;
|
|
738
|
+
globals.chainId = new Fr(this.CHAIN_ID);
|
|
739
|
+
globals.version = new Fr(this.ROLLUP_VERSION);
|
|
1005
740
|
globals.gasFees = GasFees.empty();
|
|
1006
741
|
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
|
|
1007
742
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(this.baseFork);
|
|
1008
743
|
const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, true, true);
|
|
1009
744
|
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
|
|
745
|
+
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
746
|
+
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
747
|
+
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
748
|
+
// unique.
|
|
749
|
+
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
750
|
+
if (!isStaticCall) {
|
|
751
|
+
nonRevertibleAccumulatedData.nullifiers[0] = this.getTxRequestHash();
|
|
752
|
+
}
|
|
753
|
+
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
754
|
+
// may require producing reverts.
|
|
755
|
+
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
756
|
+
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
757
|
+
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
1010
758
|
const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
759
|
+
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
|
|
760
|
+
const tx = await Tx.create({
|
|
761
|
+
data: txData,
|
|
762
|
+
clientIvcProof: ClientIvcProof.empty(),
|
|
763
|
+
contractClassLogFields: [],
|
|
764
|
+
publicFunctionCalldata: [
|
|
765
|
+
calldataHashedValues
|
|
766
|
+
]
|
|
767
|
+
});
|
|
1020
768
|
let checkpoint;
|
|
1021
769
|
if (isStaticCall) {
|
|
1022
770
|
checkpoint = await ForkCheckpoint.new(this.baseFork);
|
|
@@ -1024,10 +772,17 @@ export class TXE {
|
|
|
1024
772
|
const results = await processor.process([
|
|
1025
773
|
tx
|
|
1026
774
|
]);
|
|
1027
|
-
const
|
|
775
|
+
const [processedTx] = results[0];
|
|
1028
776
|
const failedTxs = results[1];
|
|
1029
|
-
if (failedTxs.length !== 0
|
|
1030
|
-
throw new Error(
|
|
777
|
+
if (failedTxs.length !== 0) {
|
|
778
|
+
throw new Error(`Public execution has failed: ${failedTxs[0].error}`);
|
|
779
|
+
} else if (!processedTx.revertCode.isOK()) {
|
|
780
|
+
if (processedTx.revertReason) {
|
|
781
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
|
|
782
|
+
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
783
|
+
} else {
|
|
784
|
+
throw new Error('Contract execution has reverted');
|
|
785
|
+
}
|
|
1031
786
|
}
|
|
1032
787
|
const returnValues = results[3][0].values;
|
|
1033
788
|
let returnValuesHash;
|
|
@@ -1035,23 +790,22 @@ export class TXE {
|
|
|
1035
790
|
// This is a bit of a hack to not deal with returning a slice in nr which is what normally happens.
|
|
1036
791
|
// Investigate whether it is faster to do this or return from the oracle directly.
|
|
1037
792
|
returnValuesHash = await computeVarArgsHash(returnValues);
|
|
1038
|
-
this.
|
|
793
|
+
this.privateStoreInExecutionCache(returnValues, returnValuesHash);
|
|
1039
794
|
}
|
|
1040
795
|
if (isStaticCall) {
|
|
1041
796
|
await checkpoint.revert();
|
|
1042
|
-
const txRequestHash = this.getTxRequestHash();
|
|
1043
797
|
return {
|
|
1044
798
|
returnsHash: returnValuesHash ?? Fr.ZERO,
|
|
1045
|
-
txHash:
|
|
799
|
+
txHash: tx.getTxHash()
|
|
1046
800
|
};
|
|
1047
801
|
}
|
|
1048
802
|
const fork = this.baseFork;
|
|
1049
803
|
const txEffect = TxEffect.empty();
|
|
1050
|
-
txEffect.noteHashes =
|
|
1051
|
-
txEffect.nullifiers =
|
|
1052
|
-
txEffect.privateLogs =
|
|
1053
|
-
txEffect.publicLogs =
|
|
1054
|
-
txEffect.publicDataWrites =
|
|
804
|
+
txEffect.noteHashes = processedTx.txEffect.noteHashes;
|
|
805
|
+
txEffect.nullifiers = processedTx.txEffect.nullifiers;
|
|
806
|
+
txEffect.privateLogs = processedTx.txEffect.privateLogs;
|
|
807
|
+
txEffect.publicLogs = processedTx.txEffect.publicLogs;
|
|
808
|
+
txEffect.publicDataWrites = processedTx.txEffect.publicDataWrites;
|
|
1055
809
|
txEffect.txHash = new TxHash(new Fr(this.blockNumber));
|
|
1056
810
|
const body = new Body([
|
|
1057
811
|
txEffect
|
|
@@ -1066,12 +820,17 @@ export class TXE {
|
|
|
1066
820
|
l2Block.header = header;
|
|
1067
821
|
await fork.updateArchive(l2Block.header);
|
|
1068
822
|
await this.stateMachine.handleL2Block(l2Block);
|
|
1069
|
-
const txRequestHash = this.getTxRequestHash();
|
|
1070
823
|
this.setBlockNumber(this.blockNumber + 1);
|
|
1071
|
-
this.advanceTimestampBy(AZTEC_SLOT_DURATION);
|
|
1072
824
|
return {
|
|
1073
825
|
returnsHash: returnValuesHash ?? Fr.ZERO,
|
|
1074
|
-
txHash:
|
|
826
|
+
txHash: tx.getTxHash()
|
|
1075
827
|
};
|
|
1076
828
|
}
|
|
829
|
+
async getBlockTimestamp(blockNumber) {
|
|
830
|
+
const blockHeader = await this.stateMachine.archiver.getBlockHeader(blockNumber);
|
|
831
|
+
if (!blockHeader) {
|
|
832
|
+
throw new Error(`Requested timestamp for block ${blockNumber}, which does not exist`);
|
|
833
|
+
}
|
|
834
|
+
return blockHeader.globalVariables.timestamp;
|
|
835
|
+
}
|
|
1077
836
|
}
|