@aztec/txe 5.0.0-rc.1 → 5.0.0-rc.2
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/AuthRegistry-URXCCPYF.js +3 -0
- package/dest/AuthRegistry-URXCCPYF.js.map +7 -0
- package/dest/{ContractClassRegistry-EHVIHGEK.js → ContractClassRegistry-5RDBM6TC.js} +1 -1
- package/dest/{ContractClassRegistry-EHVIHGEK.js.map → ContractClassRegistry-5RDBM6TC.js.map} +2 -2
- package/dest/{ContractInstanceRegistry-DWZDXHRG.js → ContractInstanceRegistry-GCR4G4D7.js} +1 -1
- package/dest/{ContractInstanceRegistry-DWZDXHRG.js.map → ContractInstanceRegistry-GCR4G4D7.js.map} +1 -1
- package/dest/{FeeJuice-MI32ZO7B.js → FeeJuice-O3KOSZO5.js} +1 -1
- package/dest/{FeeJuice-MI32ZO7B.js.map → FeeJuice-O3KOSZO5.js.map} +1 -1
- package/dest/HandshakeRegistry-TXSMHMNY.js +3 -0
- package/dest/HandshakeRegistry-TXSMHMNY.js.map +7 -0
- package/dest/MultiCallEntrypoint-P4FSRXAD.js +3 -0
- package/dest/MultiCallEntrypoint-P4FSRXAD.js.map +7 -0
- package/dest/SchnorrAccount-AQZX7ROU.js +3 -0
- package/dest/SchnorrAccount-AQZX7ROU.js.map +7 -0
- package/dest/SchnorrInitializerlessAccount-KMX2H3J6.js +3 -0
- package/dest/SchnorrInitializerlessAccount-KMX2H3J6.js.map +7 -0
- package/dest/bin/index.js +1 -1
- package/dest/bin/oracle_test_server.js +2 -2
- package/dest/{chunk-UPW55EJX.js → chunk-I6DL4FT2.js} +2 -2
- package/dest/chunk-IAO54JS2.js +266 -0
- package/dest/{chunk-5U25VAFR.js.map → chunk-IAO54JS2.js.map} +4 -4
- package/dest/constants.d.ts +1 -1
- package/dest/constants.d.ts.map +1 -1
- package/dest/constants.js +1 -1
- package/dest/metafile.json +7241 -6706
- package/dest/oracle/interfaces.d.ts +10 -5
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/test-resolver/default_fixtures.d.ts +9 -0
- package/dest/oracle/test-resolver/default_fixtures.d.ts.map +1 -0
- package/dest/oracle/test-resolver/default_fixtures.js +164 -0
- package/dest/oracle/test-resolver/index.d.ts +1 -1
- package/dest/oracle/test-resolver/index.d.ts.map +1 -1
- package/dest/oracle/test-resolver/index.js +1 -2
- package/dest/oracle/test-resolver/resolver.d.ts +22 -8
- package/dest/oracle/test-resolver/resolver.d.ts.map +1 -1
- package/dest/oracle/test-resolver/resolver.js +62 -32
- package/dest/oracle/txe_oracle_public_context.d.ts +4 -4
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_registry.d.ts +156 -3
- package/dest/oracle/txe_oracle_registry.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_registry.js +179 -26
- package/dest/oracle/txe_oracle_top_level_context.d.ts +20 -8
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +72 -30
- package/dest/oracle/txe_oracle_version.d.ts +2 -2
- package/dest/oracle/txe_oracle_version.js +2 -2
- package/dest/rpc_translator.d.ts +10 -2
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +69 -5
- package/dest/server.bundle.js +1 -1
- 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 +1 -2
- package/dest/state_machine/dummy_p2p_client.d.ts +3 -2
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +3 -0
- package/dest/state_machine/global_variable_builder.d.ts +3 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +0 -3
- package/dest/state_machine/index.d.ts +6 -5
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +35 -10
- package/dest/state_machine/synchronizer.d.ts +3 -2
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +3 -2
- package/dest/txe_session.d.ts +8 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +53 -27
- package/dest/utils/block_creation.d.ts +2 -2
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +2 -2
- package/dest/worker.bundle.js +1 -1
- package/package.json +17 -17
- package/src/bin/oracle_test_server.ts +2 -2
- package/src/constants.ts +1 -1
- package/src/oracle/interfaces.ts +9 -3
- package/src/oracle/test-resolver/default_fixtures.ts +226 -0
- package/src/oracle/test-resolver/index.ts +1 -2
- package/src/oracle/test-resolver/resolver.ts +74 -41
- package/src/oracle/txe_oracle_public_context.ts +3 -3
- package/src/oracle/txe_oracle_registry.ts +106 -13
- package/src/oracle/txe_oracle_top_level_context.ts +76 -30
- package/src/oracle/txe_oracle_version.ts +2 -2
- package/src/rpc_translator.ts +93 -5
- package/src/state_machine/archiver.ts +0 -1
- package/src/state_machine/dummy_p2p_client.ts +5 -0
- package/src/state_machine/global_variable_builder.ts +2 -16
- package/src/state_machine/index.ts +31 -29
- package/src/state_machine/synchronizer.ts +3 -2
- package/src/txe_session.ts +62 -23
- package/src/utils/block_creation.ts +2 -1
- package/dest/AuthRegistry-CPGFQR26.js +0 -3
- package/dest/AuthRegistry-CPGFQR26.js.map +0 -7
- package/dest/HandshakeRegistry-3KSP3ITH.js +0 -3
- package/dest/HandshakeRegistry-3KSP3ITH.js.map +0 -7
- package/dest/MultiCallEntrypoint-IU7HYFYE.js +0 -3
- package/dest/MultiCallEntrypoint-IU7HYFYE.js.map +0 -7
- package/dest/SchnorrAccount-6TUE7JX4.js +0 -3
- package/dest/SchnorrAccount-6TUE7JX4.js.map +0 -7
- package/dest/SchnorrInitializerlessAccount-S3DU2DJK.js +0 -3
- package/dest/SchnorrInitializerlessAccount-S3DU2DJK.js.map +0 -7
- package/dest/chunk-5U25VAFR.js +0 -265
- package/dest/oracle/test-resolver/fixtures.d.ts +0 -43
- package/dest/oracle/test-resolver/fixtures.d.ts.map +0 -1
- package/dest/oracle/test-resolver/fixtures.js +0 -39
- package/src/oracle/test-resolver/fixtures.ts +0 -84
- /package/dest/{chunk-UPW55EJX.js.map → chunk-I6DL4FT2.js.map} +0 -0
package/dest/txe_session.js
CHANGED
|
@@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { KeyStore } from '@aztec/key-store';
|
|
5
5
|
import { openEphemeralStore } from '@aztec/kv-store/lmdb-v2';
|
|
6
|
-
import { AddressStore, AnchorBlockStore, CapsuleService, CapsuleStore, JobCoordinator, NoteService, NoteStore, PrivateEventStore, RecipientTaggingStore,
|
|
6
|
+
import { AddressStore, AnchorBlockStore, CapsuleService, CapsuleStore, FactService, FactStore, JobCoordinator, NoteService, NoteStore, PrivateEventStore, RecipientTaggingStore, SenderTaggingStore, TaggingSecretSourcesStore, composeHooks } from '@aztec/pxe/server';
|
|
7
7
|
import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, TransientArrayService, UtilityExecutionOracle, buildACIRCallback } from '@aztec/pxe/simulator';
|
|
8
8
|
import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness } from '@aztec/simulator/client';
|
|
9
9
|
import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants';
|
|
@@ -47,8 +47,9 @@ function emptyLastCallState() {
|
|
|
47
47
|
accountStore;
|
|
48
48
|
senderTaggingStore;
|
|
49
49
|
recipientTaggingStore;
|
|
50
|
-
|
|
50
|
+
taggingSecretSourcesStore;
|
|
51
51
|
capsuleStore;
|
|
52
|
+
factStore;
|
|
52
53
|
privateEventStore;
|
|
53
54
|
jobCoordinator;
|
|
54
55
|
currentJobId;
|
|
@@ -60,10 +61,11 @@ function emptyLastCallState() {
|
|
|
60
61
|
packageName;
|
|
61
62
|
state;
|
|
62
63
|
authwits;
|
|
64
|
+
taggingSecretStrategy;
|
|
63
65
|
lastCallInfo;
|
|
64
66
|
txeOracleVersion;
|
|
65
67
|
disposed;
|
|
66
|
-
constructor(logger, sessionStore, stateMachine, oracleHandler, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore,
|
|
68
|
+
constructor(logger, sessionStore, stateMachine, oracleHandler, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, taggingSecretSourcesStore, capsuleStore, factStore, privateEventStore, jobCoordinator, currentJobId, chainId, version, nextBlockTimestamp, artifactResolver, rootPath, packageName){
|
|
67
69
|
this.logger = logger;
|
|
68
70
|
this.sessionStore = sessionStore;
|
|
69
71
|
this.stateMachine = stateMachine;
|
|
@@ -75,8 +77,9 @@ function emptyLastCallState() {
|
|
|
75
77
|
this.accountStore = accountStore;
|
|
76
78
|
this.senderTaggingStore = senderTaggingStore;
|
|
77
79
|
this.recipientTaggingStore = recipientTaggingStore;
|
|
78
|
-
this.
|
|
80
|
+
this.taggingSecretSourcesStore = taggingSecretSourcesStore;
|
|
79
81
|
this.capsuleStore = capsuleStore;
|
|
82
|
+
this.factStore = factStore;
|
|
80
83
|
this.privateEventStore = privateEventStore;
|
|
81
84
|
this.jobCoordinator = jobCoordinator;
|
|
82
85
|
this.currentJobId = currentJobId;
|
|
@@ -90,6 +93,7 @@ function emptyLastCallState() {
|
|
|
90
93
|
name: 'TOP_LEVEL'
|
|
91
94
|
};
|
|
92
95
|
this.authwits = new Map();
|
|
96
|
+
this.taggingSecretStrategy = undefined;
|
|
93
97
|
this.lastCallInfo = emptyLastCallState();
|
|
94
98
|
this.disposed = false;
|
|
95
99
|
}
|
|
@@ -123,13 +127,15 @@ function emptyLastCallState() {
|
|
|
123
127
|
const noteStore = new NoteStore(store);
|
|
124
128
|
const senderTaggingStore = new SenderTaggingStore(store);
|
|
125
129
|
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
126
|
-
const
|
|
130
|
+
const taggingSecretSourcesStore = new TaggingSecretSourcesStore(store);
|
|
127
131
|
const capsuleStore = new CapsuleStore(store);
|
|
132
|
+
const factStore = new FactStore(store);
|
|
128
133
|
const keyStore = new KeyStore(store);
|
|
129
134
|
const accountStore = new TXEAccountStore(store);
|
|
130
135
|
const jobCoordinator = new JobCoordinator(store);
|
|
131
136
|
jobCoordinator.registerStores([
|
|
132
137
|
capsuleStore,
|
|
138
|
+
factStore,
|
|
133
139
|
senderTaggingStore,
|
|
134
140
|
recipientTaggingStore,
|
|
135
141
|
privateEventStore,
|
|
@@ -143,11 +149,11 @@ function emptyLastCallState() {
|
|
|
143
149
|
const chainId = new Fr(await stateMachine.node.getChainId());
|
|
144
150
|
const initialJobId = jobCoordinator.beginJob();
|
|
145
151
|
const logger = createLogger('txe:session');
|
|
146
|
-
const topLevelOracleHandler = new TXEOracleTopLevelContext(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore,
|
|
152
|
+
const topLevelOracleHandler = new TXEOracleTopLevelContext(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, taggingSecretSourcesStore, capsuleStore, factStore, privateEventStore, nextBlockTimestamp, version, chainId, new Map(), undefined, artifactResolver, rootPath, packageName);
|
|
147
153
|
await topLevelOracleHandler.mineDeploymentNullifiers([
|
|
148
154
|
STANDARD_AUTH_REGISTRY_ADDRESS
|
|
149
155
|
]);
|
|
150
|
-
return new TXESession(logger, store, stateMachine, topLevelOracleHandler, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore,
|
|
156
|
+
return new TXESession(logger, store, stateMachine, topLevelOracleHandler, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, taggingSecretSourcesStore, capsuleStore, factStore, privateEventStore, jobCoordinator, initialJobId, version, chainId, nextBlockTimestamp, artifactResolver, rootPath, packageName);
|
|
151
157
|
}
|
|
152
158
|
/**
|
|
153
159
|
* Processes an oracle function invoked by the Noir test associated to this session.
|
|
@@ -252,10 +258,10 @@ function emptyLastCallState() {
|
|
|
252
258
|
};
|
|
253
259
|
});
|
|
254
260
|
}
|
|
255
|
-
async executeUtilityFunction(targetContractAddress, functionSelector, args, authorizedUtilityCallTargets) {
|
|
261
|
+
async executeUtilityFunction(from, targetContractAddress, functionSelector, args, authorizedUtilityCallTargets) {
|
|
256
262
|
const handler = this.handlerAsTxe();
|
|
257
263
|
return await this.withTopLevelCallTracking(async ()=>{
|
|
258
|
-
const returnValues = await handler.executeUtilityFunction(targetContractAddress, functionSelector, args, this.currentJobId, authorizedUtilityCallTargets);
|
|
264
|
+
const returnValues = await handler.executeUtilityFunction(from?.value, targetContractAddress, functionSelector, args, this.currentJobId, authorizedUtilityCallTargets);
|
|
259
265
|
await this.cycleJob();
|
|
260
266
|
return {
|
|
261
267
|
result: returnValues
|
|
@@ -332,7 +338,7 @@ function emptyLastCallState() {
|
|
|
332
338
|
}
|
|
333
339
|
// Commit all staged stores from the job that was just completed, then begin a new job
|
|
334
340
|
await this.cycleJob();
|
|
335
|
-
this.oracleHandler = new TXEOracleTopLevelContext(this.stateMachine, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.accountStore, this.senderTaggingStore, this.recipientTaggingStore, this.
|
|
341
|
+
this.oracleHandler = new TXEOracleTopLevelContext(this.stateMachine, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.accountStore, this.senderTaggingStore, this.recipientTaggingStore, this.taggingSecretSourcesStore, this.capsuleStore, this.factStore, this.privateEventStore, this.nextBlockTimestamp, this.version, this.chainId, this.authwits, this.taggingSecretStrategy, this.artifactResolver, this.rootPath, this.packageName);
|
|
336
342
|
this.state = {
|
|
337
343
|
name: 'TOP_LEVEL'
|
|
338
344
|
};
|
|
@@ -361,6 +367,7 @@ function emptyLastCallState() {
|
|
|
361
367
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
362
368
|
const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
|
|
363
369
|
const transientArrayService = new TransientArrayService();
|
|
370
|
+
const taggingSecretStrategy = this.taggingSecretStrategy;
|
|
364
371
|
this.oracleHandler = new TXEPrivateExecutionOracle({
|
|
365
372
|
argsHash: Fr.ZERO,
|
|
366
373
|
txContext: new TxContext(this.chainId, this.version, gasSettings),
|
|
@@ -379,15 +386,19 @@ function emptyLastCallState() {
|
|
|
379
386
|
aztecNode: this.stateMachine.node,
|
|
380
387
|
senderTaggingStore: this.senderTaggingStore,
|
|
381
388
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
382
|
-
|
|
389
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
383
390
|
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
391
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
384
392
|
privateEventStore: this.privateEventStore,
|
|
385
393
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
386
394
|
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
387
395
|
jobId: this.currentJobId,
|
|
388
396
|
scopes: await this.keyStore.getAccounts(),
|
|
389
|
-
|
|
397
|
+
txResolver: this.stateMachine.txResolver,
|
|
390
398
|
simulator: new WASMSimulator(),
|
|
399
|
+
hooks: composeHooks({
|
|
400
|
+
resolveTaggingSecretStrategy: taggingSecretStrategy ? ()=>Promise.resolve(taggingSecretStrategy) : undefined
|
|
401
|
+
}),
|
|
391
402
|
transientArrayService
|
|
392
403
|
});
|
|
393
404
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
@@ -440,7 +451,13 @@ function emptyLastCallState() {
|
|
|
440
451
|
// TODO(#12553): make the synchronizer sync here instead and remove this
|
|
441
452
|
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlockHeader, this.currentJobId).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts());
|
|
442
453
|
this.oracleHandler = new UtilityExecutionOracle({
|
|
443
|
-
|
|
454
|
+
callContext: CallContext.from({
|
|
455
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
456
|
+
contractAddress,
|
|
457
|
+
// No specific function is being executed in this inlined utility context, hence the empty selector.
|
|
458
|
+
functionSelector: FunctionSelector.empty(),
|
|
459
|
+
isStaticCall: true
|
|
460
|
+
}),
|
|
444
461
|
authWitnesses: [],
|
|
445
462
|
capsules: [],
|
|
446
463
|
anchorBlockHeader,
|
|
@@ -450,10 +467,11 @@ function emptyLastCallState() {
|
|
|
450
467
|
addressStore: this.addressStore,
|
|
451
468
|
aztecNode: this.stateMachine.node,
|
|
452
469
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
453
|
-
|
|
470
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
454
471
|
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
472
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
455
473
|
privateEventStore: this.privateEventStore,
|
|
456
|
-
|
|
474
|
+
txResolver: this.stateMachine.txResolver,
|
|
457
475
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
458
476
|
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
459
477
|
jobId: this.currentJobId,
|
|
@@ -475,15 +493,17 @@ function emptyLastCallState() {
|
|
|
475
493
|
throw new Error(`Expected to be in state 'TOP_LEVEL', but got '${this.state.name}' instead`);
|
|
476
494
|
}
|
|
477
495
|
// Note that while all public and private contexts do is build a single block that we then process when exiting
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
// the
|
|
485
|
-
//
|
|
486
|
-
|
|
496
|
+
// them, the top level context does most of its work as it goes: it creates empty blocks (via `advanceBlocksBy`
|
|
497
|
+
// and `deploy`), creates blocks with transactions (via `privateCallNewFlow` and `publicCallNewFlow`), adds
|
|
498
|
+
// accounts to PXE (via `addAccount`), etc. This is a slight inconsistency in the working model of this class, but
|
|
499
|
+
// is not too bad. The `close` call below therefore only hands back the session-scoped values that a test
|
|
500
|
+
// sets directly at the top level, outside any contract execution (e.g. via `advanceTimestampBy`,
|
|
501
|
+
// `addAuthWitness`, `setTaggingSecretStrategy`). The oracle handler is discarded on every state transition,
|
|
502
|
+
// so the session must seed these values into the contexts it creates later.
|
|
503
|
+
// TODO: persisting authwits this way is quite unfortunate: they create a temporary utility context that would
|
|
504
|
+
// otherwise reset them, so we'd not be able to pass more than one per execution. Ideally authwits would be passed
|
|
505
|
+
// alongside a contract call instead of pre-seeded.
|
|
506
|
+
[this.nextBlockTimestamp, this.authwits, this.taggingSecretStrategy] = this.oracleHandler.close();
|
|
487
507
|
}
|
|
488
508
|
async exitPrivateState() {
|
|
489
509
|
if (this.state.name != 'PRIVATE') {
|
|
@@ -529,7 +549,12 @@ function emptyLastCallState() {
|
|
|
529
549
|
try {
|
|
530
550
|
const simulator = new WASMSimulator();
|
|
531
551
|
const oracle = new UtilityExecutionOracle({
|
|
532
|
-
|
|
552
|
+
callContext: CallContext.from({
|
|
553
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
554
|
+
contractAddress: call.to,
|
|
555
|
+
functionSelector: call.selector,
|
|
556
|
+
isStaticCall: true
|
|
557
|
+
}),
|
|
533
558
|
authWitnesses: [],
|
|
534
559
|
capsules: [],
|
|
535
560
|
anchorBlockHeader: anchorBlock,
|
|
@@ -539,10 +564,11 @@ function emptyLastCallState() {
|
|
|
539
564
|
addressStore: this.addressStore,
|
|
540
565
|
aztecNode: this.stateMachine.node,
|
|
541
566
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
542
|
-
|
|
567
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
543
568
|
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
569
|
+
factService: new FactService(this.factStore, scopes),
|
|
544
570
|
privateEventStore: this.privateEventStore,
|
|
545
|
-
|
|
571
|
+
txResolver: this.stateMachine.txResolver,
|
|
546
572
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
547
573
|
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
548
574
|
jobId: this.currentJobId,
|
|
@@ -9,7 +9,7 @@ import { BlockHeader, GlobalVariables, TxEffect } from '@aztec/stdlib/tx';
|
|
|
9
9
|
* @returns The transaction request hash.
|
|
10
10
|
*/
|
|
11
11
|
export declare function getSingleTxBlockRequestHash(blockNumber: BlockNumber): Fr;
|
|
12
|
-
export declare function insertTxEffectIntoWorldTrees(txEffect: TxEffect, worldTrees: MerkleTreeWriteOperations): Promise<void>;
|
|
12
|
+
export declare function insertTxEffectIntoWorldTrees(txEffect: TxEffect, worldTrees: MerkleTreeWriteOperations, l1ToL2Messages?: Fr[]): Promise<void>;
|
|
13
13
|
export declare function makeTXEBlockHeader(worldTrees: MerkleTreeWriteOperations, globalVariables: GlobalVariables): Promise<BlockHeader>;
|
|
14
14
|
/**
|
|
15
15
|
* Creates an L2Block with proper archive chaining.
|
|
@@ -25,4 +25,4 @@ export declare function makeTXEBlockHeader(worldTrees: MerkleTreeWriteOperations
|
|
|
25
25
|
* @returns The created L2Block with proper archive chaining
|
|
26
26
|
*/
|
|
27
27
|
export declare function makeTXEBlock(worldTrees: MerkleTreeWriteOperations, globalVariables: GlobalVariables, txEffects: TxEffect[]): Promise<L2Block>;
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfY3JlYXRpb24uZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9ibG9ja19jcmVhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNQSxPQUFPLEVBQUUsV0FBVyxFQUEyQyxNQUFNLGlDQUFpQyxDQUFDO0FBRXZHLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQVEsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUF3QyxLQUFLLHlCQUF5QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0csT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFMUU7Ozs7R0FJRztBQUNILHdCQUFnQiwyQkFBMkIsQ0FBQyxXQUFXLEVBQUUsV0FBVyxHQUFHLEVBQUUsQ0FFeEU7QUFFRCx3QkFBc0IsNEJBQTRCLENBQ2hELFFBQVEsRUFBRSxRQUFRLEVBQ2xCLFVBQVUsRUFBRSx5QkFBeUIsRUFDckMsY0FBYyxHQUFFLEVBQUUsRUFBTyxHQUN4QixPQUFPLENBQUMsSUFBSSxDQUFDLENBa0JmO0FBRUQsd0JBQXNCLGtCQUFrQixDQUN0QyxVQUFVLEVBQUUseUJBQXlCLEVBQ3JDLGVBQWUsRUFBRSxlQUFlLEdBQy9CLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FZdEI7QUFFRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCx3QkFBc0IsWUFBWSxDQUNoQyxVQUFVLEVBQUUseUJBQXlCLEVBQ3JDLGVBQWUsRUFBRSxlQUFlLEVBQ2hDLFNBQVMsRUFBRSxRQUFRLEVBQUUsR0FDcEIsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQWlCbEIifQ==
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_creation.d.ts","sourceRoot":"","sources":["../../src/utils/block_creation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAA2C,MAAM,iCAAiC,CAAC;AAEvG,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAQ,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAwC,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW,GAAG,EAAE,CAExE;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,yBAAyB,
|
|
1
|
+
{"version":3,"file":"block_creation.d.ts","sourceRoot":"","sources":["../../src/utils/block_creation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAA2C,MAAM,iCAAiC,CAAC;AAEvG,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAQ,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAwC,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW,GAAG,EAAE,CAExE;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,yBAAyB,EACrC,cAAc,GAAE,EAAE,EAAO,GACxB,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,WAAW,CAAC,CAYtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,QAAQ,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
|
|
@@ -12,10 +12,10 @@ import { BlockHeader } from '@aztec/stdlib/tx';
|
|
|
12
12
|
*/ export function getSingleTxBlockRequestHash(blockNumber) {
|
|
13
13
|
return new Fr(blockNumber + 9999); // Why does this need to be a high number? Why do small numbered nullifiers already exist?
|
|
14
14
|
}
|
|
15
|
-
export async function insertTxEffectIntoWorldTrees(txEffect, worldTrees) {
|
|
15
|
+
export async function insertTxEffectIntoWorldTrees(txEffect, worldTrees, l1ToL2Messages = []) {
|
|
16
16
|
await worldTrees.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, padArrayEnd(txEffect.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX));
|
|
17
17
|
await worldTrees.batchInsert(MerkleTreeId.NULLIFIER_TREE, padArrayEnd(txEffect.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX).map((nullifier)=>nullifier.toBuffer()), NULLIFIER_SUBTREE_HEIGHT);
|
|
18
|
-
await worldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, padArrayEnd(
|
|
18
|
+
await worldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
|
|
19
19
|
// We do not need to add public data writes because we apply them as we go.
|
|
20
20
|
}
|
|
21
21
|
export async function makeTXEBlockHeader(worldTrees, globalVariables) {
|
package/dest/worker.bundle.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { createRequire as __txeCreateRequire } from 'node:module';
|
|
2
2
|
const require = __txeCreateRequire(import.meta.url);
|
|
3
|
-
import{TXEDispatcher,activeSessionCount,createLogger}from"./chunk-
|
|
3
|
+
import{TXEDispatcher,activeSessionCount,createLogger}from"./chunk-IAO54JS2.js";import{__name}from"./chunk-BJVAAXNA.js";import{BackendType,Barretenberg,BarretenbergSync}from"@aztec/bb.js";import{parentPort,workerData}from"node:worker_threads";Barretenberg.initSingleton({backend:BackendType.Wasm,skipSrsInit:!0,threads:1});BarretenbergSync.initSingleton({backend:BackendType.Wasm});if(!parentPort)throw new Error("worker.ts must be loaded as a worker_thread");var port=parentPort,logger=createLogger("txe:worker"),dispatcherOpts={contractStoreSourceDir:workerData.contractStoreSourceDir,schnorrClassId:workerData.schnorrClassId},dispatcher=new TXEDispatcher(logger,dispatcherOpts);function serializeError(err){return err instanceof Error?{message:err.message,name:err.name,stack:err.stack}:{message:String(err)}}__name(serializeError,"serializeError");process.env.TXE_WORKER_MEMSTAT==="1"&&setInterval(()=>{let m=process.memoryUsage();port.postMessage({type:"memstat",sessions:activeSessionCount(),rss:m.rss,heapTotal:m.heapTotal,heapUsed:m.heapUsed,external:m.external,arrayBuffers:m.arrayBuffers})},2e3).unref();port.on("message",msg=>{switch(msg.type){case"foreign-call":(async()=>{try{let value=await dispatcher.resolve_foreign_call(msg.callData);port.postMessage({type:"result",requestId:msg.requestId,ok:!0,value})}catch(err){port.postMessage({type:"result",requestId:msg.requestId,ok:!1,error:serializeError(err)})}})();return;case"dispose-session":dispatcher.disposeSession(msg.sessionId).catch(err=>logger.warn("disposeSession failed",err));return}});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/txe",
|
|
3
|
-
"version": "5.0.0-rc.
|
|
3
|
+
"version": "5.0.0-rc.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./server": {
|
|
@@ -69,22 +69,22 @@
|
|
|
69
69
|
]
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@aztec/accounts": "5.0.0-rc.
|
|
73
|
-
"@aztec/archiver": "5.0.0-rc.
|
|
74
|
-
"@aztec/aztec-node": "5.0.0-rc.
|
|
75
|
-
"@aztec/aztec.js": "5.0.0-rc.
|
|
76
|
-
"@aztec/bb-prover": "5.0.0-rc.
|
|
77
|
-
"@aztec/bb.js": "5.0.0-rc.
|
|
78
|
-
"@aztec/constants": "5.0.0-rc.
|
|
79
|
-
"@aztec/foundation": "5.0.0-rc.
|
|
80
|
-
"@aztec/key-store": "5.0.0-rc.
|
|
81
|
-
"@aztec/kv-store": "5.0.0-rc.
|
|
82
|
-
"@aztec/protocol-contracts": "5.0.0-rc.
|
|
83
|
-
"@aztec/pxe": "5.0.0-rc.
|
|
84
|
-
"@aztec/simulator": "5.0.0-rc.
|
|
85
|
-
"@aztec/standard-contracts": "5.0.0-rc.
|
|
86
|
-
"@aztec/stdlib": "5.0.0-rc.
|
|
87
|
-
"@aztec/world-state": "5.0.0-rc.
|
|
72
|
+
"@aztec/accounts": "5.0.0-rc.2",
|
|
73
|
+
"@aztec/archiver": "5.0.0-rc.2",
|
|
74
|
+
"@aztec/aztec-node": "5.0.0-rc.2",
|
|
75
|
+
"@aztec/aztec.js": "5.0.0-rc.2",
|
|
76
|
+
"@aztec/bb-prover": "5.0.0-rc.2",
|
|
77
|
+
"@aztec/bb.js": "5.0.0-rc.2",
|
|
78
|
+
"@aztec/constants": "5.0.0-rc.2",
|
|
79
|
+
"@aztec/foundation": "5.0.0-rc.2",
|
|
80
|
+
"@aztec/key-store": "5.0.0-rc.2",
|
|
81
|
+
"@aztec/kv-store": "5.0.0-rc.2",
|
|
82
|
+
"@aztec/protocol-contracts": "5.0.0-rc.2",
|
|
83
|
+
"@aztec/pxe": "5.0.0-rc.2",
|
|
84
|
+
"@aztec/simulator": "5.0.0-rc.2",
|
|
85
|
+
"@aztec/standard-contracts": "5.0.0-rc.2",
|
|
86
|
+
"@aztec/stdlib": "5.0.0-rc.2",
|
|
87
|
+
"@aztec/world-state": "5.0.0-rc.2",
|
|
88
88
|
"msgpackr": "^1.11.2",
|
|
89
89
|
"zod": "^4"
|
|
90
90
|
},
|
|
@@ -5,8 +5,8 @@ import { startHttpRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
|
5
5
|
import { createOracleTestRpcServer } from '../oracle/test-resolver/index.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Starts an HTTP RPC server that resolves oracle foreign calls using
|
|
9
|
-
*
|
|
8
|
+
* Starts an HTTP RPC server that resolves oracle foreign calls using auto-synthesized fixture scenarios. Used by
|
|
9
|
+
* `nargo test --oracle-resolver` to run `#[auto_serialization_test]` serialization tests against a dedicated resolver.
|
|
10
10
|
* Logs fixture coverage on shutdown.
|
|
11
11
|
*/
|
|
12
12
|
async function main() {
|
package/src/constants.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PRIVATE_LOG_CIPHERTEXT_LEN } from '@aztec/constants';
|
|
2
2
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
3
|
|
|
4
|
-
export const DEFAULT_ADDRESS = AztecAddress.
|
|
4
|
+
export const DEFAULT_ADDRESS = AztecAddress.fromNumberUnsafe(42);
|
|
5
5
|
|
|
6
6
|
// This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
|
|
7
7
|
export const MAX_PRIVATE_EVENT_LEN = 10;
|
package/src/oracle/interfaces.ts
CHANGED
|
@@ -2,6 +2,9 @@ import { CompleteAddress } from '@aztec/aztec.js/addresses';
|
|
|
2
2
|
import { TxHash } from '@aztec/aztec.js/tx';
|
|
3
3
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
|
+
import type { TaggingSecretStrategy } from '@aztec/pxe/server';
|
|
7
|
+
import type { Option } from '@aztec/pxe/simulator';
|
|
5
8
|
import type { EventSelector, FunctionSelector } from '@aztec/stdlib/abi';
|
|
6
9
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
10
|
import type { GasSettings } from '@aztec/stdlib/gas';
|
|
@@ -42,9 +45,9 @@ export interface IAvmExecutionOracle {
|
|
|
42
45
|
getContractInstanceImmutablesHash(address: AztecAddress): Promise<{ member: Fr; exists: boolean }>;
|
|
43
46
|
returndataSize(): Promise<Fr>;
|
|
44
47
|
returndataCopy(rdOffset: number, copySize: number): Promise<Fr[]>;
|
|
45
|
-
call(l2Gas: number, daGas: number, address: AztecAddress, argsLength: number, args: Fr[]): Promise<
|
|
46
|
-
staticCall(l2Gas: number, daGas: number, address: AztecAddress, argsLength: number, args: Fr[]): Promise<
|
|
47
|
-
successCopy(): Promise<
|
|
48
|
+
call(l2Gas: number, daGas: number, address: AztecAddress, argsLength: number, args: Fr[]): Promise<void>;
|
|
49
|
+
staticCall(l2Gas: number, daGas: number, address: AztecAddress, argsLength: number, args: Fr[]): Promise<void>;
|
|
50
|
+
successCopy(): Promise<boolean>;
|
|
48
51
|
}
|
|
49
52
|
|
|
50
53
|
/**
|
|
@@ -69,6 +72,8 @@ export interface ITxeExecutionOracle {
|
|
|
69
72
|
createAccount(secret: Fr): Promise<CompleteAddress>;
|
|
70
73
|
addAccount(secret: Fr): Promise<CompleteAddress>;
|
|
71
74
|
addAuthWitness(address: AztecAddress, messageHash: Fr): Promise<void>;
|
|
75
|
+
sendL1ToL2Message(content: Fr, secretHash: Fr, sender: EthAddress, recipient: AztecAddress): Promise<Fr>;
|
|
76
|
+
setTaggingSecretStrategy(strategy: Option<TaggingSecretStrategy>): void;
|
|
72
77
|
getLastBlockTimestamp(): Promise<bigint>;
|
|
73
78
|
getLastTxEffects(): Promise<{
|
|
74
79
|
txHash: TxHash;
|
|
@@ -90,6 +95,7 @@ export interface ITxeExecutionOracle {
|
|
|
90
95
|
gasSettings: GasSettings,
|
|
91
96
|
): Promise<{ returnValues: Fr[]; offchainEffects: Fr[][] }>;
|
|
92
97
|
executeUtilityFunction(
|
|
98
|
+
from: AztecAddress | undefined,
|
|
93
99
|
targetContractAddress: AztecAddress,
|
|
94
100
|
functionSelector: FunctionSelector,
|
|
95
101
|
args: Fr[],
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { AztecAddress } from '@aztec/aztec.js/addresses';
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
+
import {
|
|
6
|
+
AZTEC_ADDRESS,
|
|
7
|
+
BIGINT,
|
|
8
|
+
BLOCK_HASH,
|
|
9
|
+
BLOCK_NUMBER,
|
|
10
|
+
BOOL,
|
|
11
|
+
BYTE,
|
|
12
|
+
BoundedVec,
|
|
13
|
+
ETH_ADDRESS,
|
|
14
|
+
FIELD,
|
|
15
|
+
FUNCTION_SELECTOR,
|
|
16
|
+
NOTE_SELECTOR,
|
|
17
|
+
Option,
|
|
18
|
+
type OracleRegistryEntry,
|
|
19
|
+
type TypeMapping,
|
|
20
|
+
U32,
|
|
21
|
+
} from '@aztec/pxe/simulator';
|
|
22
|
+
import { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
|
|
23
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
24
|
+
|
|
25
|
+
import type { OracleTestScenario } from './resolver.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Synthesizes fixture scenarios for every oracle in the registry whose parameters and return are built from scalars,
|
|
29
|
+
* arrays/bounded vecs of them, or `Option`s of them. The matching Noir serialization tests are auto-generated by
|
|
30
|
+
* `#[auto_serialization_test]` from the same seed/scenario convention.
|
|
31
|
+
*/
|
|
32
|
+
export function synthesizeDefaultFixtures(
|
|
33
|
+
registry: Record<string, OracleRegistryEntry>,
|
|
34
|
+
): Record<string, OracleTestScenario[]> {
|
|
35
|
+
const synthesized: Record<string, OracleTestScenario[]> = {};
|
|
36
|
+
|
|
37
|
+
for (const [name, entry] of Object.entries(registry)) {
|
|
38
|
+
const scenarios = synthesizeScenarios(entry);
|
|
39
|
+
if (scenarios !== undefined) {
|
|
40
|
+
synthesized[name] = scenarios;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return synthesized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The test-value implementations, one per oracle type, mirroring the Noir `OracleTestValue` trait exactly
|
|
49
|
+
* (`noir-projects/aztec-nr/.../macros/oracle_testing.nr`).
|
|
50
|
+
*/
|
|
51
|
+
const TEST_VALUE_IMPLS: TestValueImpl[] = [
|
|
52
|
+
scalar(FIELD, seed => new Fr(seed)),
|
|
53
|
+
scalar(U32, seed => seed),
|
|
54
|
+
scalar(BLOCK_NUMBER, seed => BlockNumber(seed)),
|
|
55
|
+
scalar(BIGINT, seed => BigInt(seed)),
|
|
56
|
+
scalar(BYTE, seed => seed),
|
|
57
|
+
scalar(BOOL, seed => seed % 2 !== 0),
|
|
58
|
+
scalar(AZTEC_ADDRESS, seed => AztecAddress.fromNumberUnsafe(seed)),
|
|
59
|
+
scalar(ETH_ADDRESS, seed => EthAddress.fromField(new Fr(seed))),
|
|
60
|
+
scalar(FUNCTION_SELECTOR, seed => FunctionSelector.fromField(new Fr(seed))),
|
|
61
|
+
scalar(NOTE_SELECTOR, seed => NoteSelector.fromField(new Fr(seed))),
|
|
62
|
+
scalar(BLOCK_HASH, seed => new BlockHash(new Fr(seed))),
|
|
63
|
+
composite(isOption, (type, seed) => [
|
|
64
|
+
named(Option.some(firstValue(type.inner, seed)), 'some'),
|
|
65
|
+
named(Option.none(firstValue(type.inner, seed)), 'none'),
|
|
66
|
+
]),
|
|
67
|
+
composite(isArray, (type, seed) => [unnamed(collectionData(type.inner, seed, DEFAULT_ARRAY_LENGTH))]),
|
|
68
|
+
composite(isBoundedVec, (type, seed) => [
|
|
69
|
+
unnamed(
|
|
70
|
+
BoundedVec.from({
|
|
71
|
+
data: collectionData(type.inner, seed, DEFAULT_ARRAY_LENGTH),
|
|
72
|
+
maxLength: BOUNDED_VEC_MAX_LENGTH,
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
]),
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The base every seed is offset by, applied once where a parameter's position becomes its seed, so generated values
|
|
80
|
+
* stay clear of 0. Must match `SEED_BASE` in the Noir `oracle_testing.nr`.
|
|
81
|
+
*/
|
|
82
|
+
const SEED_BASE = 10;
|
|
83
|
+
|
|
84
|
+
/** Elements per synthesized array and bounded vec. Must match `TEST_COLLECTION_LEN` in the Noir `oracle_testing.nr`. */
|
|
85
|
+
const DEFAULT_ARRAY_LENGTH = 3;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Capacity of synthesized bounded vecs, deliberately larger than the data length so padding is exercised. Must match
|
|
89
|
+
* `TEST_BOUNDED_VEC_CAP` in the Noir `oracle_testing.nr`.
|
|
90
|
+
*/
|
|
91
|
+
const BOUNDED_VEC_MAX_LENGTH = 5;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* One canonical test case for a type: the `value` to put on the wire (or expect back), and the `name` of the
|
|
95
|
+
* serialization shape it exercises (unset for single-scenario types). Mirrors the Noir `Scenario<T>`.
|
|
96
|
+
*/
|
|
97
|
+
interface Scenario {
|
|
98
|
+
value: unknown;
|
|
99
|
+
name?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function unnamed(value: unknown): Scenario {
|
|
103
|
+
return { value };
|
|
104
|
+
}
|
|
105
|
+
function named(value: unknown, name: string): Scenario {
|
|
106
|
+
return { value, name };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* One type's test-value implementation, mirroring a Noir `impl OracleTestValue<N> for T`: `match` selects the type and
|
|
111
|
+
* `scenarios` yields its [`Scenario`]s for `seed`, one per serialization shape, like Noir's
|
|
112
|
+
* `oracle_test_value(seed) -> [Scenario<Self>; N]`.
|
|
113
|
+
*/
|
|
114
|
+
interface TestValueImpl {
|
|
115
|
+
match: (type: TypeMapping<any>) => boolean;
|
|
116
|
+
scenarios: (type: TypeMapping<any>, seed: number) => Scenario[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** A scalar impl: matches the singleton `type` by identity and yields a single unnamed scenario. */
|
|
120
|
+
function scalar(type: TypeMapping<any>, value: (seed: number) => unknown): TestValueImpl {
|
|
121
|
+
return { match: t => t === type, scenarios: (_type, seed) => [unnamed(value(seed))] };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** A composite impl: selected by the `kind` type guard, recursing through its element/inner mapping. */
|
|
125
|
+
function composite<K extends CompositeMapping>(
|
|
126
|
+
guard: (type: TypeMapping<any>) => type is K,
|
|
127
|
+
scenarios: (type: K, seed: number) => Scenario[],
|
|
128
|
+
): TestValueImpl {
|
|
129
|
+
return { match: guard, scenarios: (type, seed) => scenarios(type as K, seed) };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Synthesized element values for a collection. */
|
|
133
|
+
function collectionData(element: TypeMapping<any>, seed: number, length: number): unknown[] {
|
|
134
|
+
return Array.from({ length }, (_, i) => firstValue(element, seed + i));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* The [`Scenario`]s for `type` at `seed`, one per serialization *shape*, mirroring the Noir
|
|
139
|
+
* `OracleTestValue::oracle_test_value(seed) -> [Scenario<Self>; N]`. Throws if the type has no matching impl.
|
|
140
|
+
*/
|
|
141
|
+
function scenariosForType(type: TypeMapping<any>, seed: number): Scenario[] {
|
|
142
|
+
const impl = TEST_VALUE_IMPLS.find(i => i.match(type));
|
|
143
|
+
if (!impl) {
|
|
144
|
+
throw new UnsynthesizableTypeError(type);
|
|
145
|
+
}
|
|
146
|
+
return impl.scenarios(type, seed);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** The first (representative) test value of `type`, used for collection elements and `Option` inners. */
|
|
150
|
+
function firstValue(type: TypeMapping<any>, seed: number): unknown {
|
|
151
|
+
return scenariosForType(type, seed)[0].value;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
class UnsynthesizableTypeError extends Error {
|
|
155
|
+
constructor(type: TypeMapping<any>) {
|
|
156
|
+
super(`No test-value impl for type: ${JSON.stringify(Object.keys(type))}`);
|
|
157
|
+
this.name = 'UnsynthesizableTypeError';
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Synthesizes the scenarios for one oracle by zipping every position's [`Scenario`] list to one case per test (a
|
|
163
|
+
* shorter list wraps around via mod), mirroring the Noir macro. Returns `undefined` if any param or return type is
|
|
164
|
+
* unsynthesizable (structs, ephemeral arrays).
|
|
165
|
+
*/
|
|
166
|
+
function synthesizeScenarios(entry: OracleRegistryEntry): OracleTestScenario[] | undefined {
|
|
167
|
+
try {
|
|
168
|
+
return synthesizeScenariosOrThrow(entry);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
if (e instanceof UnsynthesizableTypeError) {
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
throw e;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function synthesizeScenariosOrThrow(entry: OracleRegistryEntry): OracleTestScenario[] {
|
|
178
|
+
const params = entry.params.map((param, index) => ({
|
|
179
|
+
name: param.name,
|
|
180
|
+
scenarios: scenariosForType(param.type, SEED_BASE + index),
|
|
181
|
+
}));
|
|
182
|
+
// The return's seed is the slot right after the last parameter, so its value is distinct from every parameter.
|
|
183
|
+
const returnScenarios =
|
|
184
|
+
entry.returnType === undefined ? undefined : scenariosForType(entry.returnType, SEED_BASE + entry.params.length);
|
|
185
|
+
|
|
186
|
+
// Positions with more than one scenario drive the test count; their names are zipped together (joined with `+`) per
|
|
187
|
+
// test, matching the announcements the Noir tests emit and the resolver joins.
|
|
188
|
+
const positions = [...params.map(p => p.scenarios), ...(returnScenarios !== undefined ? [returnScenarios] : [])];
|
|
189
|
+
const namedPositions = positions.filter(s => s.length > 1);
|
|
190
|
+
const testCount = Math.max(1, ...positions.map(s => s.length));
|
|
191
|
+
|
|
192
|
+
const scenarios: OracleTestScenario[] = [];
|
|
193
|
+
for (let index = 0; index < testCount; index++) {
|
|
194
|
+
const inputs: Record<string, unknown> = {};
|
|
195
|
+
for (const { name, scenarios: cases } of params) {
|
|
196
|
+
inputs[name] = cases[index % cases.length].value;
|
|
197
|
+
}
|
|
198
|
+
const output = returnScenarios === undefined ? undefined : returnScenarios[index % returnScenarios.length].value;
|
|
199
|
+
const scenario =
|
|
200
|
+
namedPositions.length === 0
|
|
201
|
+
? undefined
|
|
202
|
+
: namedPositions.map(cases => cases[index % cases.length].name!).join('+');
|
|
203
|
+
scenarios.push({ scenario, inputs, output });
|
|
204
|
+
}
|
|
205
|
+
return scenarios;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* The composite `TypeMapping`s (`ARRAY`/`BOUNDED_VEC`/`OPTION`), discriminated by `kind`. The combinators attach `kind`
|
|
210
|
+
* plus the inner mapping at construction; the registry erases params to the base `TypeMapping`, so the guards below
|
|
211
|
+
* recover the structure for recursion.
|
|
212
|
+
*/
|
|
213
|
+
type ArrayMapping = TypeMapping & { kind: 'array'; inner: TypeMapping };
|
|
214
|
+
type BoundedVecMapping = TypeMapping & { kind: 'bounded-vec'; inner: TypeMapping };
|
|
215
|
+
type OptionMapping = TypeMapping & { kind: 'option'; inner: TypeMapping };
|
|
216
|
+
type CompositeMapping = ArrayMapping | BoundedVecMapping | OptionMapping;
|
|
217
|
+
|
|
218
|
+
function isArray(type: TypeMapping<any>): type is ArrayMapping {
|
|
219
|
+
return 'kind' in type && type.kind === 'array';
|
|
220
|
+
}
|
|
221
|
+
function isBoundedVec(type: TypeMapping<any>): type is BoundedVecMapping {
|
|
222
|
+
return 'kind' in type && type.kind === 'bounded-vec';
|
|
223
|
+
}
|
|
224
|
+
function isOption(type: TypeMapping<any>): type is OptionMapping {
|
|
225
|
+
return 'kind' in type && type.kind === 'option';
|
|
226
|
+
}
|
|
@@ -8,7 +8,6 @@ import { z } from 'zod';
|
|
|
8
8
|
|
|
9
9
|
import { ForeignCallArgsSchema, type ForeignCallResult, ForeignCallResultSchema } from '../../utils/encoding.js';
|
|
10
10
|
import { TXE_ORACLE_REGISTRY } from '../txe_oracle_registry.js';
|
|
11
|
-
import { ORACLE_TEST_FIXTURES } from './fixtures.js';
|
|
12
11
|
import { type OracleTestCallInput, OracleTestResolver } from './resolver.js';
|
|
13
12
|
|
|
14
13
|
const OracleTestCallInputSchema = zodFor<OracleTestCallInput>()(
|
|
@@ -35,7 +34,7 @@ const OracleTestRpcHandlerSchema: ApiSchemaFor<OracleTestRpcHandler> = {
|
|
|
35
34
|
|
|
36
35
|
/** Creates an RPC server backed by the oracle test resolver. */
|
|
37
36
|
export function createOracleTestRpcServer(logger: Logger) {
|
|
38
|
-
const resolver =
|
|
37
|
+
const resolver = OracleTestResolver.fromRegistry(TXE_ORACLE_REGISTRY, logger);
|
|
39
38
|
const server = createSafeJsonRpcServer<OracleTestRpcHandler>(resolver, OracleTestRpcHandlerSchema, {
|
|
40
39
|
http200OnError: true,
|
|
41
40
|
});
|