@aztec/txe 0.86.0 → 0.87.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 +11 -6
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +209 -38
- package/dest/state_machine/archiver.d.ts +53 -0
- package/dest/state_machine/archiver.d.ts.map +1 -0
- package/dest/state_machine/archiver.js +100 -0
- package/dest/state_machine/dummy_p2p_client.d.ts +48 -0
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -0
- package/dest/state_machine/dummy_p2p_client.js +122 -0
- package/dest/state_machine/global_variable_builder.d.ts +23 -0
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -0
- package/dest/state_machine/global_variable_builder.js +29 -0
- package/dest/state_machine/index.d.ts +16 -0
- package/dest/state_machine/index.d.ts.map +1 -0
- package/dest/state_machine/index.js +48 -0
- package/dest/state_machine/synchronizer.d.ts +32 -0
- package/dest/state_machine/synchronizer.d.ts.map +1 -0
- package/dest/state_machine/synchronizer.js +58 -0
- package/dest/txe_service/txe_service.d.ts +12 -3
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +221 -37
- package/dest/util/encoding.d.ts +11 -4
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +38 -2
- package/package.json +18 -15
- package/src/oracle/txe_oracle.ts +387 -40
- package/src/state_machine/archiver.ts +132 -0
- package/src/state_machine/dummy_p2p_client.ts +167 -0
- package/src/state_machine/global_variable_builder.ts +55 -0
- package/src/state_machine/index.ts +71 -0
- package/src/state_machine/synchronizer.ts +87 -0
- package/src/txe_service/txe_service.ts +427 -31
- package/src/util/encoding.ts +51 -2
- package/dest/node/txe_node.d.ts +0 -320
- package/dest/node/txe_node.d.ts.map +0 -1
- package/dest/node/txe_node.js +0 -481
- package/src/node/txe_node.ts +0 -703
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { Body, L2Block, Note } from '@aztec/aztec.js';
|
|
1
|
+
import { type AztecNode, Body, L2Block, Note } from '@aztec/aztec.js';
|
|
2
2
|
import {
|
|
3
|
+
DEFAULT_GAS_LIMIT,
|
|
4
|
+
DEFAULT_TEARDOWN_GAS_LIMIT,
|
|
3
5
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
6
|
+
MAX_CONTRACT_CLASS_LOGS_PER_TX,
|
|
7
|
+
MAX_ENQUEUED_CALLS_PER_TX,
|
|
8
|
+
MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
|
|
9
|
+
MAX_L2_TO_L1_MSGS_PER_TX,
|
|
4
10
|
MAX_NOTE_HASHES_PER_TX,
|
|
5
11
|
MAX_NULLIFIERS_PER_TX,
|
|
12
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
6
13
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
7
14
|
type NULLIFIER_TREE_HEIGHT,
|
|
8
15
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
@@ -13,7 +20,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
|
|
|
13
20
|
import { Aes128, Schnorr, poseidon2Hash } from '@aztec/foundation/crypto';
|
|
14
21
|
import { Fr, Point } from '@aztec/foundation/fields';
|
|
15
22
|
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
16
|
-
import { Timer } from '@aztec/foundation/timer';
|
|
23
|
+
import { TestDateProvider, Timer } from '@aztec/foundation/timer';
|
|
17
24
|
import { KeyStore } from '@aztec/key-store';
|
|
18
25
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
19
26
|
import type { ProtocolContract } from '@aztec/protocol-contracts';
|
|
@@ -34,8 +41,11 @@ import {
|
|
|
34
41
|
type MessageLoadOracleInputs,
|
|
35
42
|
type NoteData,
|
|
36
43
|
Oracle,
|
|
44
|
+
PrivateExecutionOracle,
|
|
37
45
|
type TypedOracle,
|
|
46
|
+
UtilityExecutionOracle,
|
|
38
47
|
WASMSimulator,
|
|
48
|
+
executePrivateFunction,
|
|
39
49
|
extractCallStack,
|
|
40
50
|
extractPrivateCircuitPublicInputs,
|
|
41
51
|
pickNotes,
|
|
@@ -46,6 +56,7 @@ import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
|
|
|
46
56
|
import {
|
|
47
57
|
ExecutionError,
|
|
48
58
|
PublicContractsDB,
|
|
59
|
+
PublicProcessor,
|
|
49
60
|
type PublicTxResult,
|
|
50
61
|
PublicTxSimulator,
|
|
51
62
|
createSimulationError,
|
|
@@ -56,6 +67,7 @@ import {
|
|
|
56
67
|
EventSelector,
|
|
57
68
|
type FunctionAbi,
|
|
58
69
|
FunctionSelector,
|
|
70
|
+
FunctionType,
|
|
59
71
|
type NoteSelector,
|
|
60
72
|
countArgumentsSize,
|
|
61
73
|
} from '@aztec/stdlib/abi';
|
|
@@ -64,25 +76,33 @@ import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
|
64
76
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
65
77
|
import type { ContractInstance, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
66
78
|
import { SimulationError } from '@aztec/stdlib/errors';
|
|
67
|
-
import { Gas, GasFees } from '@aztec/stdlib/gas';
|
|
79
|
+
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
68
80
|
import {
|
|
69
81
|
computeNoteHashNonce,
|
|
70
82
|
computePublicDataTreeLeafSlot,
|
|
71
83
|
computeUniqueNoteHash,
|
|
84
|
+
computeVarArgsHash,
|
|
72
85
|
siloNoteHash,
|
|
73
86
|
siloNullifier,
|
|
74
87
|
} from '@aztec/stdlib/hash';
|
|
75
88
|
import type { MerkleTreeReadOperations, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
76
|
-
import { type KeyValidationRequest, PrivateContextInputs, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
77
|
-
import { deriveKeys } from '@aztec/stdlib/keys';
|
|
78
89
|
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
type KeyValidationRequest,
|
|
91
|
+
PartialPrivateTailPublicInputsForPublic,
|
|
92
|
+
PartialPrivateTailPublicInputsForRollup,
|
|
93
|
+
PrivateContextInputs,
|
|
94
|
+
PrivateKernelTailCircuitPublicInputs,
|
|
95
|
+
PrivateToPublicAccumulatedData,
|
|
96
|
+
PrivateToRollupAccumulatedData,
|
|
97
|
+
PublicCallRequest,
|
|
98
|
+
RollupValidationRequests,
|
|
99
|
+
ScopedLogHash,
|
|
100
|
+
} from '@aztec/stdlib/kernel';
|
|
101
|
+
import { deriveKeys } from '@aztec/stdlib/keys';
|
|
102
|
+
import { ContractClassLog, IndexedTaggingSecret, LogWithTxData, PrivateLog, type PublicLog } from '@aztec/stdlib/logs';
|
|
103
|
+
import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
|
|
85
104
|
import type { NoteStatus } from '@aztec/stdlib/note';
|
|
105
|
+
import { ClientIvcProof } from '@aztec/stdlib/proofs';
|
|
86
106
|
import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats';
|
|
87
107
|
import {
|
|
88
108
|
makeAppendOnlyTreeSnapshot,
|
|
@@ -103,13 +123,19 @@ import {
|
|
|
103
123
|
BlockHeader,
|
|
104
124
|
CallContext,
|
|
105
125
|
GlobalVariables,
|
|
126
|
+
HashedValues,
|
|
127
|
+
PrivateExecutionResult,
|
|
106
128
|
PublicCallRequestWithCalldata,
|
|
129
|
+
Tx,
|
|
130
|
+
TxConstantData,
|
|
131
|
+
TxContext,
|
|
107
132
|
TxEffect,
|
|
108
133
|
TxHash,
|
|
134
|
+
collectNested,
|
|
109
135
|
} from '@aztec/stdlib/tx';
|
|
110
136
|
import { ForkCheckpoint, NativeWorldStateService } from '@aztec/world-state/native';
|
|
111
137
|
|
|
112
|
-
import {
|
|
138
|
+
import { TXEStateMachine } from '../state_machine/index.js';
|
|
113
139
|
import { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
|
|
114
140
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
115
141
|
|
|
@@ -136,11 +162,11 @@ export class TXE implements TypedOracle {
|
|
|
136
162
|
private ROLLUP_VERSION = 1;
|
|
137
163
|
private CHAIN_ID = 1;
|
|
138
164
|
|
|
139
|
-
private node:
|
|
165
|
+
private node: AztecNode;
|
|
140
166
|
|
|
141
167
|
private simulationProvider = new WASMSimulator();
|
|
142
168
|
|
|
143
|
-
|
|
169
|
+
public noteCache: ExecutionNoteCache;
|
|
144
170
|
|
|
145
171
|
private authwits: Map<string, AuthWitness> = new Map();
|
|
146
172
|
|
|
@@ -159,10 +185,12 @@ export class TXE implements TypedOracle {
|
|
|
159
185
|
private contractAddress: AztecAddress,
|
|
160
186
|
private nativeWorldStateService: NativeWorldStateService,
|
|
161
187
|
private baseFork: MerkleTreeWriteOperations,
|
|
188
|
+
private stateMachine: TXEStateMachine,
|
|
162
189
|
) {
|
|
163
190
|
this.noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
164
191
|
|
|
165
|
-
this.node =
|
|
192
|
+
this.node = stateMachine.node;
|
|
193
|
+
|
|
166
194
|
// Default msg_sender (for entrypoints) is now Fr.max_value rather than 0 addr (see #7190 & #7404)
|
|
167
195
|
this.msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE);
|
|
168
196
|
|
|
@@ -182,14 +210,16 @@ export class TXE implements TypedOracle {
|
|
|
182
210
|
|
|
183
211
|
static async create(logger: Logger, store: AztecAsyncKVStore, protocolContracts: ProtocolContract[]) {
|
|
184
212
|
const executionCache = new HashedValuesCache();
|
|
185
|
-
|
|
213
|
+
|
|
214
|
+
const stateMachine = await TXEStateMachine.create(store);
|
|
215
|
+
const syncDataProvider = stateMachine.syncDataProvider;
|
|
216
|
+
const nativeWorldStateService = stateMachine.synchronizer.nativeWorldStateService;
|
|
186
217
|
const baseFork = await nativeWorldStateService.fork();
|
|
187
218
|
|
|
188
219
|
const addressDataProvider = new AddressDataProvider(store);
|
|
189
220
|
const privateEventDataProvider = new PrivateEventDataProvider(store);
|
|
190
221
|
const contractDataProvider = new ContractDataProvider(store);
|
|
191
222
|
const noteDataProvider = await NoteDataProvider.create(store);
|
|
192
|
-
const syncDataProvider = new SyncDataProvider(store);
|
|
193
223
|
const taggingDataProvider = new TaggingDataProvider(store);
|
|
194
224
|
const capsuleDataProvider = new CapsuleDataProvider(store);
|
|
195
225
|
const keyStore = new KeyStore(store);
|
|
@@ -217,6 +247,7 @@ export class TXE implements TypedOracle {
|
|
|
217
247
|
await AztecAddress.random(),
|
|
218
248
|
nativeWorldStateService,
|
|
219
249
|
baseFork,
|
|
250
|
+
stateMachine,
|
|
220
251
|
);
|
|
221
252
|
}
|
|
222
253
|
|
|
@@ -231,11 +262,11 @@ export class TXE implements TypedOracle {
|
|
|
231
262
|
}
|
|
232
263
|
|
|
233
264
|
getChainId(): Promise<Fr> {
|
|
234
|
-
return Promise.resolve(
|
|
265
|
+
return Promise.resolve(new Fr(this.CHAIN_ID));
|
|
235
266
|
}
|
|
236
267
|
|
|
237
268
|
getVersion(): Promise<Fr> {
|
|
238
|
-
return Promise.resolve(
|
|
269
|
+
return Promise.resolve(new Fr(this.ROLLUP_VERSION));
|
|
239
270
|
}
|
|
240
271
|
|
|
241
272
|
getMsgSender() {
|
|
@@ -268,7 +299,6 @@ export class TXE implements TypedOracle {
|
|
|
268
299
|
|
|
269
300
|
setBlockNumber(blockNumber: number) {
|
|
270
301
|
this.blockNumber = blockNumber;
|
|
271
|
-
this.node.setBlockNumber(blockNumber);
|
|
272
302
|
}
|
|
273
303
|
|
|
274
304
|
getContractDataProvider() {
|
|
@@ -316,8 +346,8 @@ export class TXE implements TypedOracle {
|
|
|
316
346
|
|
|
317
347
|
const stateReference = await snap.getStateReference();
|
|
318
348
|
const inputs = PrivateContextInputs.empty();
|
|
319
|
-
inputs.txContext.chainId = new Fr(
|
|
320
|
-
inputs.txContext.version = new Fr(
|
|
349
|
+
inputs.txContext.chainId = new Fr(this.CHAIN_ID);
|
|
350
|
+
inputs.txContext.version = new Fr(this.ROLLUP_VERSION);
|
|
321
351
|
inputs.historicalHeader.globalVariables.blockNumber = new Fr(blockNumber);
|
|
322
352
|
inputs.historicalHeader.state = stateReference;
|
|
323
353
|
inputs.historicalHeader.lastArchive.root = Fr.fromBuffer(
|
|
@@ -381,9 +411,7 @@ export class TXE implements TypedOracle {
|
|
|
381
411
|
addPublicLogs(logs: PublicLog[]) {
|
|
382
412
|
logs.forEach(log => {
|
|
383
413
|
try {
|
|
384
|
-
|
|
385
|
-
const tag = log.log[1];
|
|
386
|
-
|
|
414
|
+
const tag = log.fields[0];
|
|
387
415
|
this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
388
416
|
this.publicLogs.push(log);
|
|
389
417
|
} catch (err) {
|
|
@@ -619,7 +647,6 @@ export class TXE implements TypedOracle {
|
|
|
619
647
|
counter,
|
|
620
648
|
);
|
|
621
649
|
this.sideEffectCounter = counter + 1;
|
|
622
|
-
return Promise.resolve();
|
|
623
650
|
}
|
|
624
651
|
|
|
625
652
|
async notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
|
|
@@ -725,6 +752,7 @@ export class TXE implements TypedOracle {
|
|
|
725
752
|
txEffect.noteHashes = [...uniqueNoteHashesFromPrivate, ...this.uniqueNoteHashesFromPublic];
|
|
726
753
|
|
|
727
754
|
txEffect.nullifiers = [...this.siloedNullifiersFromPublic, ...this.noteCache.getAllNullifiers()];
|
|
755
|
+
|
|
728
756
|
if (usedTxRequestHashForNonces) {
|
|
729
757
|
txEffect.nullifiers.unshift(this.getTxRequestHash());
|
|
730
758
|
}
|
|
@@ -732,6 +760,7 @@ export class TXE implements TypedOracle {
|
|
|
732
760
|
txEffect.publicDataWrites = this.publicDataWrites;
|
|
733
761
|
txEffect.privateLogs = this.privateLogs;
|
|
734
762
|
txEffect.publicLogs = this.publicLogs;
|
|
763
|
+
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
735
764
|
|
|
736
765
|
const body = new Body([txEffect]);
|
|
737
766
|
|
|
@@ -771,10 +800,6 @@ export class TXE implements TypedOracle {
|
|
|
771
800
|
}
|
|
772
801
|
}
|
|
773
802
|
|
|
774
|
-
// At this point we always have a single tx in the block so we set the tx index to 0.
|
|
775
|
-
const txIndexInBlock = 0;
|
|
776
|
-
await this.node.processTxEffect(blockNumber, txIndexInBlock, new TxHash(new Fr(blockNumber)), txEffect);
|
|
777
|
-
|
|
778
803
|
const stateReference = await fork.getStateReference();
|
|
779
804
|
const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
780
805
|
const header = new BlockHeader(
|
|
@@ -792,14 +817,7 @@ export class TXE implements TypedOracle {
|
|
|
792
817
|
|
|
793
818
|
await fork.updateArchive(l2Block.header);
|
|
794
819
|
|
|
795
|
-
|
|
796
|
-
// Now emulate a "sync" to this block, by letting cpp reapply the block's
|
|
797
|
-
// changes to the underlying unforked world state and comparing the results
|
|
798
|
-
// against the block's state reference (which is this state reference here in the fork).
|
|
799
|
-
// This essentially commits the state updates to the unforked state and sanity checks the roots.
|
|
800
|
-
await this.nativeWorldStateService.handleL2BlockAndMessages(l2Block, l1ToL2Messages);
|
|
801
|
-
|
|
802
|
-
await this.syncDataProvider.setHeader(header);
|
|
820
|
+
await this.stateMachine.handleL2Block(l2Block);
|
|
803
821
|
|
|
804
822
|
this.publicDataWrites = [];
|
|
805
823
|
this.privateLogs = [];
|
|
@@ -818,6 +836,61 @@ export class TXE implements TypedOracle {
|
|
|
818
836
|
throw new Error('Method not implemented.');
|
|
819
837
|
}
|
|
820
838
|
|
|
839
|
+
async simulateUtilityFunction(targetContractAddress: AztecAddress, functionSelector: FunctionSelector, argsHash: Fr) {
|
|
840
|
+
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
841
|
+
if (!artifact) {
|
|
842
|
+
throw new Error(`Cannot call ${functionSelector} as there is artifact found at ${targetContractAddress}.`);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const call = {
|
|
846
|
+
name: artifact.name,
|
|
847
|
+
selector: functionSelector,
|
|
848
|
+
to: targetContractAddress,
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
|
|
852
|
+
|
|
853
|
+
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
854
|
+
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface, undefined, undefined);
|
|
858
|
+
|
|
859
|
+
try {
|
|
860
|
+
this.logger.verbose(`Executing utility function ${entryPointArtifact.name}`, {
|
|
861
|
+
contract: call.to,
|
|
862
|
+
selector: call.selector,
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
const args = await this.loadFromExecutionCache(argsHash);
|
|
866
|
+
const initialWitness = toACVMWitness(0, args);
|
|
867
|
+
const acirExecutionResult = await this.simulationProvider
|
|
868
|
+
.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle))
|
|
869
|
+
.catch((err: Error) => {
|
|
870
|
+
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
871
|
+
throw new ExecutionError(
|
|
872
|
+
err.message,
|
|
873
|
+
{
|
|
874
|
+
contractAddress: call.to,
|
|
875
|
+
functionSelector: call.selector,
|
|
876
|
+
},
|
|
877
|
+
extractCallStack(err, entryPointArtifact.debug),
|
|
878
|
+
{ cause: err },
|
|
879
|
+
);
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
|
|
883
|
+
this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
|
|
884
|
+
|
|
885
|
+
const returnHash = await computeVarArgsHash(returnWitness);
|
|
886
|
+
|
|
887
|
+
this.storeInExecutionCache(returnWitness, returnHash);
|
|
888
|
+
return returnHash;
|
|
889
|
+
} catch (err) {
|
|
890
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
821
894
|
async callPrivateFunction(
|
|
822
895
|
targetContractAddress: AztecAddress,
|
|
823
896
|
functionSelector: FunctionSelector,
|
|
@@ -934,8 +1007,8 @@ export class TXE implements TypedOracle {
|
|
|
934
1007
|
const db = this.baseFork;
|
|
935
1008
|
|
|
936
1009
|
const globalVariables = GlobalVariables.empty();
|
|
937
|
-
globalVariables.chainId = new Fr(
|
|
938
|
-
globalVariables.version = new Fr(
|
|
1010
|
+
globalVariables.chainId = new Fr(this.CHAIN_ID);
|
|
1011
|
+
globalVariables.version = new Fr(this.ROLLUP_VERSION);
|
|
939
1012
|
globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
940
1013
|
globalVariables.gasFees = new GasFees(1, 1);
|
|
941
1014
|
|
|
@@ -950,6 +1023,8 @@ export class TXE implements TypedOracle {
|
|
|
950
1023
|
contractsDB,
|
|
951
1024
|
globalVariables,
|
|
952
1025
|
/*doMerkleOperations=*/ false,
|
|
1026
|
+
/*skipFeeEnforcement=*/ false,
|
|
1027
|
+
/*clientInitiatedSimulation=*/ true,
|
|
953
1028
|
);
|
|
954
1029
|
|
|
955
1030
|
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
@@ -1273,4 +1348,276 @@ export class TXE implements TypedOracle {
|
|
|
1273
1348
|
txIndexInBlock,
|
|
1274
1349
|
);
|
|
1275
1350
|
}
|
|
1351
|
+
|
|
1352
|
+
async privateCallNewFlow(
|
|
1353
|
+
from: AztecAddress,
|
|
1354
|
+
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
1355
|
+
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
1356
|
+
args: Fr[],
|
|
1357
|
+
argsHash: Fr = Fr.zero(),
|
|
1358
|
+
isStaticCall: boolean = false,
|
|
1359
|
+
) {
|
|
1360
|
+
this.logger.verbose(
|
|
1361
|
+
`Executing external function ${await this.getDebugFunctionName(
|
|
1362
|
+
targetContractAddress,
|
|
1363
|
+
functionSelector,
|
|
1364
|
+
)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
1368
|
+
|
|
1369
|
+
if (artifact === undefined) {
|
|
1370
|
+
throw new Error('Function Artifact does not exist');
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
1374
|
+
|
|
1375
|
+
const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
1376
|
+
|
|
1377
|
+
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
1378
|
+
|
|
1379
|
+
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
1380
|
+
|
|
1381
|
+
const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
|
|
1382
|
+
|
|
1383
|
+
const blockHeader = await this.pxeOracleInterface.getBlockHeader();
|
|
1384
|
+
|
|
1385
|
+
const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
1386
|
+
|
|
1387
|
+
const context = new PrivateExecutionOracle(
|
|
1388
|
+
argsHash,
|
|
1389
|
+
txContext,
|
|
1390
|
+
callContext,
|
|
1391
|
+
/** Header of a block whose state is used during private execution (not the block the transaction is included in). */
|
|
1392
|
+
blockHeader,
|
|
1393
|
+
/** List of transient auth witnesses to be used during this simulation */
|
|
1394
|
+
[],
|
|
1395
|
+
/** List of transient auth witnesses to be used during this simulation */
|
|
1396
|
+
[],
|
|
1397
|
+
HashedValuesCache.create(),
|
|
1398
|
+
noteCache,
|
|
1399
|
+
this.pxeOracleInterface,
|
|
1400
|
+
this.simulationProvider,
|
|
1401
|
+
0,
|
|
1402
|
+
1,
|
|
1403
|
+
);
|
|
1404
|
+
|
|
1405
|
+
context.storeInExecutionCache(args, argsHash);
|
|
1406
|
+
|
|
1407
|
+
// Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
|
|
1408
|
+
let result;
|
|
1409
|
+
try {
|
|
1410
|
+
const executionResult = await executePrivateFunction(
|
|
1411
|
+
this.simulationProvider,
|
|
1412
|
+
context,
|
|
1413
|
+
artifact,
|
|
1414
|
+
targetContractAddress,
|
|
1415
|
+
functionSelector,
|
|
1416
|
+
);
|
|
1417
|
+
const { usedTxRequestHashForNonces } = noteCache.finish();
|
|
1418
|
+
const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
|
|
1419
|
+
|
|
1420
|
+
const publicCallRequests = collectNested([executionResult], r => [
|
|
1421
|
+
...r.publicInputs.publicCallRequests.map(r => r.inner),
|
|
1422
|
+
r.publicInputs.publicTeardownCallRequest,
|
|
1423
|
+
]).filter(r => !r.isEmpty());
|
|
1424
|
+
const publicFunctionsCalldata = await Promise.all(
|
|
1425
|
+
publicCallRequests.map(async r => {
|
|
1426
|
+
const calldata = await context.loadFromExecutionCache(r.calldataHash);
|
|
1427
|
+
return new HashedValues(calldata, r.calldataHash);
|
|
1428
|
+
}),
|
|
1429
|
+
);
|
|
1430
|
+
|
|
1431
|
+
result = new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const uniqueNoteHashes: Fr[] = [];
|
|
1437
|
+
const taggedPrivateLogs: PrivateLog[] = [];
|
|
1438
|
+
const nullifiers: Fr[] = result.firstNullifier.equals(Fr.ZERO)
|
|
1439
|
+
? [this.getTxRequestHash()]
|
|
1440
|
+
: noteCache.getAllNullifiers();
|
|
1441
|
+
const l2ToL1Messages: ScopedL2ToL1Message[] = [];
|
|
1442
|
+
const contractClassLogsHashes: ScopedLogHash[] = [];
|
|
1443
|
+
const publicCallRequests: PublicCallRequest[] = [];
|
|
1444
|
+
|
|
1445
|
+
const nonceGenerator = nullifiers[0];
|
|
1446
|
+
|
|
1447
|
+
let publicTeardownCallRequest;
|
|
1448
|
+
|
|
1449
|
+
let noteHashIndexInTx = 0;
|
|
1450
|
+
const executions = [result.entrypoint];
|
|
1451
|
+
while (executions.length !== 0) {
|
|
1452
|
+
const execution = executions.shift()!;
|
|
1453
|
+
executions.unshift(...execution!.nestedExecutions);
|
|
1454
|
+
|
|
1455
|
+
const { contractAddress } = execution.publicInputs.callContext;
|
|
1456
|
+
|
|
1457
|
+
const noteHashesFromExecution = await Promise.all(
|
|
1458
|
+
execution.publicInputs.noteHashes
|
|
1459
|
+
.filter(noteHash => !noteHash.isEmpty())
|
|
1460
|
+
.map(async noteHash => {
|
|
1461
|
+
const nonce = await computeNoteHashNonce(nonceGenerator, noteHashIndexInTx++);
|
|
1462
|
+
const siloedNoteHash = await siloNoteHash(contractAddress, noteHash.value);
|
|
1463
|
+
|
|
1464
|
+
// We could defer this to the public processor, and pass this in as non-revertible.
|
|
1465
|
+
return computeUniqueNoteHash(nonce, siloedNoteHash);
|
|
1466
|
+
}),
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
const privateLogsFromExecution = await Promise.all(
|
|
1470
|
+
execution.publicInputs.privateLogs
|
|
1471
|
+
.filter(privateLog => !privateLog.isEmpty())
|
|
1472
|
+
.map(async metadata => {
|
|
1473
|
+
metadata.log.fields[0] = await poseidon2Hash([contractAddress, metadata.log.fields[0]]);
|
|
1474
|
+
|
|
1475
|
+
return metadata.log;
|
|
1476
|
+
}),
|
|
1477
|
+
);
|
|
1478
|
+
|
|
1479
|
+
uniqueNoteHashes.push(...noteHashesFromExecution);
|
|
1480
|
+
taggedPrivateLogs.push(...privateLogsFromExecution);
|
|
1481
|
+
l2ToL1Messages.push(
|
|
1482
|
+
...execution.publicInputs.l2ToL1Msgs
|
|
1483
|
+
.filter(l2ToL1Message => !l2ToL1Message.isEmpty())
|
|
1484
|
+
.map(message => message.scope(contractAddress)),
|
|
1485
|
+
);
|
|
1486
|
+
contractClassLogsHashes.push(
|
|
1487
|
+
...execution.publicInputs.contractClassLogsHashes
|
|
1488
|
+
.filter(contractClassLogsHash => !contractClassLogsHash.isEmpty())
|
|
1489
|
+
.map(message => message.logHash.scope(contractAddress)),
|
|
1490
|
+
);
|
|
1491
|
+
publicCallRequests.push(
|
|
1492
|
+
...execution.publicInputs.publicCallRequests
|
|
1493
|
+
.filter(publicCallRequest => !publicCallRequest.isEmpty())
|
|
1494
|
+
.map(callRequest => callRequest.inner),
|
|
1495
|
+
);
|
|
1496
|
+
|
|
1497
|
+
if (publicTeardownCallRequest !== undefined && !execution.publicInputs.publicTeardownCallRequest.isEmpty()) {
|
|
1498
|
+
throw new Error('Trying to set multiple teardown requests');
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
publicTeardownCallRequest = execution.publicInputs.publicTeardownCallRequest.isEmpty()
|
|
1502
|
+
? publicTeardownCallRequest
|
|
1503
|
+
: execution.publicInputs.publicTeardownCallRequest;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const globals = makeGlobalVariables();
|
|
1507
|
+
globals.blockNumber = new Fr(this.blockNumber);
|
|
1508
|
+
globals.gasFees = GasFees.empty();
|
|
1509
|
+
|
|
1510
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
|
|
1511
|
+
const simulator = new PublicTxSimulator(this.baseFork, contractsDB, globals, true, true);
|
|
1512
|
+
const processor = new PublicProcessor(globals, this.baseFork, contractsDB, simulator, new TestDateProvider());
|
|
1513
|
+
|
|
1514
|
+
const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
|
|
1515
|
+
|
|
1516
|
+
const hasPublicCalls = result.publicFunctionCalldata.length !== 0;
|
|
1517
|
+
let inputsForRollup;
|
|
1518
|
+
let inputsForPublic;
|
|
1519
|
+
|
|
1520
|
+
// Private only
|
|
1521
|
+
if (result.publicFunctionCalldata.length === 0) {
|
|
1522
|
+
const accumulatedDataForRollup = new PrivateToRollupAccumulatedData(
|
|
1523
|
+
padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
1524
|
+
padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
1525
|
+
padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
1526
|
+
padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
1527
|
+
padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
|
|
1528
|
+
);
|
|
1529
|
+
|
|
1530
|
+
inputsForRollup = new PartialPrivateTailPublicInputsForRollup(accumulatedDataForRollup);
|
|
1531
|
+
} else {
|
|
1532
|
+
const accumulatedDataForPublic = new PrivateToPublicAccumulatedData(
|
|
1533
|
+
padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
1534
|
+
padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
1535
|
+
padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
1536
|
+
padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
1537
|
+
padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
|
|
1538
|
+
padArrayEnd(publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
|
|
1542
|
+
// We are using non-revertible because we set the first nullifier to be used as a nonce generator, otherwise the tx hash is manually calculated.
|
|
1543
|
+
// nonrevertible
|
|
1544
|
+
accumulatedDataForPublic,
|
|
1545
|
+
// revertible
|
|
1546
|
+
PrivateToPublicAccumulatedData.empty(),
|
|
1547
|
+
publicTeardownCallRequest ?? PublicCallRequest.empty(),
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
const txData = new PrivateKernelTailCircuitPublicInputs(
|
|
1552
|
+
constantData,
|
|
1553
|
+
RollupValidationRequests.empty(),
|
|
1554
|
+
/*gasUsed=*/ new Gas(0, 0),
|
|
1555
|
+
/*feePayer=*/ AztecAddress.zero(),
|
|
1556
|
+
hasPublicCalls ? inputsForPublic : undefined,
|
|
1557
|
+
!hasPublicCalls ? inputsForRollup : undefined,
|
|
1558
|
+
);
|
|
1559
|
+
|
|
1560
|
+
const tx = new Tx(txData, ClientIvcProof.empty(), [], result.publicFunctionCalldata);
|
|
1561
|
+
|
|
1562
|
+
const results = await processor.process([tx]);
|
|
1563
|
+
|
|
1564
|
+
const processedTxs = results[0];
|
|
1565
|
+
const failedTxs = results[1];
|
|
1566
|
+
|
|
1567
|
+
if (failedTxs.length !== 0) {
|
|
1568
|
+
throw new Error('Public execution has failed');
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
const fork = this.baseFork;
|
|
1572
|
+
|
|
1573
|
+
const txEffect = TxEffect.empty();
|
|
1574
|
+
|
|
1575
|
+
txEffect.noteHashes = processedTxs[0]!.txEffect.noteHashes;
|
|
1576
|
+
txEffect.nullifiers = processedTxs[0]!.txEffect.nullifiers;
|
|
1577
|
+
txEffect.privateLogs = taggedPrivateLogs;
|
|
1578
|
+
txEffect.publicLogs = processedTxs[0]!.txEffect.publicLogs;
|
|
1579
|
+
txEffect.publicDataWrites = processedTxs[0]!.txEffect.publicDataWrites;
|
|
1580
|
+
|
|
1581
|
+
txEffect.txHash = new TxHash(new Fr(this.blockNumber));
|
|
1582
|
+
|
|
1583
|
+
const body = new Body([txEffect]);
|
|
1584
|
+
|
|
1585
|
+
const l2Block = new L2Block(
|
|
1586
|
+
makeAppendOnlyTreeSnapshot(this.blockNumber + 1),
|
|
1587
|
+
makeHeader(0, this.blockNumber, this.blockNumber),
|
|
1588
|
+
body,
|
|
1589
|
+
);
|
|
1590
|
+
|
|
1591
|
+
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
1592
|
+
await fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
1593
|
+
|
|
1594
|
+
const stateReference = await fork.getStateReference();
|
|
1595
|
+
const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
1596
|
+
|
|
1597
|
+
const header = new BlockHeader(
|
|
1598
|
+
new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
|
|
1599
|
+
makeContentCommitment(),
|
|
1600
|
+
stateReference,
|
|
1601
|
+
globals,
|
|
1602
|
+
Fr.ZERO,
|
|
1603
|
+
Fr.ZERO,
|
|
1604
|
+
);
|
|
1605
|
+
|
|
1606
|
+
header.globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
1607
|
+
|
|
1608
|
+
l2Block.header = header;
|
|
1609
|
+
|
|
1610
|
+
await fork.updateArchive(l2Block.header);
|
|
1611
|
+
|
|
1612
|
+
await this.stateMachine.handleL2Block(l2Block);
|
|
1613
|
+
|
|
1614
|
+
const txRequestHash = this.getTxRequestHash();
|
|
1615
|
+
|
|
1616
|
+
this.setBlockNumber(this.blockNumber + 1);
|
|
1617
|
+
return {
|
|
1618
|
+
endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
|
|
1619
|
+
returnsHash: result.entrypoint.publicInputs.returnsHash,
|
|
1620
|
+
txHash: txRequestHash,
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1276
1623
|
}
|