@aztec/txe 0.0.1-commit.f295ac2 → 0.0.1-commit.f2ce05ee
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 +3 -3
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +5 -5
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +6 -6
- 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 +33 -14
- package/dest/rpc_translator.d.ts +15 -9
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +63 -39
- package/dest/state_machine/archiver.d.ts +2 -2
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +7 -6
- 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 +7 -7
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +30 -16
- package/dest/state_machine/mock_epoch_cache.d.ts +8 -6
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +9 -6
- package/dest/state_machine/synchronizer.d.ts +3 -3
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/txe_session.d.ts +1 -1
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +14 -10
- package/dest/utils/block_creation.d.ts +5 -5
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +7 -5
- package/package.json +15 -15
- package/src/oracle/interfaces.ts +2 -2
- package/src/oracle/txe_oracle_public_context.ts +8 -10
- package/src/oracle/txe_oracle_top_level_context.ts +63 -26
- package/src/rpc_translator.ts +65 -37
- package/src/state_machine/archiver.ts +6 -8
- package/src/state_machine/dummy_p2p_client.ts +7 -2
- package/src/state_machine/index.ts +48 -19
- package/src/state_machine/mock_epoch_cache.ts +10 -11
- package/src/state_machine/synchronizer.ts +2 -2
- package/src/txe_session.ts +22 -15
- package/src/utils/block_creation.ts +8 -6
package/src/rpc_translator.ts
CHANGED
|
@@ -6,12 +6,11 @@ import {
|
|
|
6
6
|
type IMiscOracle,
|
|
7
7
|
type IPrivateExecutionOracle,
|
|
8
8
|
type IUtilityExecutionOracle,
|
|
9
|
-
|
|
9
|
+
packAsHintedNote,
|
|
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 {
|
|
14
|
-
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
13
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
15
14
|
|
|
16
15
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
17
16
|
import type { TXESessionStateHandler } from './txe_session.js';
|
|
@@ -329,7 +328,7 @@ export class RPCTranslator {
|
|
|
329
328
|
|
|
330
329
|
// When the argument is a slice, noir automatically adds a length field to oracle call.
|
|
331
330
|
// When the argument is an array, we add the field length manually to the signature.
|
|
332
|
-
utilityDebugLog(
|
|
331
|
+
async utilityDebugLog(
|
|
333
332
|
foreignLevel: ForeignCallSingle,
|
|
334
333
|
foreignMessage: ForeignCallArray,
|
|
335
334
|
_foreignLength: ForeignCallSingle,
|
|
@@ -341,7 +340,7 @@ export class RPCTranslator {
|
|
|
341
340
|
.join('');
|
|
342
341
|
const fields = fromArray(foreignFields);
|
|
343
342
|
|
|
344
|
-
this.handlerAsMisc().utilityDebugLog(level, message, fields);
|
|
343
|
+
await this.handlerAsMisc().utilityDebugLog(level, message, fields);
|
|
345
344
|
|
|
346
345
|
return toForeignCallResult([]);
|
|
347
346
|
}
|
|
@@ -352,7 +351,7 @@ export class RPCTranslator {
|
|
|
352
351
|
foreignStartStorageSlot: ForeignCallSingle,
|
|
353
352
|
foreignNumberOfElements: ForeignCallSingle,
|
|
354
353
|
) {
|
|
355
|
-
const blockHash =
|
|
354
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
356
355
|
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
357
356
|
const startStorageSlot = fromSingle(foreignStartStorageSlot);
|
|
358
357
|
const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
|
|
@@ -368,7 +367,7 @@ export class RPCTranslator {
|
|
|
368
367
|
}
|
|
369
368
|
|
|
370
369
|
async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
|
|
371
|
-
const blockHash =
|
|
370
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
372
371
|
const leafSlot = fromSingle(foreignLeafSlot);
|
|
373
372
|
|
|
374
373
|
const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
|
|
@@ -397,7 +396,7 @@ export class RPCTranslator {
|
|
|
397
396
|
foreignOffset: ForeignCallSingle,
|
|
398
397
|
foreignStatus: ForeignCallSingle,
|
|
399
398
|
foreignMaxNotes: ForeignCallSingle,
|
|
400
|
-
|
|
399
|
+
foreignPackedHintedNoteLength: ForeignCallSingle,
|
|
401
400
|
) {
|
|
402
401
|
// Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
|
|
403
402
|
const owner = fromSingle(foreignOwnerIsSome).toBool()
|
|
@@ -418,7 +417,7 @@ export class RPCTranslator {
|
|
|
418
417
|
const offset = fromSingle(foreignOffset).toNumber();
|
|
419
418
|
const status = fromSingle(foreignStatus).toNumber();
|
|
420
419
|
const maxNotes = fromSingle(foreignMaxNotes).toNumber();
|
|
421
|
-
const
|
|
420
|
+
const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
|
|
422
421
|
|
|
423
422
|
const noteDatas = await this.handlerAsUtility().utilityGetNotes(
|
|
424
423
|
owner,
|
|
@@ -439,7 +438,7 @@ export class RPCTranslator {
|
|
|
439
438
|
);
|
|
440
439
|
|
|
441
440
|
const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
|
|
442
|
-
|
|
441
|
+
packAsHintedNote({
|
|
443
442
|
contractAddress: noteData.contractAddress,
|
|
444
443
|
owner: noteData.owner,
|
|
445
444
|
randomness: noteData.randomness,
|
|
@@ -457,11 +456,7 @@ export class RPCTranslator {
|
|
|
457
456
|
|
|
458
457
|
// At last we convert the array of arrays to a bounded vec of arrays
|
|
459
458
|
return toForeignCallResult(
|
|
460
|
-
arrayOfArraysToBoundedVecOfArrays(
|
|
461
|
-
returnDataAsArrayOfForeignCallSingleArrays,
|
|
462
|
-
maxNotes,
|
|
463
|
-
packedRetrievedNoteLength,
|
|
464
|
-
),
|
|
459
|
+
arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
|
|
465
460
|
);
|
|
466
461
|
}
|
|
467
462
|
|
|
@@ -517,6 +512,15 @@ export class RPCTranslator {
|
|
|
517
512
|
return toForeignCallResult([]);
|
|
518
513
|
}
|
|
519
514
|
|
|
515
|
+
async privateIsNullifierPending(foreignInnerNullifier: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
|
|
516
|
+
const innerNullifier = fromSingle(foreignInnerNullifier);
|
|
517
|
+
const contractAddress = addressFromSingle(foreignContractAddress);
|
|
518
|
+
|
|
519
|
+
const isPending = await this.handlerAsPrivate().privateIsNullifierPending(innerNullifier, contractAddress);
|
|
520
|
+
|
|
521
|
+
return toForeignCallResult([toSingle(new Fr(isPending))]);
|
|
522
|
+
}
|
|
523
|
+
|
|
520
524
|
async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
|
|
521
525
|
const innerNullifier = fromSingle(foreignInnerNullifier);
|
|
522
526
|
|
|
@@ -541,12 +545,23 @@ export class RPCTranslator {
|
|
|
541
545
|
);
|
|
542
546
|
}
|
|
543
547
|
|
|
544
|
-
async
|
|
548
|
+
async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
|
|
545
549
|
const address = addressFromSingle(foreignAddress);
|
|
546
550
|
|
|
547
|
-
const
|
|
551
|
+
const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
|
|
548
552
|
|
|
549
|
-
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
|
+
}
|
|
550
565
|
}
|
|
551
566
|
|
|
552
567
|
async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
|
|
@@ -570,7 +585,7 @@ export class RPCTranslator {
|
|
|
570
585
|
}
|
|
571
586
|
|
|
572
587
|
async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
|
|
573
|
-
const blockHash =
|
|
588
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
574
589
|
const nullifier = fromSingle(foreignNullifier);
|
|
575
590
|
|
|
576
591
|
const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -637,30 +652,43 @@ export class RPCTranslator {
|
|
|
637
652
|
return toForeignCallResult(header.toFields().map(toSingle));
|
|
638
653
|
}
|
|
639
654
|
|
|
640
|
-
async
|
|
655
|
+
async utilityGetNoteHashMembershipWitness(
|
|
656
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
657
|
+
foreignNoteHash: ForeignCallSingle,
|
|
658
|
+
) {
|
|
659
|
+
const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
660
|
+
const noteHash = fromSingle(foreignNoteHash);
|
|
661
|
+
|
|
662
|
+
const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
|
|
663
|
+
|
|
664
|
+
if (!witness) {
|
|
665
|
+
throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
|
|
666
|
+
}
|
|
667
|
+
return toForeignCallResult(witness.toNoirRepresentation());
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
async utilityGetBlockHashMembershipWitness(
|
|
671
|
+
foreignAnchorBlockHash: ForeignCallSingle,
|
|
641
672
|
foreignBlockHash: ForeignCallSingle,
|
|
642
|
-
foreignTreeId: ForeignCallSingle,
|
|
643
|
-
foreignLeafValue: ForeignCallSingle,
|
|
644
673
|
) {
|
|
645
|
-
const
|
|
646
|
-
const
|
|
647
|
-
const leafValue = fromSingle(foreignLeafValue);
|
|
674
|
+
const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
|
|
675
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
648
676
|
|
|
649
|
-
const witness = await this.handlerAsUtility().
|
|
677
|
+
const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
|
|
650
678
|
|
|
651
679
|
if (!witness) {
|
|
652
680
|
throw new Error(
|
|
653
|
-
`
|
|
681
|
+
`Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
|
|
654
682
|
);
|
|
655
683
|
}
|
|
656
|
-
return toForeignCallResult(
|
|
684
|
+
return toForeignCallResult(witness.toNoirRepresentation());
|
|
657
685
|
}
|
|
658
686
|
|
|
659
687
|
async utilityGetLowNullifierMembershipWitness(
|
|
660
688
|
foreignBlockHash: ForeignCallSingle,
|
|
661
689
|
foreignNullifier: ForeignCallSingle,
|
|
662
690
|
) {
|
|
663
|
-
const blockHash =
|
|
691
|
+
const blockHash = new BlockHash(fromSingle(foreignBlockHash));
|
|
664
692
|
const nullifier = fromSingle(foreignNullifier);
|
|
665
693
|
|
|
666
694
|
const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
|
|
@@ -679,7 +707,7 @@ export class RPCTranslator {
|
|
|
679
707
|
return toForeignCallResult([]);
|
|
680
708
|
}
|
|
681
709
|
|
|
682
|
-
public async
|
|
710
|
+
public async utilityValidateAndStoreEnqueuedNotesAndEvents(
|
|
683
711
|
foreignContractAddress: ForeignCallSingle,
|
|
684
712
|
foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
|
|
685
713
|
foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
|
|
@@ -688,7 +716,7 @@ export class RPCTranslator {
|
|
|
688
716
|
const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
|
|
689
717
|
const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
|
|
690
718
|
|
|
691
|
-
await this.handlerAsUtility().
|
|
719
|
+
await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
|
|
692
720
|
contractAddress,
|
|
693
721
|
noteValidationRequestsArrayBaseSlot,
|
|
694
722
|
eventValidationRequestsArrayBaseSlot,
|
|
@@ -826,10 +854,11 @@ export class RPCTranslator {
|
|
|
826
854
|
return toForeignCallResult([]);
|
|
827
855
|
}
|
|
828
856
|
|
|
829
|
-
async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
|
|
857
|
+
async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
|
|
830
858
|
const slot = fromSingle(foreignSlot);
|
|
859
|
+
const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
|
|
831
860
|
|
|
832
|
-
const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
|
|
861
|
+
const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
|
|
833
862
|
|
|
834
863
|
return toForeignCallResult([toSingle(new Fr(value))]);
|
|
835
864
|
}
|
|
@@ -901,11 +930,10 @@ export class RPCTranslator {
|
|
|
901
930
|
return toForeignCallResult([]);
|
|
902
931
|
}
|
|
903
932
|
|
|
904
|
-
async avmOpcodeNullifierExists(
|
|
905
|
-
const
|
|
906
|
-
const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
|
|
933
|
+
async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
|
|
934
|
+
const siloedNullifier = fromSingle(foreignSiloedNullifier);
|
|
907
935
|
|
|
908
|
-
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(
|
|
936
|
+
const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
|
|
909
937
|
|
|
910
938
|
return toForeignCallResult([toSingle(new Fr(exists))]);
|
|
911
939
|
}
|
|
@@ -17,18 +17,14 @@ export class TXEArchiver extends ArchiverDataSourceBase {
|
|
|
17
17
|
private readonly updater = new ArchiverDataStoreUpdater(this.store);
|
|
18
18
|
|
|
19
19
|
constructor(db: AztecAsyncKVStore) {
|
|
20
|
-
const store = new KVArchiverDataStore(db, 9999);
|
|
20
|
+
const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
|
|
21
21
|
super(store);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
await this.updater.setNewCheckpointData(checkpoints, result);
|
|
27
|
-
return true;
|
|
24
|
+
public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
|
|
25
|
+
await this.updater.addCheckpoints(checkpoints, result);
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
// Abstract method implementations
|
|
31
|
-
|
|
32
28
|
public getRollupAddress(): Promise<EthAddress> {
|
|
33
29
|
throw new Error('TXE Archiver does not implement "getRollupAddress"');
|
|
34
30
|
}
|
|
@@ -63,7 +59,9 @@ export class TXEArchiver extends ArchiverDataSourceBase {
|
|
|
63
59
|
if (!checkpointedBlock) {
|
|
64
60
|
throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
|
|
65
61
|
}
|
|
66
|
-
|
|
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.
|
|
64
|
+
const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
|
|
67
65
|
if (checkpoint.length === 0) {
|
|
68
66
|
throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
|
|
69
67
|
}
|
|
@@ -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
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
|
|
2
2
|
import { TestCircuitVerifier } from '@aztec/bb-prover/test';
|
|
3
|
+
import { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import type
|
|
5
|
-
import {
|
|
6
|
-
import { L2BlockNew } from '@aztec/stdlib/block';
|
|
6
|
+
import { type AnchorBlockStore, type ContractStore, ContractSyncService, type NoteStore } from '@aztec/pxe/server';
|
|
7
|
+
import { L2Block } from '@aztec/stdlib/block';
|
|
7
8
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
8
9
|
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
|
|
10
|
+
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
9
11
|
import { getPackageVersion } from '@aztec/stdlib/update-checker';
|
|
10
12
|
|
|
11
13
|
import { TXEArchiver } from './archiver.js';
|
|
@@ -23,13 +25,16 @@ export class TXEStateMachine {
|
|
|
23
25
|
public synchronizer: TXESynchronizer,
|
|
24
26
|
public archiver: TXEArchiver,
|
|
25
27
|
public anchorBlockStore: AnchorBlockStore,
|
|
28
|
+
public contractSyncService: ContractSyncService,
|
|
26
29
|
) {}
|
|
27
30
|
|
|
28
|
-
public static async create(
|
|
29
|
-
|
|
31
|
+
public static async create(
|
|
32
|
+
archiver: TXEArchiver,
|
|
33
|
+
anchorBlockStore: AnchorBlockStore,
|
|
34
|
+
contractStore: ContractStore,
|
|
35
|
+
noteStore: NoteStore,
|
|
36
|
+
) {
|
|
30
37
|
const synchronizer = await TXESynchronizer.create();
|
|
31
|
-
const anchorBlockStore = new AnchorBlockStore(db);
|
|
32
|
-
|
|
33
38
|
const aztecNodeConfig = {} as AztecNodeConfig;
|
|
34
39
|
|
|
35
40
|
const log = createLogger('txe_node');
|
|
@@ -55,18 +60,39 @@ export class TXEStateMachine {
|
|
|
55
60
|
log,
|
|
56
61
|
);
|
|
57
62
|
|
|
58
|
-
|
|
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);
|
|
59
71
|
}
|
|
60
72
|
|
|
61
|
-
public async handleL2Block(block:
|
|
62
|
-
// Create a checkpoint from the block
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
73
|
+
public async handleL2Block(block: L2Block) {
|
|
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);
|
|
78
|
+
const checkpoint = new Checkpoint(
|
|
79
|
+
block.archive,
|
|
80
|
+
CheckpointHeader.from({
|
|
81
|
+
lastArchiveRoot: block.header.lastArchive.root,
|
|
82
|
+
inHash: Fr.ZERO,
|
|
83
|
+
blobsHash: Fr.ZERO,
|
|
84
|
+
blockHeadersHash: Fr.ZERO,
|
|
85
|
+
epochOutHash: Fr.ZERO,
|
|
86
|
+
slotNumber: block.header.globalVariables.slotNumber,
|
|
87
|
+
timestamp: block.header.globalVariables.timestamp,
|
|
88
|
+
coinbase: block.header.globalVariables.coinbase,
|
|
89
|
+
feeRecipient: block.header.globalVariables.feeRecipient,
|
|
90
|
+
gasFees: block.header.globalVariables.gasFees,
|
|
91
|
+
totalManaUsed: block.header.totalManaUsed,
|
|
92
|
+
}),
|
|
93
|
+
[block],
|
|
94
|
+
checkpointNumber,
|
|
95
|
+
);
|
|
70
96
|
|
|
71
97
|
const publishedCheckpoint = new PublishedCheckpoint(
|
|
72
98
|
checkpoint,
|
|
@@ -77,10 +103,13 @@ export class TXEStateMachine {
|
|
|
77
103
|
),
|
|
78
104
|
[],
|
|
79
105
|
);
|
|
106
|
+
// Wipe contract sync cache when anchor block changes (mirrors BlockSynchronizer behavior)
|
|
107
|
+
this.contractSyncService.wipe();
|
|
108
|
+
|
|
80
109
|
await Promise.all([
|
|
81
|
-
this.synchronizer.handleL2Block(block),
|
|
110
|
+
this.synchronizer.handleL2Block(block),
|
|
82
111
|
this.archiver.addCheckpoints([publishedCheckpoint], undefined),
|
|
83
|
-
this.anchorBlockStore.setHeader(block.header),
|
|
112
|
+
this.anchorBlockStore.setHeader(block.header),
|
|
84
113
|
]);
|
|
85
114
|
}
|
|
86
115
|
}
|
|
@@ -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.
|
|
@@ -16,11 +17,12 @@ export class MockEpochCache implements EpochCacheInterface {
|
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
getEpochAndSlotNow(): EpochAndSlot {
|
|
20
|
+
getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
|
|
20
21
|
return {
|
|
21
22
|
epoch: EpochNumber.ZERO,
|
|
22
23
|
slot: SlotNumber(0),
|
|
23
24
|
ts: 0n,
|
|
25
|
+
nowMs: 0n,
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
|
|
@@ -41,18 +43,11 @@ export class MockEpochCache implements EpochCacheInterface {
|
|
|
41
43
|
return 0n;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
nextProposer: EthAddress | undefined;
|
|
47
|
-
currentSlot: SlotNumber;
|
|
48
|
-
nextSlot: SlotNumber;
|
|
49
|
-
}> {
|
|
50
|
-
return Promise.resolve({
|
|
51
|
-
currentProposer: undefined,
|
|
52
|
-
nextProposer: undefined,
|
|
46
|
+
getCurrentAndNextSlot(): { currentSlot: SlotNumber; nextSlot: SlotNumber } {
|
|
47
|
+
return {
|
|
53
48
|
currentSlot: SlotNumber(0),
|
|
54
49
|
nextSlot: SlotNumber(0),
|
|
55
|
-
}
|
|
50
|
+
};
|
|
56
51
|
}
|
|
57
52
|
|
|
58
53
|
getProposerAttesterAddressInSlot(_slot: SlotNumber): Promise<EthAddress | undefined> {
|
|
@@ -70,4 +65,8 @@ export class MockEpochCache implements EpochCacheInterface {
|
|
|
70
65
|
filterInCommittee(_slot: SlotTag, _validators: EthAddress[]): Promise<EthAddress[]> {
|
|
71
66
|
return Promise.resolve([]);
|
|
72
67
|
}
|
|
68
|
+
|
|
69
|
+
getL1Constants(): L1RollupConstants {
|
|
70
|
+
return EmptyL1RollupConstants;
|
|
71
|
+
}
|
|
73
72
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
-
import type {
|
|
4
|
+
import type { L2Block } from '@aztec/stdlib/block';
|
|
5
5
|
import type {
|
|
6
6
|
MerkleTreeReadOperations,
|
|
7
7
|
MerkleTreeWriteOperations,
|
|
@@ -23,7 +23,7 @@ export class TXESynchronizer implements WorldStateSynchronizer {
|
|
|
23
23
|
return new this(nativeWorldStateService);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
public async handleL2Block(block:
|
|
26
|
+
public async handleL2Block(block: L2Block) {
|
|
27
27
|
await this.nativeWorldStateService.handleL2BlockAndMessages(
|
|
28
28
|
block,
|
|
29
29
|
Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero),
|
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';
|
|
@@ -152,7 +154,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
152
154
|
const addressStore = new AddressStore(store);
|
|
153
155
|
const privateEventStore = new PrivateEventStore(store);
|
|
154
156
|
const contractStore = new TXEContractStore(store);
|
|
155
|
-
const noteStore =
|
|
157
|
+
const noteStore = new NoteStore(store);
|
|
156
158
|
const senderTaggingStore = new SenderTaggingStore(store);
|
|
157
159
|
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
158
160
|
const senderAddressBookStore = new SenderAddressBookStore(store);
|
|
@@ -162,7 +164,13 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
162
164
|
|
|
163
165
|
// Create job coordinator and register staged stores
|
|
164
166
|
const jobCoordinator = new JobCoordinator(store);
|
|
165
|
-
jobCoordinator.registerStores([
|
|
167
|
+
jobCoordinator.registerStores([
|
|
168
|
+
capsuleStore,
|
|
169
|
+
senderTaggingStore,
|
|
170
|
+
recipientTaggingStore,
|
|
171
|
+
privateEventStore,
|
|
172
|
+
noteStore,
|
|
173
|
+
]);
|
|
166
174
|
|
|
167
175
|
// Register protocol contracts.
|
|
168
176
|
for (const { contractClass, instance, artifact } of protocolContracts) {
|
|
@@ -170,7 +178,9 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
170
178
|
await contractStore.addContractInstance(instance);
|
|
171
179
|
}
|
|
172
180
|
|
|
173
|
-
const
|
|
181
|
+
const archiver = new TXEArchiver(store);
|
|
182
|
+
const anchorBlockStore = new AnchorBlockStore(store);
|
|
183
|
+
const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
|
|
174
184
|
|
|
175
185
|
const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
|
|
176
186
|
const version = new Fr(await stateMachine.node.getVersion());
|
|
@@ -306,16 +316,14 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
306
316
|
): Promise<PrivateContextInputs> {
|
|
307
317
|
this.exitTopLevelState();
|
|
308
318
|
|
|
309
|
-
await new NoteService(
|
|
310
|
-
this.noteStore,
|
|
311
|
-
this.stateMachine.node,
|
|
312
|
-
this.stateMachine.anchorBlockStore,
|
|
313
|
-
).syncNoteNullifiers(contractAddress);
|
|
314
|
-
|
|
315
319
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
316
320
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
317
321
|
// a single transaction with the effects of what was done in the test.
|
|
318
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
|
+
);
|
|
319
327
|
const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
|
|
320
328
|
|
|
321
329
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
@@ -347,12 +355,12 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
347
355
|
this.keyStore,
|
|
348
356
|
this.addressStore,
|
|
349
357
|
this.stateMachine.node,
|
|
350
|
-
this.stateMachine.anchorBlockStore,
|
|
351
358
|
this.senderTaggingStore,
|
|
352
359
|
this.recipientTaggingStore,
|
|
353
360
|
this.senderAddressBookStore,
|
|
354
361
|
this.capsuleStore,
|
|
355
362
|
this.privateEventStore,
|
|
363
|
+
this.stateMachine.contractSyncService,
|
|
356
364
|
this.currentJobId,
|
|
357
365
|
);
|
|
358
366
|
|
|
@@ -394,6 +402,8 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
394
402
|
async enterUtilityState(contractAddress: AztecAddress = DEFAULT_ADDRESS) {
|
|
395
403
|
this.exitTopLevelState();
|
|
396
404
|
|
|
405
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
406
|
+
|
|
397
407
|
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
398
408
|
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
399
409
|
// we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
|
|
@@ -402,11 +412,10 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
402
412
|
await new NoteService(
|
|
403
413
|
this.noteStore,
|
|
404
414
|
this.stateMachine.node,
|
|
405
|
-
|
|
415
|
+
anchorBlockHeader,
|
|
416
|
+
this.currentJobId,
|
|
406
417
|
).syncNoteNullifiers(contractAddress);
|
|
407
418
|
|
|
408
|
-
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
409
|
-
|
|
410
419
|
this.oracleHandler = new UtilityExecutionOracle(
|
|
411
420
|
contractAddress,
|
|
412
421
|
[],
|
|
@@ -417,7 +426,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
417
426
|
this.keyStore,
|
|
418
427
|
this.addressStore,
|
|
419
428
|
this.stateMachine.node,
|
|
420
|
-
this.stateMachine.anchorBlockStore,
|
|
421
429
|
this.recipientTaggingStore,
|
|
422
430
|
this.senderAddressBookStore,
|
|
423
431
|
this.capsuleStore,
|
|
@@ -508,7 +516,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
508
516
|
this.keyStore,
|
|
509
517
|
this.addressStore,
|
|
510
518
|
this.stateMachine.node,
|
|
511
|
-
this.stateMachine.anchorBlockStore,
|
|
512
519
|
this.recipientTaggingStore,
|
|
513
520
|
this.senderAddressBookStore,
|
|
514
521
|
this.capsuleStore,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
|
|
8
8
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
9
9
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
10
|
-
import { Body,
|
|
10
|
+
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
11
11
|
import { AppendOnlyTreeSnapshot, MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
|
|
12
12
|
import { BlockHeader, GlobalVariables, TxEffect } from '@aztec/stdlib/tx';
|
|
13
13
|
|
|
@@ -61,7 +61,7 @@ export async function makeTXEBlockHeader(
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
/**
|
|
64
|
-
* Creates an
|
|
64
|
+
* Creates an L2Block with proper archive chaining.
|
|
65
65
|
* This function:
|
|
66
66
|
* 1. Gets the current archive state as lastArchive for the header
|
|
67
67
|
* 2. Creates the block header
|
|
@@ -71,13 +71,13 @@ export async function makeTXEBlockHeader(
|
|
|
71
71
|
* @param worldTrees - The world trees to read/write from
|
|
72
72
|
* @param globalVariables - Global variables for the block
|
|
73
73
|
* @param txEffects - Transaction effects to include in the block
|
|
74
|
-
* @returns The created
|
|
74
|
+
* @returns The created L2Block with proper archive chaining
|
|
75
75
|
*/
|
|
76
76
|
export async function makeTXEBlock(
|
|
77
77
|
worldTrees: MerkleTreeWriteOperations,
|
|
78
78
|
globalVariables: GlobalVariables,
|
|
79
79
|
txEffects: TxEffect[],
|
|
80
|
-
): Promise<
|
|
80
|
+
): Promise<L2Block> {
|
|
81
81
|
const header = await makeTXEBlockHeader(worldTrees, globalVariables);
|
|
82
82
|
|
|
83
83
|
// Update the archive tree with this block's header hash
|
|
@@ -87,9 +87,11 @@ 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
|
-
//
|
|
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
|
|
|
94
|
-
return new
|
|
96
|
+
return new L2Block(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
|
|
95
97
|
}
|