@aztec/txe 0.0.1-commit.e61ad554 → 0.0.1-commit.ec5f612
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 +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +82 -50
- package/dest/oracle/interfaces.d.ts +5 -4
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +2 -2
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +3 -4
- package/dest/oracle/txe_oracle_top_level_context.d.ts +7 -8
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +106 -35
- package/dest/rpc_translator.d.ts +9 -9
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +57 -34
- package/dest/state_machine/archiver.d.ts +1 -1
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +2 -0
- package/dest/state_machine/dummy_p2p_client.d.ts +16 -12
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +28 -16
- package/dest/state_machine/index.d.ts +5 -5
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +15 -10
- package/dest/state_machine/mock_epoch_cache.d.ts +3 -1
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +4 -0
- package/dest/txe_session.d.ts +9 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +80 -21
- package/dest/util/txe_public_contract_data_source.d.ts +2 -3
- package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
- package/dest/util/txe_public_contract_data_source.js +5 -22
- package/dest/utils/block_creation.d.ts +1 -1
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +3 -1
- package/package.json +15 -15
- package/src/index.ts +83 -49
- package/src/oracle/interfaces.ts +7 -2
- package/src/oracle/txe_oracle_public_context.ts +3 -5
- package/src/oracle/txe_oracle_top_level_context.ts +134 -82
- package/src/rpc_translator.ts +61 -28
- package/src/state_machine/archiver.ts +2 -0
- package/src/state_machine/dummy_p2p_client.ts +40 -22
- package/src/state_machine/index.ts +25 -9
- package/src/state_machine/mock_epoch_cache.ts +5 -0
- package/src/txe_session.ts +89 -81
- package/src/util/txe_public_contract_data_source.ts +10 -36
- package/src/utils/block_creation.ts +3 -1
- package/dest/util/txe_contract_store.d.ts +0 -12
- package/dest/util/txe_contract_store.d.ts.map +0 -1
- package/dest/util/txe_contract_store.js +0 -22
- package/src/util/txe_contract_store.ts +0 -36
|
@@ -12,9 +12,11 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
12
12
|
import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
13
13
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
14
14
|
import type { KeyStore } from '@aztec/key-store';
|
|
15
|
+
import type { AccessScopes } from '@aztec/pxe/client/lazy';
|
|
15
16
|
import {
|
|
16
17
|
AddressStore,
|
|
17
18
|
CapsuleStore,
|
|
19
|
+
type ContractStore,
|
|
18
20
|
NoteStore,
|
|
19
21
|
ORACLE_VERSION,
|
|
20
22
|
PrivateEventStore,
|
|
@@ -22,7 +24,6 @@ import {
|
|
|
22
24
|
SenderAddressBookStore,
|
|
23
25
|
SenderTaggingStore,
|
|
24
26
|
enrichPublicSimulationError,
|
|
25
|
-
syncState,
|
|
26
27
|
} from '@aztec/pxe/server';
|
|
27
28
|
import {
|
|
28
29
|
ExecutionNoteCache,
|
|
@@ -84,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
|
|
|
84
85
|
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
85
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
86
87
|
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
87
|
-
import type { TXEContractStore } from '../util/txe_contract_store.js';
|
|
88
88
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
89
89
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
90
90
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
@@ -97,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
97
97
|
|
|
98
98
|
constructor(
|
|
99
99
|
private stateMachine: TXEStateMachine,
|
|
100
|
-
private contractStore:
|
|
100
|
+
private contractStore: ContractStore,
|
|
101
101
|
private noteStore: NoteStore,
|
|
102
102
|
private keyStore: KeyStore,
|
|
103
103
|
private addressStore: AddressStore,
|
|
@@ -107,7 +107,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
107
107
|
private senderAddressBookStore: SenderAddressBookStore,
|
|
108
108
|
private capsuleStore: CapsuleStore,
|
|
109
109
|
private privateEventStore: PrivateEventStore,
|
|
110
|
-
private jobId: string,
|
|
111
110
|
private nextBlockTimestamp: bigint,
|
|
112
111
|
private version: Fr,
|
|
113
112
|
private chainId: Fr,
|
|
@@ -132,13 +131,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
135
|
-
|
|
134
|
+
utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
136
135
|
if (!LogLevels[level]) {
|
|
137
|
-
throw new Error(`Invalid
|
|
136
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
138
137
|
}
|
|
139
138
|
const levelName = LogLevels[level];
|
|
140
139
|
|
|
141
140
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
|
|
141
|
+
return Promise.resolve();
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
txeGetDefaultAddress(): AztecAddress {
|
|
@@ -171,6 +171,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
171
171
|
return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
175
|
+
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
176
|
+
this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
181
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
182
|
+
contractAddress,
|
|
183
|
+
null,
|
|
184
|
+
async (call, execScopes) => {
|
|
185
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
186
|
+
},
|
|
187
|
+
blockHeader,
|
|
188
|
+
jobId,
|
|
189
|
+
[scope],
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
174
193
|
async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
175
194
|
return (
|
|
176
195
|
await this.privateEventStore.getPrivateEvents(selector, {
|
|
@@ -210,7 +229,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
210
229
|
await this.txeAddAccount(artifact, instance, secret);
|
|
211
230
|
} else {
|
|
212
231
|
await this.contractStore.addContractInstance(instance);
|
|
213
|
-
await this.contractStore.addContractArtifact(
|
|
232
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
214
233
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
215
234
|
}
|
|
216
235
|
}
|
|
@@ -220,7 +239,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
220
239
|
|
|
221
240
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
222
241
|
await this.contractStore.addContractInstance(instance);
|
|
223
|
-
await this.contractStore.addContractArtifact(
|
|
242
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
224
243
|
|
|
225
244
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
226
245
|
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
@@ -284,6 +303,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
284
303
|
args: Fr[],
|
|
285
304
|
argsHash: Fr = Fr.zero(),
|
|
286
305
|
isStaticCall: boolean = false,
|
|
306
|
+
jobId: string,
|
|
287
307
|
) {
|
|
288
308
|
this.logger.verbose(
|
|
289
309
|
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -297,12 +317,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
297
317
|
throw new Error(message);
|
|
298
318
|
}
|
|
299
319
|
|
|
320
|
+
// When `from` is the zero address (e.g. when deploying a new account contract), we return an
|
|
321
|
+
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
322
|
+
const effectiveScopes = from.isZero() ? [] : [from];
|
|
323
|
+
|
|
300
324
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
301
|
-
const utilityExecutor = async (call: FunctionCall) => {
|
|
302
|
-
await this.executeUtilityCall(call);
|
|
325
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
|
|
326
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
303
327
|
};
|
|
304
328
|
|
|
305
|
-
await
|
|
329
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
330
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
331
|
+
targetContractAddress,
|
|
332
|
+
functionSelector,
|
|
333
|
+
utilityExecutor,
|
|
334
|
+
blockHeader,
|
|
335
|
+
jobId,
|
|
336
|
+
effectiveScopes,
|
|
337
|
+
);
|
|
306
338
|
|
|
307
339
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
308
340
|
|
|
@@ -314,8 +346,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
314
346
|
|
|
315
347
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
316
348
|
|
|
317
|
-
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
318
|
-
|
|
319
349
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
320
350
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
321
351
|
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
@@ -327,43 +357,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
327
357
|
|
|
328
358
|
const simulator = new WASMSimulator();
|
|
329
359
|
|
|
330
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
360
|
+
const privateExecutionOracle = new PrivateExecutionOracle({
|
|
331
361
|
argsHash,
|
|
332
362
|
txContext,
|
|
333
363
|
callContext,
|
|
334
|
-
|
|
335
|
-
blockHeader,
|
|
364
|
+
anchorBlockHeader: blockHeader,
|
|
336
365
|
utilityExecutor,
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
[],
|
|
341
|
-
HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
366
|
+
authWitnesses: Array.from(this.authwits.values()),
|
|
367
|
+
capsules: [],
|
|
368
|
+
executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
|
|
342
369
|
noteCache,
|
|
343
370
|
taggingIndexCache,
|
|
344
|
-
this.contractStore,
|
|
345
|
-
this.noteStore,
|
|
346
|
-
this.keyStore,
|
|
347
|
-
this.addressStore,
|
|
348
|
-
this.stateMachine.node,
|
|
349
|
-
this.
|
|
350
|
-
this.
|
|
351
|
-
this.
|
|
352
|
-
this.
|
|
353
|
-
this.
|
|
354
|
-
this.
|
|
355
|
-
|
|
356
|
-
0,
|
|
357
|
-
minRevertibleSideEffectCounter,
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
* contract would perform, including setting senderForTags.
|
|
363
|
-
*/
|
|
364
|
-
from,
|
|
371
|
+
contractStore: this.contractStore,
|
|
372
|
+
noteStore: this.noteStore,
|
|
373
|
+
keyStore: this.keyStore,
|
|
374
|
+
addressStore: this.addressStore,
|
|
375
|
+
aztecNode: this.stateMachine.node,
|
|
376
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
377
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
378
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
379
|
+
capsuleStore: this.capsuleStore,
|
|
380
|
+
privateEventStore: this.privateEventStore,
|
|
381
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
382
|
+
jobId,
|
|
383
|
+
totalPublicCalldataCount: 0,
|
|
384
|
+
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
385
|
+
scopes: effectiveScopes,
|
|
386
|
+
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
387
|
+
// contract would perform, including setting senderForTags.
|
|
388
|
+
senderForTags: from,
|
|
365
389
|
simulator,
|
|
366
|
-
);
|
|
390
|
+
});
|
|
367
391
|
|
|
368
392
|
// 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.
|
|
369
393
|
let result: PrivateExecutionResult;
|
|
@@ -402,7 +426,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
402
426
|
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
403
427
|
const { publicInputs } = await generateSimulatedProvingResult(
|
|
404
428
|
result,
|
|
405
|
-
this.contractStore,
|
|
429
|
+
(addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
|
|
430
|
+
this.stateMachine.node,
|
|
406
431
|
minRevertibleSideEffectCounter,
|
|
407
432
|
);
|
|
408
433
|
|
|
@@ -415,7 +440,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
415
440
|
|
|
416
441
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
417
442
|
|
|
418
|
-
const
|
|
443
|
+
const bindings = this.logger.getBindings();
|
|
444
|
+
const contractsDB = new PublicContractsDB(
|
|
445
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
446
|
+
bindings,
|
|
447
|
+
);
|
|
419
448
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
420
449
|
const config = PublicSimulatorConfig.from({
|
|
421
450
|
skipFeeEnforcement: true,
|
|
@@ -428,8 +457,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
428
457
|
globals,
|
|
429
458
|
guardedMerkleTrees,
|
|
430
459
|
contractsDB,
|
|
431
|
-
new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
|
|
460
|
+
new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
|
|
432
461
|
new TestDateProvider(),
|
|
462
|
+
undefined,
|
|
463
|
+
createLogger('simulator:public-processor', bindings),
|
|
433
464
|
);
|
|
434
465
|
|
|
435
466
|
const tx = await Tx.create({
|
|
@@ -526,7 +557,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
526
557
|
|
|
527
558
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
528
559
|
|
|
529
|
-
const
|
|
560
|
+
const bindings2 = this.logger.getBindings();
|
|
561
|
+
const contractsDB = new PublicContractsDB(
|
|
562
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
563
|
+
bindings2,
|
|
564
|
+
);
|
|
530
565
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
531
566
|
const config = PublicSimulatorConfig.from({
|
|
532
567
|
skipFeeEnforcement: true,
|
|
@@ -535,8 +570,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
535
570
|
collectStatistics: false,
|
|
536
571
|
collectCallMetadata: true,
|
|
537
572
|
});
|
|
538
|
-
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
|
|
539
|
-
const processor = new PublicProcessor(
|
|
573
|
+
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
574
|
+
const processor = new PublicProcessor(
|
|
575
|
+
globals,
|
|
576
|
+
guardedMerkleTrees,
|
|
577
|
+
contractsDB,
|
|
578
|
+
simulator,
|
|
579
|
+
new TestDateProvider(),
|
|
580
|
+
undefined,
|
|
581
|
+
createLogger('simulator:public-processor', bindings2),
|
|
582
|
+
);
|
|
540
583
|
|
|
541
584
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
542
585
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
@@ -567,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
567
610
|
constantData,
|
|
568
611
|
/*gasUsed=*/ new Gas(0, 0),
|
|
569
612
|
/*feePayer=*/ AztecAddress.zero(),
|
|
570
|
-
/*
|
|
613
|
+
/*expirationTimestamp=*/ 0n,
|
|
571
614
|
inputsForPublic,
|
|
572
615
|
undefined,
|
|
573
616
|
);
|
|
@@ -635,10 +678,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
635
678
|
return returnValues ?? [];
|
|
636
679
|
}
|
|
637
680
|
|
|
638
|
-
async
|
|
681
|
+
async txeExecuteUtilityFunction(
|
|
639
682
|
targetContractAddress: AztecAddress,
|
|
640
683
|
functionSelector: FunctionSelector,
|
|
641
684
|
args: Fr[],
|
|
685
|
+
jobId: string,
|
|
642
686
|
) {
|
|
643
687
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
644
688
|
if (!artifact) {
|
|
@@ -646,25 +690,33 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
646
690
|
}
|
|
647
691
|
|
|
648
692
|
// Sync notes before executing utility function to discover notes from previous transactions
|
|
649
|
-
await
|
|
650
|
-
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
const call = new FunctionCall(
|
|
654
|
-
artifact.name,
|
|
693
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
694
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
655
695
|
targetContractAddress,
|
|
656
696
|
functionSelector,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
697
|
+
async (call, execScopes) => {
|
|
698
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
699
|
+
},
|
|
700
|
+
blockHeader,
|
|
701
|
+
jobId,
|
|
702
|
+
'ALL_SCOPES',
|
|
662
703
|
);
|
|
663
704
|
|
|
664
|
-
|
|
705
|
+
const call = FunctionCall.from({
|
|
706
|
+
name: artifact.name,
|
|
707
|
+
to: targetContractAddress,
|
|
708
|
+
selector: functionSelector,
|
|
709
|
+
type: FunctionType.UTILITY,
|
|
710
|
+
hideMsgSender: false,
|
|
711
|
+
isStatic: false,
|
|
712
|
+
args,
|
|
713
|
+
returnTypes: [],
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
|
|
665
717
|
}
|
|
666
718
|
|
|
667
|
-
private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
|
|
719
|
+
private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
|
|
668
720
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
669
721
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
670
722
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -677,23 +729,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
677
729
|
|
|
678
730
|
try {
|
|
679
731
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
680
|
-
const oracle = new UtilityExecutionOracle(
|
|
681
|
-
call.to,
|
|
682
|
-
[],
|
|
683
|
-
[],
|
|
732
|
+
const oracle = new UtilityExecutionOracle({
|
|
733
|
+
contractAddress: call.to,
|
|
734
|
+
authWitnesses: [],
|
|
735
|
+
capsules: [],
|
|
684
736
|
anchorBlockHeader,
|
|
685
|
-
this.contractStore,
|
|
686
|
-
this.noteStore,
|
|
687
|
-
this.keyStore,
|
|
688
|
-
this.addressStore,
|
|
689
|
-
this.stateMachine.node,
|
|
690
|
-
this.
|
|
691
|
-
this.
|
|
692
|
-
this.
|
|
693
|
-
this.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
);
|
|
737
|
+
contractStore: this.contractStore,
|
|
738
|
+
noteStore: this.noteStore,
|
|
739
|
+
keyStore: this.keyStore,
|
|
740
|
+
addressStore: this.addressStore,
|
|
741
|
+
aztecNode: this.stateMachine.node,
|
|
742
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
743
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
744
|
+
capsuleStore: this.capsuleStore,
|
|
745
|
+
privateEventStore: this.privateEventStore,
|
|
746
|
+
jobId,
|
|
747
|
+
scopes,
|
|
748
|
+
});
|
|
697
749
|
const acirExecutionResult = await new WASMSimulator()
|
|
698
750
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
699
751
|
.catch((err: Error) => {
|
|
@@ -709,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
709
761
|
);
|
|
710
762
|
});
|
|
711
763
|
|
|
712
|
-
this.logger.verbose(`Utility
|
|
764
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
713
765
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
714
766
|
} catch (err) {
|
|
715
|
-
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility
|
|
767
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
|
|
716
768
|
}
|
|
717
769
|
}
|
|
718
770
|
|
package/src/rpc_translator.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from '@aztec/pxe/simulator';
|
|
11
11
|
import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
|
|
12
12
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
|
-
import {
|
|
13
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
14
14
|
|
|
15
15
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
16
16
|
import type { TXESessionStateHandler } from './txe_session.js';
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
toSingle,
|
|
31
31
|
} from './util/encoding.js';
|
|
32
32
|
|
|
33
|
-
const MAX_EVENT_LEN =
|
|
33
|
+
const MAX_EVENT_LEN = 10; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
|
|
34
34
|
const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
|
|
35
35
|
|
|
36
36
|
export class UnavailableOracleError extends Error {
|
|
@@ -285,6 +285,13 @@ export class RPCTranslator {
|
|
|
285
285
|
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
286
286
|
const scope = addressFromSingle(foreignScope);
|
|
287
287
|
|
|
288
|
+
// TODO(F-335): Avoid doing the following 2 calls here.
|
|
289
|
+
{
|
|
290
|
+
await this.handlerAsTxe().syncContractNonOracleMethod(contractAddress, scope, this.stateHandler.getCurrentJob());
|
|
291
|
+
// We cycle job to commit the stores after the contract sync.
|
|
292
|
+
await this.stateHandler.cycleJob();
|
|
293
|
+
}
|
|
294
|
+
|
|
288
295
|
const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
|
|
289
296
|
|
|
290
297
|
if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
|
|
@@ -328,7 +335,7 @@ export class RPCTranslator {
|
|
|
328
335
|
|
|
329
336
|
// When the argument is a slice, noir automatically adds a length field to oracle call.
|
|
330
337
|
// When the argument is an array, we add the field length manually to the signature.
|
|
331
|
-
|
|
338
|
+
async utilityLog(
|
|
332
339
|
foreignLevel: ForeignCallSingle,
|
|
333
340
|
foreignMessage: ForeignCallArray,
|
|
334
341
|
_foreignLength: ForeignCallSingle,
|
|
@@ -340,7 +347,7 @@ export class RPCTranslator {
|
|
|
340
347
|
.join('');
|
|
341
348
|
const fields = fromArray(foreignFields);
|
|
342
349
|
|
|
343
|
-
this.handlerAsMisc().
|
|
350
|
+
await this.handlerAsMisc().utilityLog(level, message, fields);
|
|
344
351
|
|
|
345
352
|
return toForeignCallResult([]);
|
|
346
353
|
}
|
|
@@ -351,7 +358,7 @@ export class RPCTranslator {
|
|
|
351
358
|
foreignStartStorageSlot: ForeignCallSingle,
|
|
352
359
|
foreignNumberOfElements: ForeignCallSingle,
|
|
353
360
|
) {
|
|
354
|
-
const blockHash =
|
|
361
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
355
362
|
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
356
363
|
const startStorageSlot = fromSingle(foreignStartStorageSlot);
|
|
357
364
|
const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
|
|
@@ -367,7 +374,7 @@ export class RPCTranslator {
|
|
|
367
374
|
}
|
|
368
375
|
|
|
369
376
|
async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
|
|
370
|
-
const blockHash =
|
|
377
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
371
378
|
const leafSlot = fromSingle(foreignLeafSlot);
|
|
372
379
|
|
|
373
380
|
const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
|
|
@@ -545,12 +552,23 @@ export class RPCTranslator {
|
|
|
545
552
|
);
|
|
546
553
|
}
|
|
547
554
|
|
|
548
|
-
async
|
|
555
|
+
async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
|
|
549
556
|
const address = addressFromSingle(foreignAddress);
|
|
550
557
|
|
|
551
|
-
const
|
|
558
|
+
const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
|
|
552
559
|
|
|
553
|
-
return
|
|
560
|
+
// We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
|
|
561
|
+
// with two fields: `some` (a boolean) and `value` (a field array in this case).
|
|
562
|
+
if (result === undefined) {
|
|
563
|
+
// No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
|
|
564
|
+
return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
|
|
565
|
+
} else {
|
|
566
|
+
// Data was found so we set `some` to 1 and return it along with `value`.
|
|
567
|
+
return toForeignCallResult([
|
|
568
|
+
toSingle(new Fr(1)),
|
|
569
|
+
toArray([...result.publicKeys.toFields(), result.partialAddress]),
|
|
570
|
+
]);
|
|
571
|
+
}
|
|
554
572
|
}
|
|
555
573
|
|
|
556
574
|
async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
|
|
@@ -574,7 +592,7 @@ export class RPCTranslator {
|
|
|
574
592
|
}
|
|
575
593
|
|
|
576
594
|
async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
|
|
577
|
-
const blockHash =
|
|
595
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
578
596
|
const nullifier = fromSingle(foreignNullifier);
|
|
579
597
|
|
|
580
598
|
const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -641,26 +659,34 @@ export class RPCTranslator {
|
|
|
641
659
|
return toForeignCallResult(header.toFields().map(toSingle));
|
|
642
660
|
}
|
|
643
661
|
|
|
644
|
-
async utilityGetNoteHashMembershipWitness(
|
|
645
|
-
|
|
646
|
-
|
|
662
|
+
async utilityGetNoteHashMembershipWitness(
|
|
663
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
664
|
+
foreignNoteHash: ForeignCallSingle,
|
|
665
|
+
) {
|
|
666
|
+
const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
667
|
+
const noteHash = fromSingle(foreignNoteHash);
|
|
647
668
|
|
|
648
|
-
const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash,
|
|
669
|
+
const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
|
|
649
670
|
|
|
650
671
|
if (!witness) {
|
|
651
|
-
throw new Error(`Note hash ${
|
|
672
|
+
throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
|
|
652
673
|
}
|
|
653
674
|
return toForeignCallResult(witness.toNoirRepresentation());
|
|
654
675
|
}
|
|
655
676
|
|
|
656
|
-
async
|
|
657
|
-
|
|
658
|
-
|
|
677
|
+
async utilityGetBlockHashMembershipWitness(
|
|
678
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
679
|
+
foreignBlockHash: ForeignCallSingle,
|
|
680
|
+
) {
|
|
681
|
+
const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
682
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
659
683
|
|
|
660
|
-
const witness = await this.handlerAsUtility().
|
|
684
|
+
const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
|
|
661
685
|
|
|
662
686
|
if (!witness) {
|
|
663
|
-
throw new Error(
|
|
687
|
+
throw new Error(
|
|
688
|
+
`Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
|
|
689
|
+
);
|
|
664
690
|
}
|
|
665
691
|
return toForeignCallResult(witness.toNoirRepresentation());
|
|
666
692
|
}
|
|
@@ -669,7 +695,7 @@ export class RPCTranslator {
|
|
|
669
695
|
foreignBlockHash: ForeignCallSingle,
|
|
670
696
|
foreignNullifier: ForeignCallSingle,
|
|
671
697
|
) {
|
|
672
|
-
const blockHash =
|
|
698
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
673
699
|
const nullifier = fromSingle(foreignNullifier);
|
|
674
700
|
|
|
675
701
|
const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -830,7 +856,7 @@ export class RPCTranslator {
|
|
|
830
856
|
|
|
831
857
|
// AVM opcodes
|
|
832
858
|
|
|
833
|
-
|
|
859
|
+
avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
|
|
834
860
|
// TODO(#8811): Implement
|
|
835
861
|
return toForeignCallResult([]);
|
|
836
862
|
}
|
|
@@ -911,11 +937,10 @@ export class RPCTranslator {
|
|
|
911
937
|
return toForeignCallResult([]);
|
|
912
938
|
}
|
|
913
939
|
|
|
914
|
-
async avmOpcodeNullifierExists(
|
|
915
|
-
const
|
|
916
|
-
const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
|
|
940
|
+
async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
|
|
941
|
+
const siloedNullifier = fromSingle(foreignSiloedNullifier);
|
|
917
942
|
|
|
918
|
-
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(
|
|
943
|
+
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
|
|
919
944
|
|
|
920
945
|
return toForeignCallResult([toSingle(new Fr(exists))]);
|
|
921
946
|
}
|
|
@@ -1020,12 +1045,15 @@ export class RPCTranslator {
|
|
|
1020
1045
|
args,
|
|
1021
1046
|
argsHash,
|
|
1022
1047
|
isStaticCall,
|
|
1048
|
+
this.stateHandler.getCurrentJob(),
|
|
1023
1049
|
);
|
|
1024
1050
|
|
|
1051
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1052
|
+
await this.stateHandler.cycleJob();
|
|
1025
1053
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1026
1054
|
}
|
|
1027
1055
|
|
|
1028
|
-
async
|
|
1056
|
+
async txeExecuteUtilityFunction(
|
|
1029
1057
|
foreignTargetContractAddress: ForeignCallSingle,
|
|
1030
1058
|
foreignFunctionSelector: ForeignCallSingle,
|
|
1031
1059
|
foreignArgs: ForeignCallArray,
|
|
@@ -1034,12 +1062,15 @@ export class RPCTranslator {
|
|
|
1034
1062
|
const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
|
|
1035
1063
|
const args = fromArray(foreignArgs);
|
|
1036
1064
|
|
|
1037
|
-
const returnValues = await this.handlerAsTxe().
|
|
1065
|
+
const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
|
|
1038
1066
|
targetContractAddress,
|
|
1039
1067
|
functionSelector,
|
|
1040
1068
|
args,
|
|
1069
|
+
this.stateHandler.getCurrentJob(),
|
|
1041
1070
|
);
|
|
1042
1071
|
|
|
1072
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1073
|
+
await this.stateHandler.cycleJob();
|
|
1043
1074
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1044
1075
|
}
|
|
1045
1076
|
|
|
@@ -1056,6 +1087,8 @@ export class RPCTranslator {
|
|
|
1056
1087
|
|
|
1057
1088
|
const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
|
|
1058
1089
|
|
|
1090
|
+
// TODO(F-335): Avoid doing the following call here.
|
|
1091
|
+
await this.stateHandler.cycleJob();
|
|
1059
1092
|
return toForeignCallResult([toArray(returnValues)]);
|
|
1060
1093
|
}
|
|
1061
1094
|
|
|
@@ -59,6 +59,8 @@ export class TXEArchiver extends ArchiverDataSourceBase {
|
|
|
59
59
|
if (!checkpointedBlock) {
|
|
60
60
|
throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
|
|
61
61
|
}
|
|
62
|
+
// TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
|
|
63
|
+
// This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
|
|
62
64
|
const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
|
|
63
65
|
if (checkpoint.length === 0) {
|
|
64
66
|
throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
|