@aztec/txe 0.0.1-commit.2ed92850 → 0.0.1-commit.43597cc1
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/oracle/interfaces.d.ts +2 -2
- 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 +2 -2
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +34 -15
- package/dest/rpc_translator.d.ts +7 -7
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +40 -29
- 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 +4 -3
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +5 -2
- 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 +14 -9
- 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 +1 -1
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +11 -8
- 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/oracle/interfaces.ts +1 -1
- package/src/oracle/txe_oracle_public_context.ts +3 -5
- package/src/oracle/txe_oracle_top_level_context.ts +63 -27
- package/src/rpc_translator.ts +42 -24
- package/src/state_machine/archiver.ts +2 -0
- package/src/state_machine/dummy_p2p_client.ts +7 -2
- package/src/state_machine/index.ts +24 -9
- package/src/state_machine/mock_epoch_cache.ts +5 -0
- package/src/txe_session.ts +13 -14
- package/src/utils/block_creation.ts +3 -1
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
SenderAddressBookStore,
|
|
23
23
|
SenderTaggingStore,
|
|
24
24
|
enrichPublicSimulationError,
|
|
25
|
-
syncState,
|
|
26
25
|
} from '@aztec/pxe/server';
|
|
27
26
|
import {
|
|
28
27
|
ExecutionNoteCache,
|
|
@@ -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
|
-
utilityDebugLog(level: number, message: string, fields: Fr[]): void {
|
|
134
|
+
utilityDebugLog(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
136
135
|
if (!LogLevels[level]) {
|
|
137
136
|
throw new Error(`Invalid debug 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 {
|
|
@@ -297,12 +297,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
297
297
|
throw new Error(message);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
// When `from` is the zero address (used when creating a new contract account for example),
|
|
301
|
+
// we disable scope filtering by setting effectiveScopes to undefined. This allows these operations
|
|
302
|
+
// to proceed without requiring keys registered for the zero address.
|
|
303
|
+
const effectiveScopes = from.isZero() ? undefined : [from];
|
|
304
|
+
|
|
300
305
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
301
306
|
const utilityExecutor = async (call: FunctionCall) => {
|
|
302
|
-
await this.executeUtilityCall(call);
|
|
307
|
+
await this.executeUtilityCall(call, effectiveScopes);
|
|
303
308
|
};
|
|
304
309
|
|
|
305
|
-
await
|
|
310
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
311
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
312
|
+
targetContractAddress,
|
|
313
|
+
functionSelector,
|
|
314
|
+
utilityExecutor,
|
|
315
|
+
blockHeader,
|
|
316
|
+
this.jobId,
|
|
317
|
+
);
|
|
306
318
|
|
|
307
319
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
308
320
|
|
|
@@ -314,8 +326,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
314
326
|
|
|
315
327
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
316
328
|
|
|
317
|
-
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
318
|
-
|
|
319
329
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
320
330
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
321
331
|
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
@@ -346,17 +356,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
346
356
|
this.keyStore,
|
|
347
357
|
this.addressStore,
|
|
348
358
|
this.stateMachine.node,
|
|
349
|
-
this.stateMachine.anchorBlockStore,
|
|
350
359
|
this.senderTaggingStore,
|
|
351
360
|
this.recipientTaggingStore,
|
|
352
361
|
this.senderAddressBookStore,
|
|
353
362
|
this.capsuleStore,
|
|
354
363
|
this.privateEventStore,
|
|
364
|
+
this.stateMachine.contractSyncService,
|
|
355
365
|
this.jobId,
|
|
356
366
|
0, // totalPublicArgsCount
|
|
357
367
|
minRevertibleSideEffectCounter, // (start) sideEffectCounter
|
|
358
368
|
undefined, // log
|
|
359
|
-
|
|
369
|
+
effectiveScopes, // scopes
|
|
360
370
|
/**
|
|
361
371
|
* In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
362
372
|
* contract would perform, including setting senderForTags.
|
|
@@ -402,7 +412,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
402
412
|
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
403
413
|
const { publicInputs } = await generateSimulatedProvingResult(
|
|
404
414
|
result,
|
|
405
|
-
this.contractStore,
|
|
415
|
+
(addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
|
|
406
416
|
minRevertibleSideEffectCounter,
|
|
407
417
|
);
|
|
408
418
|
|
|
@@ -415,7 +425,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
415
425
|
|
|
416
426
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
417
427
|
|
|
418
|
-
const
|
|
428
|
+
const bindings = this.logger.getBindings();
|
|
429
|
+
const contractsDB = new PublicContractsDB(
|
|
430
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
431
|
+
bindings,
|
|
432
|
+
);
|
|
419
433
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
420
434
|
const config = PublicSimulatorConfig.from({
|
|
421
435
|
skipFeeEnforcement: true,
|
|
@@ -428,8 +442,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
428
442
|
globals,
|
|
429
443
|
guardedMerkleTrees,
|
|
430
444
|
contractsDB,
|
|
431
|
-
new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
|
|
445
|
+
new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
|
|
432
446
|
new TestDateProvider(),
|
|
447
|
+
undefined,
|
|
448
|
+
createLogger('simulator:public-processor', bindings),
|
|
433
449
|
);
|
|
434
450
|
|
|
435
451
|
const tx = await Tx.create({
|
|
@@ -526,7 +542,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
526
542
|
|
|
527
543
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
528
544
|
|
|
529
|
-
const
|
|
545
|
+
const bindings2 = this.logger.getBindings();
|
|
546
|
+
const contractsDB = new PublicContractsDB(
|
|
547
|
+
new TXEPublicContractDataSource(blockNumber, this.contractStore),
|
|
548
|
+
bindings2,
|
|
549
|
+
);
|
|
530
550
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
531
551
|
const config = PublicSimulatorConfig.from({
|
|
532
552
|
skipFeeEnforcement: true,
|
|
@@ -535,8 +555,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
535
555
|
collectStatistics: false,
|
|
536
556
|
collectCallMetadata: true,
|
|
537
557
|
});
|
|
538
|
-
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
|
|
539
|
-
const processor = new PublicProcessor(
|
|
558
|
+
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
559
|
+
const processor = new PublicProcessor(
|
|
560
|
+
globals,
|
|
561
|
+
guardedMerkleTrees,
|
|
562
|
+
contractsDB,
|
|
563
|
+
simulator,
|
|
564
|
+
new TestDateProvider(),
|
|
565
|
+
undefined,
|
|
566
|
+
createLogger('simulator:public-processor', bindings2),
|
|
567
|
+
);
|
|
540
568
|
|
|
541
569
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
542
570
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
@@ -646,25 +674,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
646
674
|
}
|
|
647
675
|
|
|
648
676
|
// 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,
|
|
677
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
678
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(
|
|
655
679
|
targetContractAddress,
|
|
656
680
|
functionSelector,
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
681
|
+
async call => {
|
|
682
|
+
await this.executeUtilityCall(call);
|
|
683
|
+
},
|
|
684
|
+
blockHeader,
|
|
685
|
+
this.jobId,
|
|
662
686
|
);
|
|
663
687
|
|
|
688
|
+
const call = FunctionCall.from({
|
|
689
|
+
name: artifact.name,
|
|
690
|
+
to: targetContractAddress,
|
|
691
|
+
selector: functionSelector,
|
|
692
|
+
type: FunctionType.UTILITY,
|
|
693
|
+
hideMsgSender: false,
|
|
694
|
+
isStatic: false,
|
|
695
|
+
args,
|
|
696
|
+
returnTypes: [],
|
|
697
|
+
});
|
|
698
|
+
|
|
664
699
|
return this.executeUtilityCall(call);
|
|
665
700
|
}
|
|
666
701
|
|
|
667
|
-
private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
|
|
702
|
+
private async executeUtilityCall(call: FunctionCall, scopes?: AztecAddress[]): Promise<Fr[]> {
|
|
668
703
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
669
704
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
670
705
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -687,12 +722,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
687
722
|
this.keyStore,
|
|
688
723
|
this.addressStore,
|
|
689
724
|
this.stateMachine.node,
|
|
690
|
-
this.stateMachine.anchorBlockStore,
|
|
691
725
|
this.recipientTaggingStore,
|
|
692
726
|
this.senderAddressBookStore,
|
|
693
727
|
this.capsuleStore,
|
|
694
728
|
this.privateEventStore,
|
|
695
729
|
this.jobId,
|
|
730
|
+
undefined, // log
|
|
731
|
+
scopes, // scopes - used to filter notes by account
|
|
696
732
|
);
|
|
697
733
|
const acirExecutionResult = await new WASMSimulator()
|
|
698
734
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
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';
|
|
@@ -328,7 +328,7 @@ export class RPCTranslator {
|
|
|
328
328
|
|
|
329
329
|
// When the argument is a slice, noir automatically adds a length field to oracle call.
|
|
330
330
|
// When the argument is an array, we add the field length manually to the signature.
|
|
331
|
-
utilityDebugLog(
|
|
331
|
+
async utilityDebugLog(
|
|
332
332
|
foreignLevel: ForeignCallSingle,
|
|
333
333
|
foreignMessage: ForeignCallArray,
|
|
334
334
|
_foreignLength: ForeignCallSingle,
|
|
@@ -340,7 +340,7 @@ export class RPCTranslator {
|
|
|
340
340
|
.join('');
|
|
341
341
|
const fields = fromArray(foreignFields);
|
|
342
342
|
|
|
343
|
-
this.handlerAsMisc().utilityDebugLog(level, message, fields);
|
|
343
|
+
await this.handlerAsMisc().utilityDebugLog(level, message, fields);
|
|
344
344
|
|
|
345
345
|
return toForeignCallResult([]);
|
|
346
346
|
}
|
|
@@ -351,7 +351,7 @@ export class RPCTranslator {
|
|
|
351
351
|
foreignStartStorageSlot: ForeignCallSingle,
|
|
352
352
|
foreignNumberOfElements: ForeignCallSingle,
|
|
353
353
|
) {
|
|
354
|
-
const blockHash =
|
|
354
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
355
355
|
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
356
356
|
const startStorageSlot = fromSingle(foreignStartStorageSlot);
|
|
357
357
|
const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
|
|
@@ -367,7 +367,7 @@ export class RPCTranslator {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
|
|
370
|
-
const blockHash =
|
|
370
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
371
371
|
const leafSlot = fromSingle(foreignLeafSlot);
|
|
372
372
|
|
|
373
373
|
const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
|
|
@@ -545,12 +545,23 @@ export class RPCTranslator {
|
|
|
545
545
|
);
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
-
async
|
|
548
|
+
async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
|
|
549
549
|
const address = addressFromSingle(foreignAddress);
|
|
550
550
|
|
|
551
|
-
const
|
|
551
|
+
const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
|
|
552
552
|
|
|
553
|
-
return
|
|
553
|
+
// We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
|
|
554
|
+
// with two fields: `some` (a boolean) and `value` (a field array in this case).
|
|
555
|
+
if (result === undefined) {
|
|
556
|
+
// No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
|
|
557
|
+
return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
|
|
558
|
+
} else {
|
|
559
|
+
// Data was found so we set `some` to 1 and return it along with `value`.
|
|
560
|
+
return toForeignCallResult([
|
|
561
|
+
toSingle(new Fr(1)),
|
|
562
|
+
toArray([...result.publicKeys.toFields(), result.partialAddress]),
|
|
563
|
+
]);
|
|
564
|
+
}
|
|
554
565
|
}
|
|
555
566
|
|
|
556
567
|
async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
|
|
@@ -574,7 +585,7 @@ export class RPCTranslator {
|
|
|
574
585
|
}
|
|
575
586
|
|
|
576
587
|
async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
|
|
577
|
-
const blockHash =
|
|
588
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
578
589
|
const nullifier = fromSingle(foreignNullifier);
|
|
579
590
|
|
|
580
591
|
const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -641,26 +652,34 @@ export class RPCTranslator {
|
|
|
641
652
|
return toForeignCallResult(header.toFields().map(toSingle));
|
|
642
653
|
}
|
|
643
654
|
|
|
644
|
-
async utilityGetNoteHashMembershipWitness(
|
|
645
|
-
|
|
646
|
-
|
|
655
|
+
async utilityGetNoteHashMembershipWitness(
|
|
656
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
657
|
+
foreignNoteHash: ForeignCallSingle,
|
|
658
|
+
) {
|
|
659
|
+
const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
660
|
+
const noteHash = fromSingle(foreignNoteHash);
|
|
647
661
|
|
|
648
|
-
const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash,
|
|
662
|
+
const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
|
|
649
663
|
|
|
650
664
|
if (!witness) {
|
|
651
|
-
throw new Error(`Note hash ${
|
|
665
|
+
throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
|
|
652
666
|
}
|
|
653
667
|
return toForeignCallResult(witness.toNoirRepresentation());
|
|
654
668
|
}
|
|
655
669
|
|
|
656
|
-
async
|
|
657
|
-
|
|
658
|
-
|
|
670
|
+
async utilityGetBlockHashMembershipWitness(
|
|
671
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
672
|
+
foreignBlockHash: ForeignCallSingle,
|
|
673
|
+
) {
|
|
674
|
+
const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
675
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
659
676
|
|
|
660
|
-
const witness = await this.handlerAsUtility().
|
|
677
|
+
const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
|
|
661
678
|
|
|
662
679
|
if (!witness) {
|
|
663
|
-
throw new Error(
|
|
680
|
+
throw new Error(
|
|
681
|
+
`Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
|
|
682
|
+
);
|
|
664
683
|
}
|
|
665
684
|
return toForeignCallResult(witness.toNoirRepresentation());
|
|
666
685
|
}
|
|
@@ -669,7 +688,7 @@ export class RPCTranslator {
|
|
|
669
688
|
foreignBlockHash: ForeignCallSingle,
|
|
670
689
|
foreignNullifier: ForeignCallSingle,
|
|
671
690
|
) {
|
|
672
|
-
const blockHash =
|
|
691
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
673
692
|
const nullifier = fromSingle(foreignNullifier);
|
|
674
693
|
|
|
675
694
|
const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -911,11 +930,10 @@ export class RPCTranslator {
|
|
|
911
930
|
return toForeignCallResult([]);
|
|
912
931
|
}
|
|
913
932
|
|
|
914
|
-
async avmOpcodeNullifierExists(
|
|
915
|
-
const
|
|
916
|
-
const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
|
|
933
|
+
async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
|
|
934
|
+
const siloedNullifier = fromSingle(foreignSiloedNullifier);
|
|
917
935
|
|
|
918
|
-
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(
|
|
936
|
+
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
|
|
919
937
|
|
|
920
938
|
return toForeignCallResult([toSingle(new Fr(exists))]);
|
|
921
939
|
}
|
|
@@ -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}`);
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
P2PBlockReceivedCallback,
|
|
7
7
|
P2PCheckpointReceivedCallback,
|
|
8
8
|
P2PConfig,
|
|
9
|
+
P2PDuplicateProposalCallback,
|
|
9
10
|
P2PSyncState,
|
|
10
11
|
PeerId,
|
|
11
12
|
ReqRespSubProtocol,
|
|
@@ -133,8 +134,8 @@ export class DummyP2P implements P2P {
|
|
|
133
134
|
throw new Error('DummyP2P does not implement "getCheckpointAttestationsForSlot"');
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
public
|
|
137
|
-
throw new Error('DummyP2P does not implement "
|
|
137
|
+
public addOwnCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
|
|
138
|
+
throw new Error('DummyP2P does not implement "addOwnCheckpointAttestations"');
|
|
138
139
|
}
|
|
139
140
|
|
|
140
141
|
public getL2BlockHash(_number: number): Promise<string | undefined> {
|
|
@@ -206,4 +207,8 @@ export class DummyP2P implements P2P {
|
|
|
206
207
|
|
|
207
208
|
//This is no-op
|
|
208
209
|
public registerThisValidatorAddresses(_address: EthAddress[]): void {}
|
|
210
|
+
|
|
211
|
+
public registerDuplicateProposalCallback(_callback: P2PDuplicateProposalCallback): void {
|
|
212
|
+
throw new Error('DummyP2P does not implement "registerDuplicateProposalCallback"');
|
|
213
|
+
}
|
|
209
214
|
}
|
|
@@ -3,8 +3,7 @@ import { TestCircuitVerifier } from '@aztec/bb-prover/test';
|
|
|
3
3
|
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
-
import type
|
|
7
|
-
import { AnchorBlockStore } from '@aztec/pxe/server';
|
|
6
|
+
import { type AnchorBlockStore, type ContractStore, ContractSyncService, type NoteStore } from '@aztec/pxe/server';
|
|
8
7
|
import { L2Block } from '@aztec/stdlib/block';
|
|
9
8
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
10
9
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
@@ -26,13 +25,16 @@ export class TXEStateMachine {
|
|
|
26
25
|
public synchronizer: TXESynchronizer,
|
|
27
26
|
public archiver: TXEArchiver,
|
|
28
27
|
public anchorBlockStore: AnchorBlockStore,
|
|
28
|
+
public contractSyncService: ContractSyncService,
|
|
29
29
|
) {}
|
|
30
30
|
|
|
31
|
-
public static async create(
|
|
32
|
-
|
|
31
|
+
public static async create(
|
|
32
|
+
archiver: TXEArchiver,
|
|
33
|
+
anchorBlockStore: AnchorBlockStore,
|
|
34
|
+
contractStore: ContractStore,
|
|
35
|
+
noteStore: NoteStore,
|
|
36
|
+
) {
|
|
33
37
|
const synchronizer = await TXESynchronizer.create();
|
|
34
|
-
const anchorBlockStore = new AnchorBlockStore(db);
|
|
35
|
-
|
|
36
38
|
const aztecNodeConfig = {} as AztecNodeConfig;
|
|
37
39
|
|
|
38
40
|
const log = createLogger('txe_node');
|
|
@@ -58,11 +60,21 @@ export class TXEStateMachine {
|
|
|
58
60
|
log,
|
|
59
61
|
);
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
const contractSyncService = new ContractSyncService(
|
|
64
|
+
node,
|
|
65
|
+
contractStore,
|
|
66
|
+
noteStore,
|
|
67
|
+
createLogger('txe:contract_sync'),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return new this(node, synchronizer, archiver, anchorBlockStore, contractSyncService);
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
public async handleL2Block(block: L2Block) {
|
|
65
|
-
// Create a checkpoint from the block manually
|
|
74
|
+
// Create a checkpoint from the block manually.
|
|
75
|
+
// TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
|
|
76
|
+
// This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
|
|
77
|
+
const checkpointNumber = CheckpointNumber.fromBlockNumber(block.number);
|
|
66
78
|
const checkpoint = new Checkpoint(
|
|
67
79
|
block.archive,
|
|
68
80
|
CheckpointHeader.from({
|
|
@@ -79,7 +91,7 @@ export class TXEStateMachine {
|
|
|
79
91
|
totalManaUsed: block.header.totalManaUsed,
|
|
80
92
|
}),
|
|
81
93
|
[block],
|
|
82
|
-
|
|
94
|
+
checkpointNumber,
|
|
83
95
|
);
|
|
84
96
|
|
|
85
97
|
const publishedCheckpoint = new PublishedCheckpoint(
|
|
@@ -91,6 +103,9 @@ export class TXEStateMachine {
|
|
|
91
103
|
),
|
|
92
104
|
[],
|
|
93
105
|
);
|
|
106
|
+
// Wipe contract sync cache when anchor block changes (mirrors BlockSynchronizer behavior)
|
|
107
|
+
this.contractSyncService.wipe();
|
|
108
|
+
|
|
94
109
|
await Promise.all([
|
|
95
110
|
this.synchronizer.handleL2Block(block),
|
|
96
111
|
this.archiver.addCheckpoints([publishedCheckpoint], undefined),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EpochAndSlot, EpochCacheInterface, EpochCommitteeInfo, SlotTag } from '@aztec/epoch-cache';
|
|
2
2
|
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
+
import { EmptyL1RollupConstants, type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Mock implementation of the EpochCacheInterface used to satisfy dependencies of AztecNodeService.
|
|
@@ -64,4 +65,8 @@ export class MockEpochCache implements EpochCacheInterface {
|
|
|
64
65
|
filterInCommittee(_slot: SlotTag, _validators: EthAddress[]): Promise<EthAddress[]> {
|
|
65
66
|
return Promise.resolve([]);
|
|
66
67
|
}
|
|
68
|
+
|
|
69
|
+
getL1Constants(): L1RollupConstants {
|
|
70
|
+
return EmptyL1RollupConstants;
|
|
71
|
+
}
|
|
67
72
|
}
|
package/src/txe_session.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
|
6
6
|
import type { ProtocolContract } from '@aztec/protocol-contracts';
|
|
7
7
|
import {
|
|
8
8
|
AddressStore,
|
|
9
|
+
AnchorBlockStore,
|
|
9
10
|
CapsuleStore,
|
|
10
11
|
JobCoordinator,
|
|
11
12
|
NoteService,
|
|
@@ -49,6 +50,7 @@ import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfac
|
|
|
49
50
|
import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
|
|
50
51
|
import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
|
|
51
52
|
import { RPCTranslator } from './rpc_translator.js';
|
|
53
|
+
import { TXEArchiver } from './state_machine/archiver.js';
|
|
52
54
|
import { TXEStateMachine } from './state_machine/index.js';
|
|
53
55
|
import type { ForeignCallArgs, ForeignCallResult } from './util/encoding.js';
|
|
54
56
|
import { TXEAccountStore } from './util/txe_account_store.js';
|
|
@@ -176,7 +178,9 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
176
178
|
await contractStore.addContractInstance(instance);
|
|
177
179
|
}
|
|
178
180
|
|
|
179
|
-
const
|
|
181
|
+
const archiver = new TXEArchiver(store);
|
|
182
|
+
const anchorBlockStore = new AnchorBlockStore(store);
|
|
183
|
+
const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
|
|
180
184
|
|
|
181
185
|
const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
|
|
182
186
|
const version = new Fr(await stateMachine.node.getVersion());
|
|
@@ -312,17 +316,14 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
312
316
|
): Promise<PrivateContextInputs> {
|
|
313
317
|
this.exitTopLevelState();
|
|
314
318
|
|
|
315
|
-
await new NoteService(
|
|
316
|
-
this.noteStore,
|
|
317
|
-
this.stateMachine.node,
|
|
318
|
-
this.stateMachine.anchorBlockStore,
|
|
319
|
-
this.currentJobId,
|
|
320
|
-
).syncNoteNullifiers(contractAddress);
|
|
321
|
-
|
|
322
319
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
323
320
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
324
321
|
// a single transaction with the effects of what was done in the test.
|
|
325
322
|
const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
|
|
323
|
+
|
|
324
|
+
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
325
|
+
contractAddress,
|
|
326
|
+
);
|
|
326
327
|
const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
|
|
327
328
|
|
|
328
329
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
@@ -354,12 +355,12 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
354
355
|
this.keyStore,
|
|
355
356
|
this.addressStore,
|
|
356
357
|
this.stateMachine.node,
|
|
357
|
-
this.stateMachine.anchorBlockStore,
|
|
358
358
|
this.senderTaggingStore,
|
|
359
359
|
this.recipientTaggingStore,
|
|
360
360
|
this.senderAddressBookStore,
|
|
361
361
|
this.capsuleStore,
|
|
362
362
|
this.privateEventStore,
|
|
363
|
+
this.stateMachine.contractSyncService,
|
|
363
364
|
this.currentJobId,
|
|
364
365
|
);
|
|
365
366
|
|
|
@@ -401,6 +402,8 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
401
402
|
async enterUtilityState(contractAddress: AztecAddress = DEFAULT_ADDRESS) {
|
|
402
403
|
this.exitTopLevelState();
|
|
403
404
|
|
|
405
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
406
|
+
|
|
404
407
|
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
405
408
|
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
406
409
|
// we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
|
|
@@ -409,12 +412,10 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
409
412
|
await new NoteService(
|
|
410
413
|
this.noteStore,
|
|
411
414
|
this.stateMachine.node,
|
|
412
|
-
|
|
415
|
+
anchorBlockHeader,
|
|
413
416
|
this.currentJobId,
|
|
414
417
|
).syncNoteNullifiers(contractAddress);
|
|
415
418
|
|
|
416
|
-
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
417
|
-
|
|
418
419
|
this.oracleHandler = new UtilityExecutionOracle(
|
|
419
420
|
contractAddress,
|
|
420
421
|
[],
|
|
@@ -425,7 +426,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
425
426
|
this.keyStore,
|
|
426
427
|
this.addressStore,
|
|
427
428
|
this.stateMachine.node,
|
|
428
|
-
this.stateMachine.anchorBlockStore,
|
|
429
429
|
this.recipientTaggingStore,
|
|
430
430
|
this.senderAddressBookStore,
|
|
431
431
|
this.capsuleStore,
|
|
@@ -516,7 +516,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
516
516
|
this.keyStore,
|
|
517
517
|
this.addressStore,
|
|
518
518
|
this.stateMachine.node,
|
|
519
|
-
this.stateMachine.anchorBlockStore,
|
|
520
519
|
this.recipientTaggingStore,
|
|
521
520
|
this.senderAddressBookStore,
|
|
522
521
|
this.capsuleStore,
|
|
@@ -87,7 +87,9 @@ export async function makeTXEBlock(
|
|
|
87
87
|
const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
88
88
|
const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size));
|
|
89
89
|
|
|
90
|
-
// L2Block requires checkpointNumber and indexWithinCheckpoint
|
|
90
|
+
// L2Block requires checkpointNumber and indexWithinCheckpoint.
|
|
91
|
+
// TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
|
|
92
|
+
// This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
|
|
91
93
|
const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
|
|
92
94
|
const indexWithinCheckpoint = IndexWithinCheckpoint(0);
|
|
93
95
|
|