@aztec/txe 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c
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/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 +177 -79
- package/dest/rpc_translator.d.ts +30 -18
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +127 -60
- package/dest/state_machine/archiver.d.ts +21 -52
- 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 +19 -14
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +41 -24
- package/dest/state_machine/global_variable_builder.d.ts +6 -5
- 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 +9 -6
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +14 -7
- 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 +151 -52
- package/dest/util/encoding.d.ts +618 -19
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +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 -18
- 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 +213 -124
- package/src/rpc_translator.ts +156 -60
- package/src/state_machine/archiver.ts +59 -114
- package/src/state_machine/dummy_p2p_client.ts +57 -32
- package/src/state_machine/global_variable_builder.ts +21 -4
- package/src/state_machine/index.ts +60 -21
- package/src/state_machine/mock_epoch_cache.ts +15 -11
- package/src/state_machine/synchronizer.ts +6 -5
- package/src/txe_session.ts +207 -100
- 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 -15
- 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,35 +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';
|
|
12
13
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
13
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
14
|
-
import { Body, L2Block } from '@aztec/stdlib/block';
|
|
15
15
|
import { computePartialAddress } from '@aztec/stdlib/contract';
|
|
16
16
|
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
17
17
|
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
18
18
|
import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
19
19
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
20
|
-
import {
|
|
20
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
21
21
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
22
22
|
import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
23
23
|
import { ForkCheckpoint } from '@aztec/world-state';
|
|
24
|
+
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
24
25
|
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
25
|
-
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees,
|
|
26
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
26
27
|
export class TXEOracleTopLevelContext {
|
|
27
28
|
stateMachine;
|
|
28
|
-
|
|
29
|
+
contractStore;
|
|
30
|
+
noteStore;
|
|
29
31
|
keyStore;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
addressStore;
|
|
33
|
+
accountStore;
|
|
34
|
+
senderTaggingStore;
|
|
35
|
+
recipientTaggingStore;
|
|
36
|
+
senderAddressBookStore;
|
|
37
|
+
capsuleStore;
|
|
38
|
+
privateEventStore;
|
|
39
|
+
jobId;
|
|
33
40
|
nextBlockTimestamp;
|
|
34
41
|
version;
|
|
35
42
|
chainId;
|
|
@@ -37,13 +44,19 @@ export class TXEOracleTopLevelContext {
|
|
|
37
44
|
isMisc;
|
|
38
45
|
isTxe;
|
|
39
46
|
logger;
|
|
40
|
-
constructor(stateMachine,
|
|
47
|
+
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, jobId, nextBlockTimestamp, version, chainId, authwits){
|
|
41
48
|
this.stateMachine = stateMachine;
|
|
42
|
-
this.
|
|
49
|
+
this.contractStore = contractStore;
|
|
50
|
+
this.noteStore = noteStore;
|
|
43
51
|
this.keyStore = keyStore;
|
|
44
|
-
this.
|
|
45
|
-
this.
|
|
46
|
-
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;
|
|
47
60
|
this.nextBlockTimestamp = nextBlockTimestamp;
|
|
48
61
|
this.version = version;
|
|
49
62
|
this.chainId = chainId;
|
|
@@ -64,17 +77,21 @@ export class TXEOracleTopLevelContext {
|
|
|
64
77
|
return Fr.random();
|
|
65
78
|
}
|
|
66
79
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
67
|
-
|
|
80
|
+
utilityLog(level, message, fields) {
|
|
68
81
|
if (!LogLevels[level]) {
|
|
69
|
-
throw new Error(`Invalid
|
|
82
|
+
throw new Error(`Invalid log level: ${level}`);
|
|
70
83
|
}
|
|
71
84
|
const levelName = LogLevels[level];
|
|
72
85
|
this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
|
|
73
86
|
module: `${this.logger.module}:debug_log`
|
|
74
87
|
});
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
txeGetDefaultAddress() {
|
|
91
|
+
return DEFAULT_ADDRESS;
|
|
75
92
|
}
|
|
76
93
|
async txeGetNextBlockNumber() {
|
|
77
|
-
return await this.getLastBlockNumber() + 1;
|
|
94
|
+
return BlockNumber(await this.getLastBlockNumber() + 1);
|
|
78
95
|
}
|
|
79
96
|
txeGetNextBlockTimestamp() {
|
|
80
97
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
@@ -83,7 +100,8 @@ export class TXEOracleTopLevelContext {
|
|
|
83
100
|
return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
|
|
84
101
|
}
|
|
85
102
|
async txeGetLastTxEffects() {
|
|
86
|
-
const
|
|
103
|
+
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
104
|
+
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
87
105
|
if (block.body.txEffects.length != 1) {
|
|
88
106
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
89
107
|
throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
|
|
@@ -95,6 +113,16 @@ export class TXEOracleTopLevelContext {
|
|
|
95
113
|
nullifiers: txEffects.nullifiers
|
|
96
114
|
};
|
|
97
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
|
+
}
|
|
98
126
|
async txeAdvanceBlocksBy(blocks) {
|
|
99
127
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
100
128
|
for(let i = 0; i < blocks; i++){
|
|
@@ -115,32 +143,32 @@ export class TXEOracleTopLevelContext {
|
|
|
115
143
|
if (!secret.equals(Fr.ZERO)) {
|
|
116
144
|
await this.txeAddAccount(artifact, instance, secret);
|
|
117
145
|
} else {
|
|
118
|
-
await this.
|
|
119
|
-
await this.
|
|
146
|
+
await this.contractStore.addContractInstance(instance);
|
|
147
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
120
148
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
121
149
|
}
|
|
122
150
|
}
|
|
123
151
|
async txeAddAccount(artifact, instance, secret) {
|
|
124
152
|
const partialAddress = await computePartialAddress(instance);
|
|
125
153
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
126
|
-
await this.
|
|
127
|
-
await this.
|
|
154
|
+
await this.contractStore.addContractInstance(instance);
|
|
155
|
+
await this.contractStore.addContractArtifact(artifact);
|
|
128
156
|
const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
|
|
129
|
-
await this.
|
|
130
|
-
await this.
|
|
157
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
158
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
131
159
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
132
160
|
return completeAddress;
|
|
133
161
|
}
|
|
134
162
|
async txeCreateAccount(secret) {
|
|
135
|
-
// This is a
|
|
163
|
+
// This is a foot gun !
|
|
136
164
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
137
|
-
await this.
|
|
138
|
-
await this.
|
|
165
|
+
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
166
|
+
await this.addressStore.addCompleteAddress(completeAddress);
|
|
139
167
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
140
168
|
return completeAddress;
|
|
141
169
|
}
|
|
142
170
|
async txeAddAuthWitness(address, messageHash) {
|
|
143
|
-
const account = await this.
|
|
171
|
+
const account = await this.accountStore.getAccount(address);
|
|
144
172
|
const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
|
|
145
173
|
const schnorr = new Schnorr();
|
|
146
174
|
const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
|
|
@@ -159,42 +187,85 @@ export class TXEOracleTopLevelContext {
|
|
|
159
187
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
160
188
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
161
189
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
162
|
-
const
|
|
190
|
+
const globals = makeGlobalVariables(undefined, {
|
|
163
191
|
blockNumber,
|
|
164
192
|
timestamp: this.nextBlockTimestamp,
|
|
165
193
|
version: this.version,
|
|
166
194
|
chainId: this.chainId
|
|
167
|
-
})
|
|
195
|
+
});
|
|
196
|
+
const block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
168
197
|
txEffect
|
|
169
|
-
])
|
|
198
|
+
]);
|
|
170
199
|
await forkedWorldTrees.close();
|
|
171
200
|
this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
|
|
172
201
|
await this.stateMachine.handleL2Block(block);
|
|
173
202
|
}
|
|
174
203
|
async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
|
|
175
|
-
this.logger.verbose(`Executing external function ${await this.
|
|
176
|
-
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);
|
|
177
206
|
if (!artifact) {
|
|
178
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';
|
|
179
208
|
throw new Error(message);
|
|
180
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);
|
|
181
221
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
182
222
|
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
183
223
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
184
224
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
185
225
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
186
226
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
187
|
-
const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
|
|
188
227
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
189
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);
|
|
190
234
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
191
235
|
const simulator = new WASMSimulator();
|
|
192
|
-
const privateExecutionOracle = new PrivateExecutionOracle(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
+
});
|
|
198
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.
|
|
199
270
|
let result;
|
|
200
271
|
let executionResult;
|
|
@@ -209,18 +280,16 @@ export class TXEOracleTopLevelContext {
|
|
|
209
280
|
const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
|
|
210
281
|
return new HashedValues(calldata, r.calldataHash);
|
|
211
282
|
}));
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
|
|
283
|
+
noteCache.finish();
|
|
284
|
+
const nonceGenerator = noteCache.getNonceGenerator();
|
|
285
|
+
result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
|
|
216
286
|
} catch (err) {
|
|
217
287
|
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
218
288
|
}
|
|
219
|
-
// According to the protocol rules,
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
const
|
|
223
|
-
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);
|
|
224
293
|
const globals = makeGlobalVariables();
|
|
225
294
|
globals.blockNumber = blockNumber;
|
|
226
295
|
globals.timestamp = this.nextBlockTimestamp;
|
|
@@ -228,7 +297,8 @@ export class TXEOracleTopLevelContext {
|
|
|
228
297
|
globals.version = this.version;
|
|
229
298
|
globals.gasFees = GasFees.empty();
|
|
230
299
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
231
|
-
const
|
|
300
|
+
const bindings = this.logger.getBindings();
|
|
301
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
|
|
232
302
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
233
303
|
const config = PublicSimulatorConfig.from({
|
|
234
304
|
skipFeeEnforcement: true,
|
|
@@ -237,7 +307,7 @@ export class TXEOracleTopLevelContext {
|
|
|
237
307
|
collectStatistics: false,
|
|
238
308
|
collectCallMetadata: true
|
|
239
309
|
});
|
|
240
|
-
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new
|
|
310
|
+
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
|
|
241
311
|
const tx = await Tx.create({
|
|
242
312
|
data: publicInputs,
|
|
243
313
|
chonkProof: ChonkProof.empty(),
|
|
@@ -258,7 +328,7 @@ export class TXEOracleTopLevelContext {
|
|
|
258
328
|
} else if (!processedTx.revertCode.isOK()) {
|
|
259
329
|
if (processedTx.revertReason) {
|
|
260
330
|
try {
|
|
261
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
331
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
262
332
|
// eslint-disable-next-line no-empty
|
|
263
333
|
} catch {}
|
|
264
334
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -280,22 +350,21 @@ export class TXEOracleTopLevelContext {
|
|
|
280
350
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
281
351
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
282
352
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
283
|
-
const
|
|
353
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
284
354
|
txEffect
|
|
285
355
|
]);
|
|
286
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
287
356
|
await this.stateMachine.handleL2Block(l2Block);
|
|
288
357
|
await forkedWorldTrees.close();
|
|
289
358
|
return executionResult.returnValues ?? [];
|
|
290
359
|
}
|
|
291
360
|
async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
|
|
292
|
-
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}`);
|
|
293
362
|
const blockNumber = await this.txeGetNextBlockNumber();
|
|
294
363
|
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
295
364
|
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
296
365
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
297
366
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
298
|
-
const anchorBlockHeader = await this.
|
|
367
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
299
368
|
const calldataHash = await computeCalldataHash(calldata);
|
|
300
369
|
const calldataHashedValues = new HashedValues(calldata, calldataHash);
|
|
301
370
|
const globals = makeGlobalVariables();
|
|
@@ -305,7 +374,8 @@ export class TXEOracleTopLevelContext {
|
|
|
305
374
|
globals.version = this.version;
|
|
306
375
|
globals.gasFees = GasFees.empty();
|
|
307
376
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
308
|
-
const
|
|
377
|
+
const bindings2 = this.logger.getBindings();
|
|
378
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
|
|
309
379
|
const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
|
|
310
380
|
const config = PublicSimulatorConfig.from({
|
|
311
381
|
skipFeeEnforcement: true,
|
|
@@ -314,23 +384,21 @@ export class TXEOracleTopLevelContext {
|
|
|
314
384
|
collectStatistics: false,
|
|
315
385
|
collectCallMetadata: true
|
|
316
386
|
});
|
|
317
|
-
const simulator = new
|
|
318
|
-
const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
|
|
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));
|
|
319
389
|
// We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
|
|
320
390
|
// kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
|
|
321
391
|
// side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
|
|
322
392
|
// unique.
|
|
323
393
|
const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
324
|
-
|
|
325
|
-
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
326
|
-
}
|
|
394
|
+
nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
|
|
327
395
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
328
396
|
// may require producing reverts.
|
|
329
397
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
330
398
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
331
399
|
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
332
400
|
const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
|
|
333
|
-
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);
|
|
334
402
|
const tx = await Tx.create({
|
|
335
403
|
data: txData,
|
|
336
404
|
chonkProof: ChonkProof.empty(),
|
|
@@ -353,7 +421,7 @@ export class TXEOracleTopLevelContext {
|
|
|
353
421
|
} else if (!processedTx.revertCode.isOK()) {
|
|
354
422
|
if (processedTx.revertReason) {
|
|
355
423
|
try {
|
|
356
|
-
await enrichPublicSimulationError(processedTx.revertReason, this.
|
|
424
|
+
await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
|
|
357
425
|
// eslint-disable-next-line no-empty
|
|
358
426
|
} catch {}
|
|
359
427
|
throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
|
|
@@ -376,25 +444,37 @@ export class TXEOracleTopLevelContext {
|
|
|
376
444
|
txEffect.txHash = new TxHash(new Fr(blockNumber));
|
|
377
445
|
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
378
446
|
await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
379
|
-
const
|
|
447
|
+
const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
|
|
380
448
|
txEffect
|
|
381
449
|
]);
|
|
382
|
-
const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
|
|
383
450
|
await this.stateMachine.handleL2Block(l2Block);
|
|
384
451
|
await forkedWorldTrees.close();
|
|
385
452
|
return returnValues ?? [];
|
|
386
453
|
}
|
|
387
|
-
async
|
|
388
|
-
const artifact = await this.
|
|
454
|
+
async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args) {
|
|
455
|
+
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
389
456
|
if (!artifact) {
|
|
390
457
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
391
458
|
}
|
|
392
|
-
|
|
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({
|
|
393
465
|
name: artifact.name,
|
|
466
|
+
to: targetContractAddress,
|
|
394
467
|
selector: functionSelector,
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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);
|
|
398
478
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
399
479
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
400
480
|
}
|
|
@@ -403,8 +483,25 @@ export class TXEOracleTopLevelContext {
|
|
|
403
483
|
selector: call.selector
|
|
404
484
|
});
|
|
405
485
|
try {
|
|
406
|
-
const
|
|
407
|
-
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)=>{
|
|
408
505
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
409
506
|
throw new ExecutionError(err.message, {
|
|
410
507
|
contractAddress: call.to,
|
|
@@ -413,10 +510,10 @@ export class TXEOracleTopLevelContext {
|
|
|
413
510
|
cause: err
|
|
414
511
|
});
|
|
415
512
|
});
|
|
416
|
-
this.logger.verbose(`Utility
|
|
513
|
+
this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
|
|
417
514
|
return witnessMapToFields(acirExecutionResult.returnWitness);
|
|
418
515
|
} catch (err) {
|
|
419
|
-
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'));
|
|
420
517
|
}
|
|
421
518
|
}
|
|
422
519
|
close() {
|
|
@@ -427,6 +524,7 @@ export class TXEOracleTopLevelContext {
|
|
|
427
524
|
];
|
|
428
525
|
}
|
|
429
526
|
async getLastBlockNumber() {
|
|
430
|
-
|
|
527
|
+
const header = await this.stateMachine.node.getBlockHeader('latest');
|
|
528
|
+
return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
431
529
|
}
|
|
432
530
|
}
|