@aztec/txe 0.69.1 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/index.js +2 -2
- package/dest/oracle/txe_oracle.d.ts +30 -10
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +76 -58
- package/dest/txe_service/txe_service.d.ts +20 -10
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +47 -23
- package/dest/util/txe_world_state_db.d.ts +1 -1
- package/dest/util/txe_world_state_db.d.ts.map +1 -1
- package/dest/util/txe_world_state_db.js +2 -2
- package/package.json +14 -14
- package/src/index.ts +1 -1
- package/src/oracle/txe_oracle.ts +117 -78
- package/src/txe_service/txe_service.ts +49 -28
- package/src/util/txe_world_state_db.ts +1 -1
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -58,30 +58,32 @@ import {
|
|
|
58
58
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
59
59
|
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
60
60
|
import { Fr } from '@aztec/foundation/fields';
|
|
61
|
-
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
61
|
+
import { type LogFn, type Logger, applyStringFormatting, createDebugOnlyLogger } from '@aztec/foundation/log';
|
|
62
62
|
import { Timer } from '@aztec/foundation/timer';
|
|
63
63
|
import { type KeyStore } from '@aztec/key-store';
|
|
64
64
|
import { ContractDataOracle, SimulatorOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
65
65
|
import {
|
|
66
|
-
ExecutionError,
|
|
67
66
|
ExecutionNoteCache,
|
|
68
67
|
type MessageLoadOracleInputs,
|
|
69
68
|
type NoteData,
|
|
70
69
|
Oracle,
|
|
71
|
-
type PackedValuesCache,
|
|
72
|
-
type PublicTxResult,
|
|
73
|
-
PublicTxSimulator,
|
|
74
70
|
type TypedOracle,
|
|
75
|
-
|
|
76
|
-
createSimulationError,
|
|
71
|
+
WASMSimulator,
|
|
77
72
|
extractCallStack,
|
|
78
73
|
extractPrivateCircuitPublicInputs,
|
|
79
74
|
pickNotes,
|
|
80
|
-
resolveAssertionMessageFromError,
|
|
81
75
|
toACVMWitness,
|
|
82
76
|
witnessMapToFields,
|
|
83
|
-
} from '@aztec/simulator';
|
|
84
|
-
import {
|
|
77
|
+
} from '@aztec/simulator/client';
|
|
78
|
+
import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
|
|
79
|
+
import {
|
|
80
|
+
ExecutionError,
|
|
81
|
+
type HashedValuesCache,
|
|
82
|
+
type PublicTxResult,
|
|
83
|
+
PublicTxSimulator,
|
|
84
|
+
createSimulationError,
|
|
85
|
+
resolveAssertionMessageFromError,
|
|
86
|
+
} from '@aztec/simulator/server';
|
|
85
87
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
86
88
|
import { MerkleTreeSnapshotOperationsFacade, type MerkleTrees } from '@aztec/world-state';
|
|
87
89
|
|
|
@@ -108,7 +110,6 @@ export class TXE implements TypedOracle {
|
|
|
108
110
|
|
|
109
111
|
private uniqueNoteHashesFromPublic: Fr[] = [];
|
|
110
112
|
private siloedNullifiersFromPublic: Fr[] = [];
|
|
111
|
-
private siloedNullifiersFromPrivate: Set<string> = new Set();
|
|
112
113
|
private privateLogs: PrivateLog[] = [];
|
|
113
114
|
private publicLogs: UnencryptedL2Log[] = [];
|
|
114
115
|
|
|
@@ -116,19 +117,33 @@ export class TXE implements TypedOracle {
|
|
|
116
117
|
|
|
117
118
|
private node = new TXENode(this.blockNumber);
|
|
118
119
|
|
|
120
|
+
private simulationProvider = new WASMSimulator();
|
|
121
|
+
|
|
122
|
+
private noteCache: ExecutionNoteCache;
|
|
123
|
+
|
|
124
|
+
debug: LogFn;
|
|
125
|
+
|
|
119
126
|
constructor(
|
|
120
127
|
private logger: Logger,
|
|
121
128
|
private trees: MerkleTrees,
|
|
122
|
-
private
|
|
123
|
-
private noteCache: ExecutionNoteCache,
|
|
129
|
+
private executionCache: HashedValuesCache,
|
|
124
130
|
private keyStore: KeyStore,
|
|
125
131
|
private txeDatabase: TXEDatabase,
|
|
126
132
|
) {
|
|
133
|
+
this.noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
127
134
|
this.contractDataOracle = new ContractDataOracle(txeDatabase);
|
|
128
135
|
this.contractAddress = AztecAddress.random();
|
|
129
136
|
// Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404)
|
|
130
137
|
this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE);
|
|
131
|
-
this.simulatorOracle = new SimulatorOracle(
|
|
138
|
+
this.simulatorOracle = new SimulatorOracle(
|
|
139
|
+
this.contractDataOracle,
|
|
140
|
+
txeDatabase,
|
|
141
|
+
keyStore,
|
|
142
|
+
this.node,
|
|
143
|
+
this.simulationProvider,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
this.debug = createDebugOnlyLogger('aztec:kv-pxe-database');
|
|
132
147
|
}
|
|
133
148
|
|
|
134
149
|
// Utils
|
|
@@ -260,18 +275,14 @@ export class TXE implements TypedOracle {
|
|
|
260
275
|
);
|
|
261
276
|
}
|
|
262
277
|
|
|
263
|
-
async
|
|
278
|
+
async checkNullifiersNotInTree(contractAddress: AztecAddress, nullifiers: Fr[]) {
|
|
264
279
|
const siloedNullifiers = nullifiers.map(nullifier => siloNullifier(contractAddress, nullifier));
|
|
265
280
|
const db = await this.trees.getLatest();
|
|
266
281
|
const nullifierIndexesInTree = await db.findLeafIndices(
|
|
267
282
|
MerkleTreeId.NULLIFIER_TREE,
|
|
268
283
|
siloedNullifiers.map(n => n.toBuffer()),
|
|
269
284
|
);
|
|
270
|
-
|
|
271
|
-
const notInCache = siloedNullifiers.every(n => !this.siloedNullifiersFromPrivate.has(n.toString()));
|
|
272
|
-
if (notInTree && notInCache) {
|
|
273
|
-
siloedNullifiers.forEach(n => this.siloedNullifiersFromPrivate.add(n.toString()));
|
|
274
|
-
} else {
|
|
285
|
+
if (nullifierIndexesInTree.some(index => index !== undefined)) {
|
|
275
286
|
throw new Error(`Rejecting tx for emitting duplicate nullifiers`);
|
|
276
287
|
}
|
|
277
288
|
}
|
|
@@ -360,16 +371,16 @@ export class TXE implements TypedOracle {
|
|
|
360
371
|
return Fr.random();
|
|
361
372
|
}
|
|
362
373
|
|
|
363
|
-
|
|
364
|
-
return Promise.resolve(this.
|
|
374
|
+
storeArrayInExecutionCache(values: Fr[]) {
|
|
375
|
+
return Promise.resolve(this.executionCache.store(values));
|
|
365
376
|
}
|
|
366
377
|
|
|
367
|
-
|
|
368
|
-
return Promise.resolve(this.
|
|
378
|
+
storeInExecutionCache(values: Fr[]) {
|
|
379
|
+
return Promise.resolve(this.executionCache.store(values));
|
|
369
380
|
}
|
|
370
381
|
|
|
371
|
-
|
|
372
|
-
return Promise.resolve(this.
|
|
382
|
+
loadFromExecutionCache(returnsHash: Fr) {
|
|
383
|
+
return Promise.resolve(this.executionCache.getPreimage(returnsHash));
|
|
373
384
|
}
|
|
374
385
|
|
|
375
386
|
getKeyValidationRequest(pkMHash: Fr): Promise<KeyValidationRequest> {
|
|
@@ -550,12 +561,18 @@ export class TXE implements TypedOracle {
|
|
|
550
561
|
}
|
|
551
562
|
|
|
552
563
|
async notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
|
|
553
|
-
await this.
|
|
564
|
+
await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
|
|
554
565
|
this.noteCache.nullifyNote(this.contractAddress, innerNullifier, noteHash);
|
|
555
566
|
this.sideEffectCounter = counter + 1;
|
|
556
567
|
return Promise.resolve();
|
|
557
568
|
}
|
|
558
569
|
|
|
570
|
+
async notifyCreatedNullifier(innerNullifier: Fr): Promise<void> {
|
|
571
|
+
await this.checkNullifiersNotInTree(this.contractAddress, [innerNullifier]);
|
|
572
|
+
this.noteCache.nullifierCreated(this.contractAddress, innerNullifier);
|
|
573
|
+
return Promise.resolve();
|
|
574
|
+
}
|
|
575
|
+
|
|
559
576
|
async checkNullifierExists(innerNullifier: Fr): Promise<boolean> {
|
|
560
577
|
const nullifier = siloNullifier(this.contractAddress, innerNullifier!);
|
|
561
578
|
const db = await this.trees.getLatest();
|
|
@@ -617,6 +634,7 @@ export class TXE implements TypedOracle {
|
|
|
617
634
|
|
|
618
635
|
async commitState() {
|
|
619
636
|
const blockNumber = await this.getBlockNumber();
|
|
637
|
+
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
620
638
|
if (this.committedBlocks.has(blockNumber)) {
|
|
621
639
|
throw new Error('Already committed state');
|
|
622
640
|
} else {
|
|
@@ -625,30 +643,25 @@ export class TXE implements TypedOracle {
|
|
|
625
643
|
|
|
626
644
|
const txEffect = TxEffect.empty();
|
|
627
645
|
|
|
646
|
+
const nonceGenerator = usedTxRequestHashForNonces ? this.getTxRequestHash() : this.noteCache.getAllNullifiers()[0];
|
|
647
|
+
|
|
628
648
|
let i = 0;
|
|
629
649
|
txEffect.noteHashes = [
|
|
630
650
|
...this.noteCache
|
|
631
651
|
.getAllNotes()
|
|
632
652
|
.map(pendingNote =>
|
|
633
653
|
computeUniqueNoteHash(
|
|
634
|
-
computeNoteHashNonce(
|
|
654
|
+
computeNoteHashNonce(nonceGenerator, i++),
|
|
635
655
|
siloNoteHash(pendingNote.note.contractAddress, pendingNote.noteHashForConsumption),
|
|
636
656
|
),
|
|
637
657
|
),
|
|
638
658
|
...this.uniqueNoteHashesFromPublic,
|
|
639
659
|
];
|
|
640
|
-
txEffect.nullifiers = [
|
|
641
|
-
new Fr(blockNumber + 6969),
|
|
642
|
-
...Array.from(this.siloedNullifiersFromPrivate).map(n => Fr.fromString(n)),
|
|
643
|
-
];
|
|
644
|
-
|
|
645
|
-
// Using block number itself, (without adding 6969) gets killed at 1 as it says the slot is already used,
|
|
646
|
-
// it seems like we commit a 1 there to the trees before ? To see what I mean, uncomment these lines below
|
|
647
|
-
// let index = await (await this.trees.getLatest()).findLeafIndex(MerkleTreeId.NULLIFIER_TREE, Fr.ONE.toBuffer());
|
|
648
|
-
// console.log('INDEX OF ONE', index);
|
|
649
|
-
// index = await (await this.trees.getLatest()).findLeafIndex(MerkleTreeId.NULLIFIER_TREE, Fr.random().toBuffer());
|
|
650
|
-
// console.log('INDEX OF RANDOM', index);
|
|
651
660
|
|
|
661
|
+
txEffect.nullifiers = this.noteCache.getAllNullifiers();
|
|
662
|
+
if (usedTxRequestHashForNonces) {
|
|
663
|
+
txEffect.nullifiers.unshift(this.getTxRequestHash());
|
|
664
|
+
}
|
|
652
665
|
this.node.setTxEffect(blockNumber, new TxHash(new Fr(blockNumber)), txEffect);
|
|
653
666
|
this.node.setNullifiersIndexesWithBlock(blockNumber, txEffect.nullifiers);
|
|
654
667
|
this.node.addNoteLogsByTags(this.blockNumber, this.privateLogs);
|
|
@@ -659,10 +672,14 @@ export class TXE implements TypedOracle {
|
|
|
659
672
|
|
|
660
673
|
this.privateLogs = [];
|
|
661
674
|
this.publicLogs = [];
|
|
662
|
-
this.siloedNullifiersFromPrivate = new Set();
|
|
663
675
|
this.uniqueNoteHashesFromPublic = [];
|
|
664
676
|
this.siloedNullifiersFromPublic = [];
|
|
665
|
-
this.noteCache = new ExecutionNoteCache(
|
|
677
|
+
this.noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
getTxRequestHash() {
|
|
681
|
+
// Using block number itself is invalid since indexed trees come prefilled with the first slots.
|
|
682
|
+
return new Fr(this.blockNumber + 6969);
|
|
666
683
|
}
|
|
667
684
|
|
|
668
685
|
emitContractClassLog(_log: UnencryptedL2Log, _counter: number): Fr {
|
|
@@ -697,21 +714,23 @@ export class TXE implements TypedOracle {
|
|
|
697
714
|
const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
|
|
698
715
|
const acvmCallback = new Oracle(this);
|
|
699
716
|
const timer = new Timer();
|
|
700
|
-
const acirExecutionResult = await
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
717
|
+
const acirExecutionResult = await this.simulationProvider
|
|
718
|
+
.executeUserCircuit(acir, initialWitness, acvmCallback)
|
|
719
|
+
.catch((err: Error) => {
|
|
720
|
+
err.message = resolveAssertionMessageFromError(err, artifact);
|
|
721
|
+
|
|
722
|
+
const execError = new ExecutionError(
|
|
723
|
+
err.message,
|
|
724
|
+
{
|
|
725
|
+
contractAddress: targetContractAddress,
|
|
726
|
+
functionSelector,
|
|
727
|
+
},
|
|
728
|
+
extractCallStack(err, artifact.debug),
|
|
729
|
+
{ cause: err },
|
|
730
|
+
);
|
|
731
|
+
this.logger.debug(`Error executing private function ${targetContractAddress}:${functionSelector}`);
|
|
732
|
+
throw createSimulationError(execError);
|
|
733
|
+
});
|
|
715
734
|
const duration = timer.ms();
|
|
716
735
|
const publicInputs = extractPrivateCircuitPublicInputs(artifact, acirExecutionResult.partialWitness);
|
|
717
736
|
|
|
@@ -734,24 +753,6 @@ export class TXE implements TypedOracle {
|
|
|
734
753
|
publicInputs.privateLogs.filter(privateLog => !privateLog.isEmpty()).map(privateLog => privateLog.log),
|
|
735
754
|
);
|
|
736
755
|
|
|
737
|
-
const executionNullifiers = publicInputs.nullifiers
|
|
738
|
-
.filter(nullifier => !nullifier.isEmpty())
|
|
739
|
-
.map(nullifier => nullifier.value);
|
|
740
|
-
// We inject nullifiers into siloedNullifiersFromPrivate from notifyNullifiedNote,
|
|
741
|
-
// so top level calls to destroyNote work as expected. As such, we are certain
|
|
742
|
-
// that we would insert duplicates if we just took the nullifiers from the public inputs and
|
|
743
|
-
// blindly inserted them into siloedNullifiersFromPrivate. To avoid this, we extract the first
|
|
744
|
-
// (and only the first!) duplicated nullifier from the public inputs, so we can just push
|
|
745
|
-
// the ones that were not created by deleting a note
|
|
746
|
-
const firstDuplicateIndexes = executionNullifiers
|
|
747
|
-
.map((nullifier, index) => {
|
|
748
|
-
const siloedNullifier = siloNullifier(targetContractAddress, nullifier);
|
|
749
|
-
return this.siloedNullifiersFromPrivate.has(siloedNullifier.toString()) ? index : -1;
|
|
750
|
-
})
|
|
751
|
-
.filter(index => index !== -1);
|
|
752
|
-
const nonNoteNullifiers = executionNullifiers.filter((_, index) => !firstDuplicateIndexes.includes(index));
|
|
753
|
-
await this.addNullifiersFromPrivate(targetContractAddress, nonNoteNullifiers);
|
|
754
|
-
|
|
755
756
|
this.setContractAddress(currentContractAddress);
|
|
756
757
|
this.setMsgSender(currentMessageSender);
|
|
757
758
|
this.setFunctionSelector(currentFunctionSelector);
|
|
@@ -762,7 +763,7 @@ export class TXE implements TypedOracle {
|
|
|
762
763
|
async getInitialWitness(abi: FunctionAbi, argsHash: Fr, sideEffectCounter: number, isStaticCall: boolean) {
|
|
763
764
|
const argumentsSize = countArgumentsSize(abi);
|
|
764
765
|
|
|
765
|
-
const args = this.
|
|
766
|
+
const args = this.executionCache.getPreimage(argsHash);
|
|
766
767
|
|
|
767
768
|
if (args.length !== argumentsSize) {
|
|
768
769
|
throw new Error('Invalid arguments size');
|
|
@@ -836,7 +837,12 @@ export class TXE implements TypedOracle {
|
|
|
836
837
|
// When setting up a teardown call, we tell it that
|
|
837
838
|
// private execution used Gas(1, 1) so it can compute a tx fee.
|
|
838
839
|
const gasUsedByPrivate = isTeardown ? new Gas(1, 1) : Gas.empty();
|
|
839
|
-
const tx =
|
|
840
|
+
const tx = createTxForPublicCalls(
|
|
841
|
+
/*setupExecutionRequests=*/ [],
|
|
842
|
+
/*appExecutionRequests=*/ isTeardown ? [] : [executionRequest],
|
|
843
|
+
/*teardownExecutionRequests=*/ isTeardown ? executionRequest : undefined,
|
|
844
|
+
gasUsedByPrivate,
|
|
845
|
+
);
|
|
840
846
|
|
|
841
847
|
const result = await simulator.simulate(tx);
|
|
842
848
|
|
|
@@ -868,8 +874,8 @@ export class TXE implements TypedOracle {
|
|
|
868
874
|
isStaticCall,
|
|
869
875
|
);
|
|
870
876
|
|
|
871
|
-
const args = [this.functionSelector.toField(), ...this.
|
|
872
|
-
const newArgsHash = this.
|
|
877
|
+
const args = [this.functionSelector.toField(), ...this.executionCache.getPreimage(argsHash)];
|
|
878
|
+
const newArgsHash = this.executionCache.store(args);
|
|
873
879
|
|
|
874
880
|
const executionResult = await this.executePublicFunction(args, callContext, isTeardown);
|
|
875
881
|
|
|
@@ -1051,4 +1057,37 @@ export class TXE implements TypedOracle {
|
|
|
1051
1057
|
|
|
1052
1058
|
return preimage.value;
|
|
1053
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
/**
|
|
1062
|
+
* Used by contracts during execution to store arbitrary data in the local PXE database. The data is siloed/scoped
|
|
1063
|
+
* to a specific `contract`.
|
|
1064
|
+
* @param contract - The contract address to store the data under.
|
|
1065
|
+
* @param key - A field element representing the key to store the data under.
|
|
1066
|
+
* @param values - An array of field elements representing the data to store.
|
|
1067
|
+
*/
|
|
1068
|
+
store(contract: AztecAddress, key: Fr, values: Fr[]): Promise<void> {
|
|
1069
|
+
if (!contract.equals(this.contractAddress)) {
|
|
1070
|
+
// TODO(#10727): instead of this check check that this.contractAddress is allowed to process notes for contract
|
|
1071
|
+
throw new Error(
|
|
1072
|
+
`Contract address ${contract} does not match the oracle's contract address ${this.contractAddress}`,
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
return this.txeDatabase.store(this.contractAddress, key, values);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* Used by contracts during execution to load arbitrary data from the local PXE database. The data is siloed/scoped
|
|
1080
|
+
* to a specific `contract`.
|
|
1081
|
+
* @param contract - The contract address to load the data from.
|
|
1082
|
+
* @param key - A field element representing the key under which to load the data..
|
|
1083
|
+
* @returns An array of field elements representing the stored data or `null` if no data is stored under the key.
|
|
1084
|
+
*/
|
|
1085
|
+
load(contract: AztecAddress, key: Fr): Promise<Fr[] | null> {
|
|
1086
|
+
if (!contract.equals(this.contractAddress)) {
|
|
1087
|
+
// TODO(#10727): instead of this check check that this.contractAddress is allowed to process notes for contract
|
|
1088
|
+
this.debug(`Data not found for contract ${contract.toString()} and key ${key.toString()}`);
|
|
1089
|
+
return Promise.resolve(null);
|
|
1090
|
+
}
|
|
1091
|
+
return this.txeDatabase.load(this.contractAddress, key);
|
|
1092
|
+
}
|
|
1054
1093
|
}
|
|
@@ -18,7 +18,8 @@ import { openTmpStore } from '@aztec/kv-store/lmdb';
|
|
|
18
18
|
import { protocolContractNames } from '@aztec/protocol-contracts';
|
|
19
19
|
import { getCanonicalProtocolContract } from '@aztec/protocol-contracts/bundle';
|
|
20
20
|
import { enrichPublicSimulationError } from '@aztec/pxe';
|
|
21
|
-
import {
|
|
21
|
+
import { type TypedOracle } from '@aztec/simulator/client';
|
|
22
|
+
import { HashedValuesCache } from '@aztec/simulator/server';
|
|
22
23
|
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
23
24
|
import { MerkleTrees } from '@aztec/world-state';
|
|
24
25
|
|
|
@@ -42,9 +43,7 @@ export class TXEService {
|
|
|
42
43
|
static async init(logger: Logger) {
|
|
43
44
|
const store = openTmpStore(true);
|
|
44
45
|
const trees = await MerkleTrees.new(store, new NoopTelemetryClient(), logger);
|
|
45
|
-
const
|
|
46
|
-
const txHash = new Fr(1); // The txHash is used for computing the revertible nullifiers for non-revertible note hashes. It can be any value for testing.
|
|
47
|
-
const noteCache = new ExecutionNoteCache(txHash);
|
|
46
|
+
const executionCache = new HashedValuesCache();
|
|
48
47
|
const keyStore = new KeyStore(store);
|
|
49
48
|
const txeDatabase = new TXEDatabase(store);
|
|
50
49
|
// Register protocol contracts.
|
|
@@ -54,7 +53,7 @@ export class TXEService {
|
|
|
54
53
|
await txeDatabase.addContractInstance(instance);
|
|
55
54
|
}
|
|
56
55
|
logger.debug(`TXE service initialized`);
|
|
57
|
-
const txe = new TXE(logger, trees,
|
|
56
|
+
const txe = new TXE(logger, trees, executionCache, keyStore, txeDatabase);
|
|
58
57
|
const service = new TXEService(logger, txe);
|
|
59
58
|
await service.advanceBlocksBy(toSingle(new Fr(1n)));
|
|
60
59
|
return service;
|
|
@@ -272,25 +271,20 @@ export class TXEService {
|
|
|
272
271
|
return toForeignCallResult([toSingle(new Fr(blockNumber))]);
|
|
273
272
|
}
|
|
274
273
|
|
|
275
|
-
async
|
|
276
|
-
const
|
|
277
|
-
return toForeignCallResult([toSingle(
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
async packArguments(_length: ForeignCallSingle, values: ForeignCallArray) {
|
|
281
|
-
const packed = await this.typedOracle.packArgumentsArray(fromArray(values));
|
|
282
|
-
return toForeignCallResult([toSingle(packed)]);
|
|
274
|
+
async storeArrayInExecutionCache(args: ForeignCallArray) {
|
|
275
|
+
const hash = await this.typedOracle.storeArrayInExecutionCache(fromArray(args));
|
|
276
|
+
return toForeignCallResult([toSingle(hash)]);
|
|
283
277
|
}
|
|
284
278
|
|
|
285
279
|
// Since the argument is a slice, noir automatically adds a length field to oracle call.
|
|
286
|
-
async
|
|
287
|
-
const
|
|
288
|
-
return toForeignCallResult([toSingle(
|
|
280
|
+
async storeInExecutionCache(_length: ForeignCallSingle, values: ForeignCallArray) {
|
|
281
|
+
const returnsHash = await this.typedOracle.storeInExecutionCache(fromArray(values));
|
|
282
|
+
return toForeignCallResult([toSingle(returnsHash)]);
|
|
289
283
|
}
|
|
290
284
|
|
|
291
|
-
async
|
|
292
|
-
const
|
|
293
|
-
return toForeignCallResult([toArray(
|
|
285
|
+
async loadFromExecutionCache(hash: ForeignCallSingle) {
|
|
286
|
+
const returns = await this.typedOracle.loadFromExecutionCache(fromSingle(hash));
|
|
287
|
+
return toForeignCallResult([toArray(returns)]);
|
|
294
288
|
}
|
|
295
289
|
|
|
296
290
|
// Since the argument is a slice, noir automatically adds a length field to oracle call.
|
|
@@ -334,15 +328,6 @@ export class TXEService {
|
|
|
334
328
|
return toForeignCallResult([toArray(witness.toFields())]);
|
|
335
329
|
}
|
|
336
330
|
|
|
337
|
-
async getSiblingPath(blockNumber: ForeignCallSingle, treeId: ForeignCallSingle, leafIndex: ForeignCallSingle) {
|
|
338
|
-
const result = await this.typedOracle.getSiblingPath(
|
|
339
|
-
fromSingle(blockNumber).toNumber(),
|
|
340
|
-
fromSingle(treeId).toNumber(),
|
|
341
|
-
fromSingle(leafIndex),
|
|
342
|
-
);
|
|
343
|
-
return toForeignCallResult([toArray(result)]);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
331
|
async getNotes(
|
|
347
332
|
storageSlot: ForeignCallSingle,
|
|
348
333
|
numSelects: ForeignCallSingle,
|
|
@@ -434,6 +419,11 @@ export class TXEService {
|
|
|
434
419
|
return toForeignCallResult([toSingle(new Fr(0))]);
|
|
435
420
|
}
|
|
436
421
|
|
|
422
|
+
async notifyCreatedNullifier(innerNullifier: ForeignCallSingle) {
|
|
423
|
+
await this.typedOracle.notifyCreatedNullifier(fromSingle(innerNullifier));
|
|
424
|
+
return toForeignCallResult([toSingle(new Fr(0))]);
|
|
425
|
+
}
|
|
426
|
+
|
|
437
427
|
async checkNullifierExists(innerNullifier: ForeignCallSingle) {
|
|
438
428
|
const exists = await this.typedOracle.checkNullifierExists(fromSingle(innerNullifier));
|
|
439
429
|
return toForeignCallResult([toSingle(new Fr(exists))]);
|
|
@@ -598,6 +588,37 @@ export class TXEService {
|
|
|
598
588
|
return toForeignCallResult([]);
|
|
599
589
|
}
|
|
600
590
|
|
|
591
|
+
async store(contract: ForeignCallSingle, key: ForeignCallSingle, values: ForeignCallArray) {
|
|
592
|
+
const processedContract = AztecAddress.fromField(fromSingle(contract));
|
|
593
|
+
const processedKey = fromSingle(key);
|
|
594
|
+
const processedValues = fromArray(values);
|
|
595
|
+
await this.typedOracle.store(processedContract, processedKey, processedValues);
|
|
596
|
+
return toForeignCallResult([]);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Load data from pxe db.
|
|
601
|
+
* @param contract - The contract address.
|
|
602
|
+
* @param key - The key to load.
|
|
603
|
+
* @param tSize - The size of the serialized object to return.
|
|
604
|
+
* @returns The data found flag and the serialized object concatenated in one array.
|
|
605
|
+
*/
|
|
606
|
+
async load(contract: ForeignCallSingle, key: ForeignCallSingle, tSize: ForeignCallSingle) {
|
|
607
|
+
const processedContract = AztecAddress.fromField(fromSingle(contract));
|
|
608
|
+
const processedKey = fromSingle(key);
|
|
609
|
+
const values = await this.typedOracle.load(processedContract, processedKey);
|
|
610
|
+
// We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
|
|
611
|
+
// with two fields: `some` (a boolean) and `value` (a field array in this case).
|
|
612
|
+
if (values === null) {
|
|
613
|
+
// No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
|
|
614
|
+
const processedTSize = fromSingle(tSize).toNumber();
|
|
615
|
+
return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(processedTSize).fill(new Fr(0)))]);
|
|
616
|
+
} else {
|
|
617
|
+
// Data was found so we set `some` to 1 and return it along with `value`.
|
|
618
|
+
return toForeignCallResult([toSingle(new Fr(1)), toArray(values)]);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
601
622
|
// AVM opcodes
|
|
602
623
|
|
|
603
624
|
avmOpcodeEmitUnencryptedLog(_message: ForeignCallArray) {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
type PublicDataTreeLeafPreimage,
|
|
8
8
|
} from '@aztec/circuits.js';
|
|
9
9
|
import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash';
|
|
10
|
-
import { WorldStateDB } from '@aztec/simulator';
|
|
10
|
+
import { WorldStateDB } from '@aztec/simulator/server';
|
|
11
11
|
|
|
12
12
|
export class TXEWorldStateDB extends WorldStateDB {
|
|
13
13
|
constructor(private merkleDb: MerkleTreeWriteOperations, dataSource: ContractDataSource) {
|