@aztec/txe 0.59.0 → 0.61.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/oracle/txe_oracle.d.ts +18 -15
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +127 -91
- package/dest/txe_service/txe_service.d.ts +66 -68
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +135 -119
- package/package.json +15 -15
- package/src/oracle/txe_oracle.ts +175 -139
- package/src/txe_service/txe_service.ts +187 -173
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
PublicDataWitness,
|
|
8
8
|
PublicDataWrite,
|
|
9
9
|
PublicExecutionRequest,
|
|
10
|
+
SimulationError,
|
|
10
11
|
type UnencryptedL2Log,
|
|
11
12
|
} from '@aztec/circuit-types';
|
|
12
13
|
import { type CircuitWitnessGenerationStats } from '@aztec/circuit-types/stats';
|
|
@@ -17,6 +18,7 @@ import {
|
|
|
17
18
|
type ContractInstanceWithAddress,
|
|
18
19
|
Gas,
|
|
19
20
|
Header,
|
|
21
|
+
IndexedTaggingSecret,
|
|
20
22
|
type KeyValidationRequest,
|
|
21
23
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
22
24
|
type NULLIFIER_TREE_HEIGHT,
|
|
@@ -29,6 +31,7 @@ import {
|
|
|
29
31
|
type PublicDataTreeLeafPreimage,
|
|
30
32
|
TxContext,
|
|
31
33
|
computeContractClassId,
|
|
34
|
+
computeTaggingSecret,
|
|
32
35
|
deriveKeys,
|
|
33
36
|
getContractClassFromArtifact,
|
|
34
37
|
} from '@aztec/circuits.js';
|
|
@@ -42,11 +45,12 @@ import {
|
|
|
42
45
|
countArgumentsSize,
|
|
43
46
|
} from '@aztec/foundation/abi';
|
|
44
47
|
import { AztecAddress } from '@aztec/foundation/aztec-address';
|
|
48
|
+
import { poseidon2Hash } from '@aztec/foundation/crypto';
|
|
45
49
|
import { Fr } from '@aztec/foundation/fields';
|
|
46
50
|
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
47
51
|
import { Timer } from '@aztec/foundation/timer';
|
|
48
52
|
import { type KeyStore } from '@aztec/key-store';
|
|
49
|
-
import { ContractDataOracle } from '@aztec/pxe';
|
|
53
|
+
import { ContractDataOracle, enrichPublicSimulationError } from '@aztec/pxe';
|
|
50
54
|
import {
|
|
51
55
|
ExecutionError,
|
|
52
56
|
type ExecutionNoteCache,
|
|
@@ -78,9 +82,8 @@ export class TXE implements TypedOracle {
|
|
|
78
82
|
private msgSender: AztecAddress;
|
|
79
83
|
private functionSelector = FunctionSelector.fromField(new Fr(0));
|
|
80
84
|
private isStaticCall = false;
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
private calldata: Fr[] = [];
|
|
85
|
+
// Return/revert data of the latest nested call.
|
|
86
|
+
private nestedCallReturndata: Fr[] = [];
|
|
84
87
|
|
|
85
88
|
private contractDataOracle: ContractDataOracle;
|
|
86
89
|
|
|
@@ -127,18 +130,10 @@ export class TXE implements TypedOracle {
|
|
|
127
130
|
return this.functionSelector;
|
|
128
131
|
}
|
|
129
132
|
|
|
130
|
-
getCalldata() {
|
|
131
|
-
return this.calldata;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
133
|
setMsgSender(msgSender: Fr) {
|
|
135
134
|
this.msgSender = msgSender;
|
|
136
135
|
}
|
|
137
136
|
|
|
138
|
-
setCalldata(calldata: Fr[]) {
|
|
139
|
-
this.calldata = calldata;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
137
|
setFunctionSelector(functionSelector: FunctionSelector) {
|
|
143
138
|
this.functionSelector = functionSelector;
|
|
144
139
|
}
|
|
@@ -188,48 +183,24 @@ export class TXE implements TypedOracle {
|
|
|
188
183
|
blockNumber: number,
|
|
189
184
|
sideEffectsCounter = this.sideEffectsCounter,
|
|
190
185
|
isStaticCall = false,
|
|
191
|
-
isDelegateCall = false,
|
|
192
186
|
) {
|
|
193
187
|
const db = await this.#getTreesAt(blockNumber);
|
|
194
188
|
const previousBlockState = await this.#getTreesAt(blockNumber - 1);
|
|
195
189
|
|
|
196
190
|
const stateReference = await db.getStateReference();
|
|
197
191
|
const inputs = PrivateContextInputs.empty();
|
|
192
|
+
inputs.txContext.chainId = this.chainId;
|
|
193
|
+
inputs.txContext.version = this.version;
|
|
198
194
|
inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
|
|
199
195
|
inputs.historicalHeader.state = stateReference;
|
|
200
196
|
inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
|
|
201
197
|
(await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
|
|
202
198
|
);
|
|
203
|
-
inputs.callContext.msgSender
|
|
204
|
-
inputs.callContext.storageContractAddress = this.contractAddress;
|
|
205
|
-
inputs.callContext.isStaticCall = isStaticCall;
|
|
206
|
-
inputs.callContext.isDelegateCall = isDelegateCall;
|
|
199
|
+
inputs.callContext = new CallContext(this.msgSender, this.contractAddress, this.functionSelector, isStaticCall);
|
|
207
200
|
inputs.startSideEffectCounter = sideEffectsCounter;
|
|
208
|
-
inputs.callContext.functionSelector = this.functionSelector;
|
|
209
201
|
return inputs;
|
|
210
202
|
}
|
|
211
203
|
|
|
212
|
-
async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
|
|
213
|
-
const nullifier = siloNullifier(targetAddress, innerNullifier!);
|
|
214
|
-
const db = await this.trees.getLatest();
|
|
215
|
-
const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
|
|
216
|
-
return index !== undefined;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async avmOpcodeEmitNullifier(nullifier: Fr) {
|
|
220
|
-
const db = await this.trees.getLatest();
|
|
221
|
-
const siloedNullifier = siloNullifier(this.contractAddress, nullifier);
|
|
222
|
-
await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()], NULLIFIER_SUBTREE_HEIGHT);
|
|
223
|
-
return Promise.resolve();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async avmOpcodeEmitNoteHash(noteHash: Fr) {
|
|
227
|
-
const db = await this.trees.getLatest();
|
|
228
|
-
const siloedNoteHash = siloNoteHash(this.contractAddress, noteHash);
|
|
229
|
-
await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
|
|
230
|
-
return Promise.resolve();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
204
|
deriveKeys(secret: Fr) {
|
|
234
205
|
return deriveKeys(secret);
|
|
235
206
|
}
|
|
@@ -468,24 +439,6 @@ export class TXE implements TypedOracle {
|
|
|
468
439
|
throw new Error('Method not implemented.');
|
|
469
440
|
}
|
|
470
441
|
|
|
471
|
-
async avmOpcodeStorageRead(slot: Fr) {
|
|
472
|
-
const db = await this.trees.getLatest();
|
|
473
|
-
|
|
474
|
-
const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, slot);
|
|
475
|
-
|
|
476
|
-
const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
477
|
-
if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
|
|
478
|
-
return Fr.ZERO;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
const preimage = (await db.getLeafPreimage(
|
|
482
|
-
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
483
|
-
lowLeafResult.index,
|
|
484
|
-
)) as PublicDataTreeLeafPreimage;
|
|
485
|
-
|
|
486
|
-
return preimage.value;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
442
|
async storageRead(
|
|
490
443
|
contractAddress: Fr,
|
|
491
444
|
startStorageSlot: Fr,
|
|
@@ -555,13 +508,12 @@ export class TXE implements TypedOracle {
|
|
|
555
508
|
argsHash: Fr,
|
|
556
509
|
sideEffectCounter: number,
|
|
557
510
|
isStaticCall: boolean,
|
|
558
|
-
isDelegateCall: boolean,
|
|
559
511
|
) {
|
|
560
512
|
this.logger.verbose(
|
|
561
513
|
`Executing external function ${await this.getDebugFunctionName(
|
|
562
514
|
targetContractAddress,
|
|
563
515
|
functionSelector,
|
|
564
|
-
)}@${targetContractAddress} isStaticCall=${isStaticCall}
|
|
516
|
+
)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
565
517
|
);
|
|
566
518
|
|
|
567
519
|
// Store and modify env
|
|
@@ -575,13 +527,7 @@ export class TXE implements TypedOracle {
|
|
|
575
527
|
const artifact = await this.contractDataOracle.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
576
528
|
|
|
577
529
|
const acir = artifact.bytecode;
|
|
578
|
-
const initialWitness = await this.getInitialWitness(
|
|
579
|
-
artifact,
|
|
580
|
-
argsHash,
|
|
581
|
-
sideEffectCounter,
|
|
582
|
-
isStaticCall,
|
|
583
|
-
isDelegateCall,
|
|
584
|
-
);
|
|
530
|
+
const initialWitness = await this.getInitialWitness(artifact, argsHash, sideEffectCounter, isStaticCall);
|
|
585
531
|
const acvmCallback = new Oracle(this);
|
|
586
532
|
const timer = new Timer();
|
|
587
533
|
try {
|
|
@@ -633,13 +579,7 @@ export class TXE implements TypedOracle {
|
|
|
633
579
|
}
|
|
634
580
|
}
|
|
635
581
|
|
|
636
|
-
async getInitialWitness(
|
|
637
|
-
abi: FunctionAbi,
|
|
638
|
-
argsHash: Fr,
|
|
639
|
-
sideEffectCounter: number,
|
|
640
|
-
isStaticCall: boolean,
|
|
641
|
-
isDelegateCall: boolean,
|
|
642
|
-
) {
|
|
582
|
+
async getInitialWitness(abi: FunctionAbi, argsHash: Fr, sideEffectCounter: number, isStaticCall: boolean) {
|
|
643
583
|
const argumentsSize = countArgumentsSize(abi);
|
|
644
584
|
|
|
645
585
|
const args = this.packedValuesCache.unpack(argsHash);
|
|
@@ -652,7 +592,6 @@ export class TXE implements TypedOracle {
|
|
|
652
592
|
this.blockNumber - 1,
|
|
653
593
|
sideEffectCounter,
|
|
654
594
|
isStaticCall,
|
|
655
|
-
isDelegateCall,
|
|
656
595
|
);
|
|
657
596
|
|
|
658
597
|
const fields = [...privateContextInputs.toFields(), ...args];
|
|
@@ -680,21 +619,34 @@ export class TXE implements TypedOracle {
|
|
|
680
619
|
return `${artifact.name}:${f.name}`;
|
|
681
620
|
}
|
|
682
621
|
|
|
683
|
-
async executePublicFunction(
|
|
684
|
-
targetContractAddress: AztecAddress,
|
|
685
|
-
args: Fr[],
|
|
686
|
-
callContext: CallContext,
|
|
687
|
-
counter: number,
|
|
688
|
-
) {
|
|
622
|
+
private async executePublicFunction(args: Fr[], callContext: CallContext, counter: number) {
|
|
689
623
|
const executor = new PublicExecutor(
|
|
690
624
|
new TXEWorldStateDB(await this.trees.getLatest(), new TXEPublicContractDataSource(this)),
|
|
691
625
|
new NoopTelemetryClient(),
|
|
692
626
|
);
|
|
693
|
-
const execution = new PublicExecutionRequest(
|
|
627
|
+
const execution = new PublicExecutionRequest(callContext, args);
|
|
628
|
+
|
|
629
|
+
const db = await this.trees.getLatest();
|
|
630
|
+
const previousBlockState = await this.#getTreesAt(this.blockNumber - 1);
|
|
631
|
+
|
|
632
|
+
const combinedConstantData = CombinedConstantData.empty();
|
|
633
|
+
combinedConstantData.globalVariables.chainId = this.chainId;
|
|
634
|
+
combinedConstantData.globalVariables.version = this.version;
|
|
635
|
+
combinedConstantData.globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
636
|
+
combinedConstantData.historicalHeader.globalVariables.chainId = this.chainId;
|
|
637
|
+
combinedConstantData.historicalHeader.globalVariables.version = this.version;
|
|
638
|
+
combinedConstantData.historicalHeader.globalVariables.blockNumber = new Fr(this.blockNumber - 1);
|
|
639
|
+
combinedConstantData.historicalHeader.state = await db.getStateReference();
|
|
640
|
+
combinedConstantData.historicalHeader.lastArchive.root = Fr.fromBuffer(
|
|
641
|
+
(await previousBlockState.getTreeInfo(MerkleTreeId.ARCHIVE)).root,
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
combinedConstantData.txContext.chainId = this.chainId;
|
|
645
|
+
combinedConstantData.txContext.version = this.version;
|
|
694
646
|
|
|
695
647
|
const executionResult = executor.simulate(
|
|
696
648
|
execution,
|
|
697
|
-
|
|
649
|
+
combinedConstantData,
|
|
698
650
|
Gas.test(),
|
|
699
651
|
TxContext.empty(),
|
|
700
652
|
/* pendingNullifiers */ [],
|
|
@@ -704,54 +656,12 @@ export class TXE implements TypedOracle {
|
|
|
704
656
|
return Promise.resolve(executionResult);
|
|
705
657
|
}
|
|
706
658
|
|
|
707
|
-
async avmOpcodeCall(
|
|
708
|
-
targetContractAddress: AztecAddress,
|
|
709
|
-
functionSelector: FunctionSelector,
|
|
710
|
-
args: Fr[],
|
|
711
|
-
isStaticCall: boolean,
|
|
712
|
-
isDelegateCall: boolean,
|
|
713
|
-
) {
|
|
714
|
-
// Store and modify env
|
|
715
|
-
const currentContractAddress = AztecAddress.fromField(this.contractAddress);
|
|
716
|
-
const currentMessageSender = AztecAddress.fromField(this.msgSender);
|
|
717
|
-
const currentFunctionSelector = FunctionSelector.fromField(this.functionSelector.toField());
|
|
718
|
-
this.setMsgSender(this.contractAddress);
|
|
719
|
-
this.setContractAddress(targetContractAddress);
|
|
720
|
-
this.setFunctionSelector(functionSelector);
|
|
721
|
-
this.setCalldata(args);
|
|
722
|
-
|
|
723
|
-
const callContext = CallContext.empty();
|
|
724
|
-
callContext.msgSender = this.msgSender;
|
|
725
|
-
callContext.functionSelector = this.functionSelector;
|
|
726
|
-
callContext.storageContractAddress = targetContractAddress;
|
|
727
|
-
callContext.isStaticCall = isStaticCall;
|
|
728
|
-
callContext.isDelegateCall = isDelegateCall;
|
|
729
|
-
|
|
730
|
-
const executionResult = await this.executePublicFunction(
|
|
731
|
-
targetContractAddress,
|
|
732
|
-
args,
|
|
733
|
-
callContext,
|
|
734
|
-
this.sideEffectsCounter,
|
|
735
|
-
);
|
|
736
|
-
|
|
737
|
-
// Apply side effects
|
|
738
|
-
if (!executionResult.reverted) {
|
|
739
|
-
this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
|
|
740
|
-
}
|
|
741
|
-
this.setContractAddress(currentContractAddress);
|
|
742
|
-
this.setMsgSender(currentMessageSender);
|
|
743
|
-
this.setFunctionSelector(currentFunctionSelector);
|
|
744
|
-
|
|
745
|
-
return executionResult;
|
|
746
|
-
}
|
|
747
|
-
|
|
748
659
|
async enqueuePublicFunctionCall(
|
|
749
660
|
targetContractAddress: AztecAddress,
|
|
750
661
|
functionSelector: FunctionSelector,
|
|
751
662
|
argsHash: Fr,
|
|
752
663
|
sideEffectCounter: number,
|
|
753
664
|
isStaticCall: boolean,
|
|
754
|
-
isDelegateCall: boolean,
|
|
755
665
|
): Promise<Fr> {
|
|
756
666
|
// Store and modify env
|
|
757
667
|
const currentContractAddress = AztecAddress.fromField(this.contractAddress);
|
|
@@ -761,29 +671,44 @@ export class TXE implements TypedOracle {
|
|
|
761
671
|
this.setContractAddress(targetContractAddress);
|
|
762
672
|
this.setFunctionSelector(functionSelector);
|
|
763
673
|
|
|
764
|
-
const callContext = CallContext
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
674
|
+
const callContext = new CallContext(
|
|
675
|
+
/* msgSender */ currentContractAddress,
|
|
676
|
+
targetContractAddress,
|
|
677
|
+
FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)),
|
|
678
|
+
isStaticCall,
|
|
679
|
+
);
|
|
770
680
|
|
|
771
681
|
const args = [this.functionSelector.toField(), ...this.packedValuesCache.unpack(argsHash)];
|
|
772
682
|
const newArgsHash = this.packedValuesCache.pack(args);
|
|
773
683
|
|
|
774
|
-
const executionResult = await this.executePublicFunction(
|
|
775
|
-
targetContractAddress,
|
|
776
|
-
args,
|
|
777
|
-
callContext,
|
|
778
|
-
sideEffectCounter,
|
|
779
|
-
);
|
|
684
|
+
const executionResult = await this.executePublicFunction(args, callContext, sideEffectCounter);
|
|
780
685
|
|
|
686
|
+
// Poor man's revert handling
|
|
781
687
|
if (executionResult.reverted) {
|
|
782
|
-
|
|
688
|
+
if (executionResult.revertReason && executionResult.revertReason instanceof SimulationError) {
|
|
689
|
+
await enrichPublicSimulationError(
|
|
690
|
+
executionResult.revertReason,
|
|
691
|
+
this.contractDataOracle,
|
|
692
|
+
this.txeDatabase,
|
|
693
|
+
this.logger,
|
|
694
|
+
);
|
|
695
|
+
throw new Error(executionResult.revertReason.message);
|
|
696
|
+
} else {
|
|
697
|
+
throw new Error(`Enqueued public function call reverted: ${executionResult.revertReason}`);
|
|
698
|
+
}
|
|
783
699
|
}
|
|
784
700
|
|
|
785
701
|
// Apply side effects
|
|
786
702
|
this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
|
|
703
|
+
await this.addNoteHashes(
|
|
704
|
+
targetContractAddress,
|
|
705
|
+
executionResult.noteHashes.map(noteHash => noteHash.value),
|
|
706
|
+
);
|
|
707
|
+
await this.addNullifiers(
|
|
708
|
+
targetContractAddress,
|
|
709
|
+
executionResult.nullifiers.map(nullifier => nullifier.value),
|
|
710
|
+
);
|
|
711
|
+
|
|
787
712
|
this.setContractAddress(currentContractAddress);
|
|
788
713
|
this.setMsgSender(currentMessageSender);
|
|
789
714
|
this.setFunctionSelector(currentFunctionSelector);
|
|
@@ -797,7 +722,6 @@ export class TXE implements TypedOracle {
|
|
|
797
722
|
argsHash: Fr,
|
|
798
723
|
sideEffectCounter: number,
|
|
799
724
|
isStaticCall: boolean,
|
|
800
|
-
isDelegateCall: boolean,
|
|
801
725
|
): Promise<Fr> {
|
|
802
726
|
// Definitely not right, in that the teardown should always be last.
|
|
803
727
|
// But useful for executing flows.
|
|
@@ -807,7 +731,6 @@ export class TXE implements TypedOracle {
|
|
|
807
731
|
argsHash,
|
|
808
732
|
sideEffectCounter,
|
|
809
733
|
isStaticCall,
|
|
810
|
-
isDelegateCall,
|
|
811
734
|
);
|
|
812
735
|
}
|
|
813
736
|
|
|
@@ -828,4 +751,117 @@ export class TXE implements TypedOracle {
|
|
|
828
751
|
this.sideEffectsCounter = counter + 1;
|
|
829
752
|
return;
|
|
830
753
|
}
|
|
754
|
+
|
|
755
|
+
async getAppTaggingSecret(sender: AztecAddress, recipient: AztecAddress): Promise<IndexedTaggingSecret> {
|
|
756
|
+
const senderCompleteAddress = await this.getCompleteAddress(sender);
|
|
757
|
+
const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
|
|
758
|
+
const sharedSecret = computeTaggingSecret(senderCompleteAddress, senderIvsk, recipient);
|
|
759
|
+
// Silo the secret to the app so it can't be used to track other app's notes
|
|
760
|
+
const secret = poseidon2Hash([sharedSecret.x, sharedSecret.y, this.contractAddress]);
|
|
761
|
+
const [index] = await this.txeDatabase.getTaggingSecretsIndexes([secret]);
|
|
762
|
+
return new IndexedTaggingSecret(secret, index);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
async getAppTaggingSecretsForSenders(recipient: AztecAddress): Promise<IndexedTaggingSecret[]> {
|
|
766
|
+
const recipientCompleteAddress = await this.getCompleteAddress(recipient);
|
|
767
|
+
const completeAddresses = await this.txeDatabase.getCompleteAddresses();
|
|
768
|
+
// Filter out the addresses corresponding to accounts
|
|
769
|
+
const accounts = await this.keyStore.getAccounts();
|
|
770
|
+
const senders = completeAddresses.filter(
|
|
771
|
+
completeAddress => !accounts.find(account => account.equals(completeAddress.address)),
|
|
772
|
+
);
|
|
773
|
+
const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
|
|
774
|
+
const secrets = senders.map(({ address: sender }) => {
|
|
775
|
+
const sharedSecret = computeTaggingSecret(recipientCompleteAddress, recipientIvsk, sender);
|
|
776
|
+
return poseidon2Hash([sharedSecret.x, sharedSecret.y, this.contractAddress]);
|
|
777
|
+
});
|
|
778
|
+
const indexes = await this.txeDatabase.getTaggingSecretsIndexes(secrets);
|
|
779
|
+
return secrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i]));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// AVM oracles
|
|
783
|
+
|
|
784
|
+
async avmOpcodeCall(targetContractAddress: AztecAddress, args: Fr[], isStaticCall: boolean) {
|
|
785
|
+
// Store and modify env
|
|
786
|
+
const currentContractAddress = AztecAddress.fromField(this.contractAddress);
|
|
787
|
+
const currentMessageSender = AztecAddress.fromField(this.msgSender);
|
|
788
|
+
this.setMsgSender(this.contractAddress);
|
|
789
|
+
this.setContractAddress(targetContractAddress);
|
|
790
|
+
|
|
791
|
+
const callContext = new CallContext(
|
|
792
|
+
/* msgSender */ currentContractAddress,
|
|
793
|
+
targetContractAddress,
|
|
794
|
+
FunctionSelector.fromField(new Fr(PUBLIC_DISPATCH_SELECTOR)),
|
|
795
|
+
isStaticCall,
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
const executionResult = await this.executePublicFunction(args, callContext, this.sideEffectsCounter);
|
|
799
|
+
// Save return/revert data for later.
|
|
800
|
+
this.nestedCallReturndata = executionResult.returnValues;
|
|
801
|
+
|
|
802
|
+
// Apply side effects
|
|
803
|
+
if (!executionResult.reverted) {
|
|
804
|
+
this.sideEffectsCounter = executionResult.endSideEffectCounter.toNumber() + 1;
|
|
805
|
+
await this.addNoteHashes(
|
|
806
|
+
targetContractAddress,
|
|
807
|
+
executionResult.noteHashes.map(noteHash => noteHash.value),
|
|
808
|
+
);
|
|
809
|
+
await this.addNullifiers(
|
|
810
|
+
targetContractAddress,
|
|
811
|
+
executionResult.nullifiers.map(nullifier => nullifier.value),
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
this.setContractAddress(currentContractAddress);
|
|
816
|
+
this.setMsgSender(currentMessageSender);
|
|
817
|
+
|
|
818
|
+
return executionResult;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
avmOpcodeReturndataSize(): number {
|
|
822
|
+
return this.nestedCallReturndata.length;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
avmOpcodeReturndataCopy(rdOffset: number, copySize: number): Fr[] {
|
|
826
|
+
return this.nestedCallReturndata.slice(rdOffset, rdOffset + copySize);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
async avmOpcodeNullifierExists(innerNullifier: Fr, targetAddress: AztecAddress): Promise<boolean> {
|
|
830
|
+
const nullifier = siloNullifier(targetAddress, innerNullifier!);
|
|
831
|
+
const db = await this.trees.getLatest();
|
|
832
|
+
const index = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
|
|
833
|
+
return index !== undefined;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
async avmOpcodeEmitNullifier(nullifier: Fr) {
|
|
837
|
+
const db = await this.trees.getLatest();
|
|
838
|
+
const siloedNullifier = siloNullifier(this.contractAddress, nullifier);
|
|
839
|
+
await db.batchInsert(MerkleTreeId.NULLIFIER_TREE, [siloedNullifier.toBuffer()], NULLIFIER_SUBTREE_HEIGHT);
|
|
840
|
+
return Promise.resolve();
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
async avmOpcodeEmitNoteHash(noteHash: Fr) {
|
|
844
|
+
const db = await this.trees.getLatest();
|
|
845
|
+
const siloedNoteHash = siloNoteHash(this.contractAddress, noteHash);
|
|
846
|
+
await db.appendLeaves(MerkleTreeId.NOTE_HASH_TREE, [siloedNoteHash]);
|
|
847
|
+
return Promise.resolve();
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
async avmOpcodeStorageRead(slot: Fr) {
|
|
851
|
+
const db = await this.trees.getLatest();
|
|
852
|
+
|
|
853
|
+
const leafSlot = computePublicDataTreeLeafSlot(this.contractAddress, slot);
|
|
854
|
+
|
|
855
|
+
const lowLeafResult = await db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt());
|
|
856
|
+
if (!lowLeafResult || !lowLeafResult.alreadyPresent) {
|
|
857
|
+
return Fr.ZERO;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const preimage = (await db.getLeafPreimage(
|
|
861
|
+
MerkleTreeId.PUBLIC_DATA_TREE,
|
|
862
|
+
lowLeafResult.index,
|
|
863
|
+
)) as PublicDataTreeLeafPreimage;
|
|
864
|
+
|
|
865
|
+
return preimage.value;
|
|
866
|
+
}
|
|
831
867
|
}
|