@aztec/txe 0.0.1-fake-c83136db25 → 0.0.2-commit.217f559981
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/bin/index.d.ts +1 -1
- package/dest/constants.d.ts +3 -0
- package/dest/constants.d.ts.map +1 -0
- package/dest/constants.js +2 -0
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +85 -52
- package/dest/oracle/interfaces.d.ts +12 -9
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +10 -12
- package/dest/oracle/txe_oracle_top_level_context.d.ts +23 -14
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +194 -87
- package/dest/rpc_translator.d.ts +35 -20
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +138 -64
- package/dest/state_machine/archiver.d.ts +21 -51
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +63 -94
- package/dest/state_machine/dummy_p2p_client.d.ts +20 -13
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +41 -21
- package/dest/state_machine/global_variable_builder.d.ts +6 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +13 -1
- 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 +40 -23
- package/dest/state_machine/mock_epoch_cache.d.ts +14 -10
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +21 -13
- package/dest/state_machine/synchronizer.d.ts +3 -2
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +5 -4
- package/dest/txe_session.d.ts +21 -15
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +154 -53
- package/dest/util/encoding.d.ts +615 -16
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +1 -1
- package/dest/util/expected_failure_error.d.ts +1 -1
- package/dest/util/expected_failure_error.d.ts.map +1 -1
- package/dest/util/txe_account_store.d.ts +10 -0
- package/dest/util/txe_account_store.d.ts.map +1 -0
- package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
- package/dest/util/txe_public_contract_data_source.d.ts +8 -8
- package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
- package/dest/util/txe_public_contract_data_source.js +12 -29
- package/dest/utils/block_creation.d.ts +21 -6
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +38 -4
- package/dest/utils/tx_effect_creation.d.ts +3 -3
- package/dest/utils/tx_effect_creation.d.ts.map +1 -1
- package/dest/utils/tx_effect_creation.js +4 -7
- package/package.json +18 -17
- package/src/constants.ts +3 -0
- package/src/index.ts +97 -60
- package/src/oracle/interfaces.ts +11 -8
- package/src/oracle/txe_oracle_public_context.ts +12 -19
- package/src/oracle/txe_oracle_top_level_context.ts +229 -131
- package/src/rpc_translator.ts +164 -68
- package/src/state_machine/archiver.ts +63 -117
- package/src/state_machine/dummy_p2p_client.ts +58 -28
- package/src/state_machine/global_variable_builder.ts +22 -4
- package/src/state_machine/index.ts +60 -21
- package/src/state_machine/mock_epoch_cache.ts +25 -20
- package/src/state_machine/synchronizer.ts +6 -5
- package/src/txe_session.ts +210 -101
- package/src/util/encoding.ts +1 -1
- package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
- package/src/util/txe_public_contract_data_source.ts +20 -45
- package/src/utils/block_creation.ts +49 -14
- package/src/utils/tx_effect_creation.ts +5 -12
- package/dest/util/txe_account_data_provider.d.ts +0 -10
- package/dest/util/txe_account_data_provider.d.ts.map +0 -1
- package/dest/util/txe_contract_data_provider.d.ts +0 -12
- package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
- package/dest/util/txe_contract_data_provider.js +0 -22
- package/src/util/txe_contract_data_provider.ts +0 -36
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Schnorr } from '@aztec/foundation/crypto/schnorr';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
5
|
import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
6
7
|
import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
|
|
7
8
|
import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
|
|
8
9
|
import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
|
|
9
|
-
import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor
|
|
10
|
-
import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
10
|
+
import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
|
|
11
|
+
import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
11
12
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
13
|
+
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
12
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
|
-
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
14
15
|
import { computePartialAddress } from '@aztec/stdlib/contract';
|
|
15
16
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
16
|
-
import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
|
|
17
|
+
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
17
18
|
import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
18
19
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
19
|
-
import {
|
|
20
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
20
21
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
21
22
|
import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
22
23
|
import { ForkCheckpoint } from '@aztec/world-state';
|
|
24
|
+
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
23
25
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
24
|
-
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees,
|
|
26
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
25
27
|
export class TXEOracleTopLevelContext {
|
|
26
28
|
stateMachine;
|
|
27
|
-
|
|
29
|
+
contractStore;
|
|
30
|
+
noteStore;
|
|
28
31
|
keyStore;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
addressStore;
|
|
33
|
+
accountStore;
|
|
34
|
+
senderTaggingStore;
|
|
35
|
+
recipientTaggingStore;
|
|
36
|
+
senderAddressBookStore;
|
|
37
|
+
capsuleStore;
|
|
38
|
+
privateEventStore;
|
|
39
|
+
jobId;
|
|
32
40
|
nextBlockTimestamp;
|
|
33
41
|
version;
|
|
34
42
|
chainId;
|
|
@@ -36,13 +44,19 @@ export class TXEOracleTopLevelContext {
|
|
|
36
44
|
isMisc;
|
|
37
45
|
isTxe;
|
|
38
46
|
logger;
|
|
39
|
-
constructor(stateMachine,
|
|
47
|
+
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, jobId, nextBlockTimestamp, version, chainId, authwits){
|
|
40
48
|
this.stateMachine = stateMachine;
|
|
41
|
-
this.
|
|
49
|
+
this.contractStore = contractStore;
|
|
50
|
+
this.noteStore = noteStore;
|
|
42
51
|
this.keyStore = keyStore;
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
52
|
+
this.addressStore = addressStore;
|
|
53
|
+
this.accountStore = accountStore;
|
|
54
|
+
this.senderTaggingStore = senderTaggingStore;
|
|
55
|
+
this.recipientTaggingStore = recipientTaggingStore;
|
|
56
|
+
this.senderAddressBookStore = senderAddressBookStore;
|
|
57
|
+
this.capsuleStore = capsuleStore;
|
|
58
|
+
this.privateEventStore = privateEventStore;
|
|
59
|
+
this.jobId = jobId;
|
|
46
60
|
this.nextBlockTimestamp = nextBlockTimestamp;
|
|
47
61
|
this.version = version;
|
|
48
62
|
this.chainId = chainId;
|
|
@@ -63,17 +77,21 @@ export class TXEOracleTopLevelContext {
|
|
|
63
77
|
return Fr.random();
|
|
64
78
|
}
|
|
65
79
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
66
|
-
|
|
80
|
+
utilityLog(level, message, fields) {
|
|
67
81
|
if (!LogLevels[level]) {
|
|
68
|
-
throw new Error(`Invalid
|
|
82
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
69
83
|
}
|
|
70
84
|
const levelName = LogLevels[level];
|
|
71
85
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
|
|
72
86
|
module: `${this.logger.module}:debug_log`
|
|
73
87
|
});
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
txeGetDefaultAddress() {
|
|
91
|
+
return DEFAULT_ADDRESS;
|
|
74
92
|
}
|
|
75
93
|
async txeGetNextBlockNumber() {
|
|
76
|
-
return await this.getLastBlockNumber() + 1;
|
|
94
|
+
return BlockNumber(await this.getLastBlockNumber() + 1);
|
|
77
95
|
}
|
|
78
96
|
txeGetNextBlockTimestamp() {
|
|
79
97
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
@@ -82,7 +100,8 @@ export class TXEOracleTopLevelContext {
|
|
|
82
100
|
return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
|
|
83
101
|
}
|
|
84
102
|
async txeGetLastTxEffects() {
|
|
85
|
-
const
|
|
103
|
+
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
104
|
+
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
86
105
|
if (block.body.txEffects.length != 1) {
|
|
87
106
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
88
107
|
throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
|
|
@@ -94,6 +113,16 @@ export class TXEOracleTopLevelContext {
|
|
|
94
113
|
nullifiers: txEffects.nullifiers
|
|
95
114
|
};
|
|
96
115
|
}
|
|
116
|
+
async txeGetPrivateEvents(selector, contractAddress, scope) {
|
|
117
|
+
return (await this.privateEventStore.getPrivateEvents(selector, {
|
|
118
|
+
contractAddress,
|
|
119
|
+
scopes: [
|
|
120
|
+
scope
|
|
121
|
+
],
|
|
122
|
+
fromBlock: 0,
|
|
123
|
+
toBlock: await this.getLastBlockNumber() + 1
|
|
124
|
+
})).map((e)=>e.packedEvent);
|
|
125
|
+
}
|
|
97
126
|
async txeAdvanceBlocksBy(blocks) {
|
|
98
127
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
99
128
|
for(let i = 0; i < blocks; i++){
|
|
@@ -114,32 +143,32 @@ export class TXEOracleTopLevelContext {
|
|
|
114
143
|
if (!secret.equals(Fr.ZERO)) {
|
|
115
144
|
await this.txeAddAccount(artifact, instance, secret);
|
|
116
145
|
} else {
|
|
117
|
-
await this.
|
|
118
|
-
await this.
|
|
146
|
+
await this.contractStore.addContractInstance(instance);
|
|
147
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
119
148
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
120
149
|
}
|
|
121
150
|
}
|
|
122
151
|
async txeAddAccount(artifact, instance, secret) {
|
|
123
152
|
const partialAddress = await computePartialAddress(instance);
|
|
124
153
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
125
|
-
await this.
|
|
126
|
-
await this.
|
|
154
|
+
await this.contractStore.addContractInstance(instance);
|
|
155
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
127
156
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
128
|
-
await this.
|
|
129
|
-
await this.
|
|
157
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
158
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
130
159
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
131
160
|
return completeAddress;
|
|
132
161
|
}
|
|
133
162
|
async txeCreateAccount(secret) {
|
|
134
|
-
// This is a
|
|
163
|
+
// This is a foot gun !
|
|
135
164
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
136
|
-
await this.
|
|
137
|
-
await this.
|
|
165
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
166
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
138
167
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
139
168
|
return completeAddress;
|
|
140
169
|
}
|
|
141
170
|
async txeAddAuthWitness(address, messageHash) {
|
|
142
|
-
const account = await this.
|
|
171
|
+
const account = await this.accountStore.getAccount(address);
|
|
143
172
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
144
173
|
const schnorr = new Schnorr();
|
|
145
174
|
const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
|
|
@@ -158,42 +187,85 @@ export class TXEOracleTopLevelContext {
|
|
|
158
187
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
159
188
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
160
189
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
161
|
-
const
|
|
190
|
+
const globals = makeGlobalVariables(undefined, {
|
|
162
191
|
blockNumber,
|
|
163
192
|
timestamp: this.nextBlockTimestamp,
|
|
164
193
|
version: this.version,
|
|
165
194
|
chainId: this.chainId
|
|
166
|
-
})
|
|
195
|
+
});
|
|
196
|
+
const block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
167
197
|
txEffect
|
|
168
|
-
])
|
|
198
|
+
]);
|
|
169
199
|
await forkedWorldTrees.close();
|
|
170
200
|
this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
|
|
171
201
|
await this.stateMachine.handleL2Block(block);
|
|
172
202
|
}
|
|
173
203
|
async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
|
|
174
|
-
this.logger.verbose(`Executing external function ${await this.
|
|
175
|
-
const artifact = await this.
|
|
204
|
+
this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
205
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
176
206
|
if (!artifact) {
|
|
177
207
|
const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
|
|
178
208
|
throw new Error(message);
|
|
179
209
|
}
|
|
210
|
+
// When `from` is the zero address (e.g. when deploying a new account contract), we return an
|
|
211
|
+
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
212
|
+
const effectiveScopes = from.isZero() ? [] : [
|
|
213
|
+
from
|
|
214
|
+
];
|
|
215
|
+
// Sync notes before executing private function to discover notes from previous transactions
|
|
216
|
+
const utilityExecutor = async (call, execScopes)=>{
|
|
217
|
+
await this.executeUtilityCall(call, execScopes);
|
|
218
|
+
};
|
|
219
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
220
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, this.jobId, effectiveScopes);
|
|
180
221
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
181
222
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
182
223
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
183
224
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
184
225
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
185
226
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
186
|
-
const
|
|
187
|
-
const
|
|
188
|
-
|
|
227
|
+
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
228
|
+
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
229
|
+
// In production, the account contract sets the min revertible counter before calling the app function.
|
|
230
|
+
// Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
|
|
231
|
+
// marking all side effects as revertible.
|
|
232
|
+
const minRevertibleSideEffectCounter = 1;
|
|
233
|
+
await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
|
|
189
234
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
190
235
|
const simulator = new WASMSimulator();
|
|
191
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
236
|
+
const privateExecutionOracle = new PrivateExecutionOracle({
|
|
237
|
+
argsHash,
|
|
238
|
+
txContext,
|
|
239
|
+
callContext,
|
|
240
|
+
anchorBlockHeader: blockHeader,
|
|
241
|
+
utilityExecutor,
|
|
242
|
+
authWitnesses: Array.from(this.authwits.values()),
|
|
243
|
+
capsules: [],
|
|
244
|
+
executionCache: HashedValuesCache.create([
|
|
245
|
+
new HashedValues(args, argsHash)
|
|
246
|
+
]),
|
|
247
|
+
noteCache,
|
|
248
|
+
taggingIndexCache,
|
|
249
|
+
contractStore: this.contractStore,
|
|
250
|
+
noteStore: this.noteStore,
|
|
251
|
+
keyStore: this.keyStore,
|
|
252
|
+
addressStore: this.addressStore,
|
|
253
|
+
aztecNode: this.stateMachine.node,
|
|
254
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
255
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
256
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
257
|
+
capsuleStore: this.capsuleStore,
|
|
258
|
+
privateEventStore: this.privateEventStore,
|
|
259
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
260
|
+
jobId: this.jobId,
|
|
261
|
+
totalPublicCalldataCount: 0,
|
|
262
|
+
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
263
|
+
scopes: effectiveScopes,
|
|
264
|
+
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
265
|
+
// contract would perform, including setting senderForTags.
|
|
266
|
+
senderForTags: from,
|
|
267
|
+
simulator
|
|
268
|
+
});
|
|
197
269
|
// 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.
|
|
198
270
|
let result;
|
|
199
271
|
let executionResult;
|
|
@@ -208,18 +280,16 @@ export class TXEOracleTopLevelContext {
|
|
|
208
280
|
const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
|
|
209
281
|
return new HashedValues(calldata, r.calldataHash);
|
|
210
282
|
}));
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
|
|
283
|
+
noteCache.finish();
|
|
284
|
+
const nonceGenerator = noteCache.getNonceGenerator();
|
|
285
|
+
result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
|
|
215
286
|
} catch (err) {
|
|
216
287
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
217
288
|
}
|
|
218
|
-
// According to the protocol rules,
|
|
219
|
-
//
|
|
220
|
-
//
|
|
221
|
-
const
|
|
222
|
-
const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
|
|
289
|
+
// According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
|
|
290
|
+
// the nonce generator for the note hashes.
|
|
291
|
+
// We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
|
|
292
|
+
const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
|
|
223
293
|
const globals = makeGlobalVariables();
|
|
224
294
|
globals.blockNumber = blockNumber;
|
|
225
295
|
globals.timestamp = this.nextBlockTimestamp;
|
|
@@ -227,12 +297,17 @@ export class TXEOracleTopLevelContext {
|
|
|
227
297
|
globals.version = this.version;
|
|
228
298
|
globals.gasFees = GasFees.empty();
|
|
229
299
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
230
|
-
const
|
|
300
|
+
const bindings = this.logger.getBindings();
|
|
301
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
|
|
231
302
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
303
|
+
const config = PublicSimulatorConfig.from({
|
|
304
|
+
skipFeeEnforcement: true,
|
|
305
|
+
collectDebugLogs: true,
|
|
306
|
+
collectHints: false,
|
|
307
|
+
collectStatistics: false,
|
|
308
|
+
collectCallMetadata: true
|
|
309
|
+
});
|
|
310
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
|
|
236
311
|
const tx = await Tx.create({
|
|
237
312
|
data: publicInputs,
|
|
238
313
|
chonkProof: ChonkProof.empty(),
|
|
@@ -253,7 +328,7 @@ export class TXEOracleTopLevelContext {
|
|
|
253
328
|
} else if (!processedTx.revertCode.isOK()) {
|
|
254
329
|
if (processedTx.revertReason) {
|
|
255
330
|
try {
|
|
256
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
331
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
257
332
|
// eslint-disable-next-line no-empty
|
|
258
333
|
} catch {}
|
|
259
334
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -275,22 +350,21 @@ export class TXEOracleTopLevelContext {
|
|
|
275
350
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
276
351
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
277
352
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
278
|
-
const
|
|
353
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
279
354
|
txEffect
|
|
280
355
|
]);
|
|
281
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
282
356
|
await this.stateMachine.handleL2Block(l2Block);
|
|
283
357
|
await forkedWorldTrees.close();
|
|
284
358
|
return executionResult.returnValues ?? [];
|
|
285
359
|
}
|
|
286
360
|
async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
|
|
287
|
-
this.logger.verbose(`Executing public function ${await this.
|
|
361
|
+
this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
288
362
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
289
363
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
290
364
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
291
365
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
292
366
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
293
|
-
const anchorBlockHeader = await this.
|
|
367
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
294
368
|
const calldataHash = await computeCalldataHash(calldata);
|
|
295
369
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
296
370
|
const globals = makeGlobalVariables();
|
|
@@ -300,28 +374,31 @@ export class TXEOracleTopLevelContext {
|
|
|
300
374
|
globals.version = this.version;
|
|
301
375
|
globals.gasFees = GasFees.empty();
|
|
302
376
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
303
|
-
const
|
|
377
|
+
const bindings2 = this.logger.getBindings();
|
|
378
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
|
|
304
379
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
380
|
+
const config = PublicSimulatorConfig.from({
|
|
381
|
+
skipFeeEnforcement: true,
|
|
382
|
+
collectDebugLogs: true,
|
|
383
|
+
collectHints: false,
|
|
384
|
+
collectStatistics: false,
|
|
385
|
+
collectCallMetadata: true
|
|
308
386
|
});
|
|
309
|
-
const
|
|
387
|
+
const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
388
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
|
|
310
389
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
311
390
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
312
391
|
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
313
392
|
// unique.
|
|
314
393
|
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
315
|
-
|
|
316
|
-
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
317
|
-
}
|
|
394
|
+
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
318
395
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
319
396
|
// may require producing reverts.
|
|
320
397
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
321
398
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
322
399
|
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
323
400
|
const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
|
|
324
|
-
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*
|
|
401
|
+
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
|
|
325
402
|
const tx = await Tx.create({
|
|
326
403
|
data: txData,
|
|
327
404
|
chonkProof: ChonkProof.empty(),
|
|
@@ -344,7 +421,7 @@ export class TXEOracleTopLevelContext {
|
|
|
344
421
|
} else if (!processedTx.revertCode.isOK()) {
|
|
345
422
|
if (processedTx.revertReason) {
|
|
346
423
|
try {
|
|
347
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
424
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
348
425
|
// eslint-disable-next-line no-empty
|
|
349
426
|
} catch {}
|
|
350
427
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -367,25 +444,37 @@ export class TXEOracleTopLevelContext {
|
|
|
367
444
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
368
445
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
369
446
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
370
|
-
const
|
|
447
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
371
448
|
txEffect
|
|
372
449
|
]);
|
|
373
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
374
450
|
await this.stateMachine.handleL2Block(l2Block);
|
|
375
451
|
await forkedWorldTrees.close();
|
|
376
452
|
return returnValues ?? [];
|
|
377
453
|
}
|
|
378
|
-
async
|
|
379
|
-
const artifact = await this.
|
|
454
|
+
async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args) {
|
|
455
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
380
456
|
if (!artifact) {
|
|
381
457
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
382
458
|
}
|
|
383
|
-
|
|
459
|
+
// Sync notes before executing utility function to discover notes from previous transactions
|
|
460
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
461
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
|
|
462
|
+
await this.executeUtilityCall(call, execScopes);
|
|
463
|
+
}, blockHeader, this.jobId, 'ALL_SCOPES');
|
|
464
|
+
const call = FunctionCall.from({
|
|
384
465
|
name: artifact.name,
|
|
466
|
+
to: targetContractAddress,
|
|
385
467
|
selector: functionSelector,
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
468
|
+
type: FunctionType.UTILITY,
|
|
469
|
+
hideMsgSender: false,
|
|
470
|
+
isStatic: false,
|
|
471
|
+
args,
|
|
472
|
+
returnTypes: []
|
|
473
|
+
});
|
|
474
|
+
return this.executeUtilityCall(call, 'ALL_SCOPES');
|
|
475
|
+
}
|
|
476
|
+
async executeUtilityCall(call, scopes) {
|
|
477
|
+
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
389
478
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
390
479
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
391
480
|
}
|
|
@@ -394,8 +483,25 @@ export class TXEOracleTopLevelContext {
|
|
|
394
483
|
selector: call.selector
|
|
395
484
|
});
|
|
396
485
|
try {
|
|
397
|
-
const
|
|
398
|
-
const
|
|
486
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
487
|
+
const oracle = new UtilityExecutionOracle({
|
|
488
|
+
contractAddress: call.to,
|
|
489
|
+
authWitnesses: [],
|
|
490
|
+
capsules: [],
|
|
491
|
+
anchorBlockHeader,
|
|
492
|
+
contractStore: this.contractStore,
|
|
493
|
+
noteStore: this.noteStore,
|
|
494
|
+
keyStore: this.keyStore,
|
|
495
|
+
addressStore: this.addressStore,
|
|
496
|
+
aztecNode: this.stateMachine.node,
|
|
497
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
498
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
499
|
+
capsuleStore: this.capsuleStore,
|
|
500
|
+
privateEventStore: this.privateEventStore,
|
|
501
|
+
jobId: this.jobId,
|
|
502
|
+
scopes
|
|
503
|
+
});
|
|
504
|
+
const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
|
|
399
505
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
400
506
|
throw new ExecutionError(err.message, {
|
|
401
507
|
contractAddress: call.to,
|
|
@@ -404,10 +510,10 @@ export class TXEOracleTopLevelContext {
|
|
|
404
510
|
cause: err
|
|
405
511
|
});
|
|
406
512
|
});
|
|
407
|
-
this.logger.verbose(`Utility
|
|
513
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
408
514
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
409
515
|
} catch (err) {
|
|
410
|
-
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility
|
|
516
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
|
|
411
517
|
}
|
|
412
518
|
}
|
|
413
519
|
close() {
|
|
@@ -418,6 +524,7 @@ export class TXEOracleTopLevelContext {
|
|
|
418
524
|
];
|
|
419
525
|
}
|
|
420
526
|
async getLastBlockNumber() {
|
|
421
|
-
|
|
527
|
+
const header = await this.stateMachine.node.getBlockHeader('latest');
|
|
528
|
+
return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
422
529
|
}
|
|
423
530
|
}
|