@aztec/txe 0.0.1-commit.03f7ef2 → 0.0.1-commit.04d373f
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/ContractClassRegistry-KKNT527R.js +3 -0
- package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
- package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
- package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
- package/dest/FeeJuice-GUJ5O6GB.js +3 -0
- package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
- package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
- package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
- package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
- package/dest/SchnorrAccount-QIXE5DXA.js.map +7 -0
- package/dest/bin/check_txe_oracle_version.d.ts +2 -0
- package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
- package/dest/bin/check_txe_oracle_version.js +32 -0
- package/dest/bin/index.js +3 -30
- package/dest/bin/index.js.map +7 -0
- package/dest/chunk-BJVAAXNA.js +3 -0
- package/dest/chunk-BJVAAXNA.js.map +7 -0
- package/dest/chunk-DF6RMOC6.js +304 -0
- package/dest/chunk-DF6RMOC6.js.map +7 -0
- package/dest/chunk-PPJTNNUG.js +265 -0
- package/dest/chunk-PPJTNNUG.js.map +7 -0
- package/dest/constants.d.ts +5 -0
- package/dest/constants.d.ts.map +1 -0
- package/dest/constants.js +7 -0
- package/dest/dispatcher_pool.d.ts +67 -0
- package/dest/dispatcher_pool.d.ts.map +1 -0
- package/dest/dispatcher_pool.js +284 -0
- package/dest/index.d.ts +188 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +148 -75
- package/dest/metafile.json +38147 -0
- package/dest/msgpackr_fr_extension.d.ts +2 -0
- package/dest/msgpackr_fr_extension.d.ts.map +1 -0
- package/dest/msgpackr_fr_extension.js +21 -0
- package/dest/oracle/interfaces.d.ts +40 -28
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +18 -13
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +31 -16
- package/dest/oracle/txe_oracle_top_level_context.d.ts +49 -31
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +265 -119
- package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
- package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
- package/dest/oracle/txe_private_execution_oracle.js +15 -0
- package/dest/rpc_server.d.ts +14 -0
- package/dest/rpc_server.d.ts.map +1 -0
- package/dest/rpc_server.js +78 -0
- package/dest/rpc_translator.d.ts +144 -82
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +599 -238
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +20 -67
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +65 -182
- package/dest/state_machine/dummy_p2p_client.d.ts +28 -17
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +51 -24
- package/dest/state_machine/global_variable_builder.d.ts +9 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +10 -4
- package/dest/state_machine/index.d.ts +11 -7
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +57 -16
- package/dest/state_machine/mock_epoch_cache.d.ts +26 -8
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +49 -9
- package/dest/state_machine/synchronizer.d.ts +6 -6
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +4 -4
- package/dest/txe_oracle_version.d.ts +17 -0
- package/dest/txe_oracle_version.d.ts.map +1 -0
- package/dest/txe_oracle_version.js +14 -0
- package/dest/txe_session.d.ts +83 -19
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +291 -66
- package/dest/utils/block_creation.d.ts +4 -4
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +18 -5
- package/dest/utils/encoding.d.ts +191 -0
- package/dest/utils/encoding.d.ts.map +1 -0
- package/dest/{util → utils}/encoding.js +7 -2
- package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
- package/dest/utils/expected_failure_error.d.ts.map +1 -0
- package/dest/utils/tx_effect_creation.d.ts +2 -3
- package/dest/utils/tx_effect_creation.d.ts.map +1 -1
- package/dest/utils/tx_effect_creation.js +3 -6
- package/dest/utils/txe_account_store.d.ts +10 -0
- package/dest/utils/txe_account_store.d.ts.map +1 -0
- package/dest/{util/txe_account_data_provider.js → utils/txe_account_store.js} +1 -1
- package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
- package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
- package/dest/utils/txe_public_contract_data_source.js +48 -0
- package/dest/worker.bundle.js +3 -0
- package/dest/worker.bundle.js.map +7 -0
- package/dest/worker.d.ts +2 -0
- package/dest/worker.d.ts.map +1 -0
- package/dest/worker.js +92 -0
- package/package.json +38 -22
- package/src/bin/check_txe_oracle_version.ts +37 -0
- package/src/bin/index.ts +11 -2
- package/src/constants.ts +9 -0
- package/src/dispatcher_pool.ts +316 -0
- package/src/index.ts +166 -80
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +48 -34
- package/src/oracle/txe_oracle_public_context.ts +46 -18
- package/src/oracle/txe_oracle_top_level_context.ts +322 -169
- package/src/oracle/txe_private_execution_oracle.ts +30 -0
- package/src/rpc_server.ts +87 -0
- package/src/rpc_translator.ts +687 -326
- package/src/state_machine/archiver.ts +69 -220
- package/src/state_machine/dummy_p2p_client.ts +80 -37
- package/src/state_machine/global_variable_builder.ts +19 -4
- package/src/state_machine/index.ts +73 -16
- package/src/state_machine/mock_epoch_cache.ts +61 -14
- package/src/state_machine/synchronizer.ts +6 -6
- package/src/txe_oracle_version.ts +17 -0
- package/src/txe_session.ts +439 -132
- package/src/utils/block_creation.ts +19 -16
- package/src/{util → utils}/encoding.ts +8 -2
- package/src/utils/tx_effect_creation.ts +3 -11
- package/src/{util/txe_account_data_provider.ts → utils/txe_account_store.ts} +1 -1
- package/src/utils/txe_public_contract_data_source.ts +58 -0
- package/src/worker.ts +98 -0
- package/dest/util/encoding.d.ts +0 -720
- package/dest/util/encoding.d.ts.map +0 -1
- package/dest/util/expected_failure_error.d.ts.map +0 -1
- 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/dest/util/txe_public_contract_data_source.d.ts +0 -21
- package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
- package/dest/util/txe_public_contract_data_source.js +0 -67
- package/src/util/txe_contract_data_provider.ts +0 -36
- package/src/util/txe_public_contract_data_source.ts +0 -86
- /package/dest/{util → utils}/expected_failure_error.js +0 -0
- /package/src/{util → utils}/expected_failure_error.ts +0 -0
package/src/txe_session.ts
CHANGED
|
@@ -2,16 +2,21 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { KeyStore } from '@aztec/key-store';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
6
|
+
import { openEphemeralStore } from '@aztec/kv-store/lmdb-v2';
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
AddressStore,
|
|
9
|
+
AnchorBlockStore,
|
|
10
|
+
CapsuleService,
|
|
11
|
+
CapsuleStore,
|
|
12
|
+
ContractStore,
|
|
13
|
+
JobCoordinator,
|
|
11
14
|
NoteService,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
NoteStore,
|
|
16
|
+
PrivateEventStore,
|
|
17
|
+
RecipientTaggingStore,
|
|
18
|
+
SenderAddressBookStore,
|
|
19
|
+
SenderTaggingStore,
|
|
15
20
|
} from '@aztec/pxe/server';
|
|
16
21
|
import {
|
|
17
22
|
ExecutionNoteCache,
|
|
@@ -19,30 +24,42 @@ import {
|
|
|
19
24
|
HashedValuesCache,
|
|
20
25
|
type IPrivateExecutionOracle,
|
|
21
26
|
type IUtilityExecutionOracle,
|
|
22
|
-
|
|
27
|
+
Oracle,
|
|
23
28
|
UtilityExecutionOracle,
|
|
24
29
|
} from '@aztec/pxe/simulator';
|
|
25
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
ExecutionError,
|
|
32
|
+
WASMSimulator,
|
|
33
|
+
createSimulationError,
|
|
34
|
+
extractCallStack,
|
|
35
|
+
resolveAssertionMessageFromError,
|
|
36
|
+
toACVMWitness,
|
|
37
|
+
} from '@aztec/simulator/client';
|
|
38
|
+
import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants';
|
|
39
|
+
import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
26
40
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
27
41
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
28
|
-
import { GasSettings } from '@aztec/stdlib/gas';
|
|
42
|
+
import type { GasSettings } from '@aztec/stdlib/gas';
|
|
29
43
|
import { computeProtocolNullifier } from '@aztec/stdlib/hash';
|
|
30
44
|
import { PrivateContextInputs } from '@aztec/stdlib/kernel';
|
|
31
45
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
32
|
-
import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
|
|
46
|
+
import { CallContext, GlobalVariables, OFFCHAIN_MESSAGE_IDENTIFIER, TxContext } from '@aztec/stdlib/tx';
|
|
33
47
|
|
|
34
48
|
import { z } from 'zod';
|
|
35
49
|
|
|
50
|
+
import { DEFAULT_ADDRESS, MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY, MAX_OFFCHAIN_EFFECT_LEN } from './constants.js';
|
|
36
51
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
37
52
|
import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
|
|
38
53
|
import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
|
|
54
|
+
import { TXEPrivateExecutionOracle } from './oracle/txe_private_execution_oracle.js';
|
|
39
55
|
import { RPCTranslator } from './rpc_translator.js';
|
|
56
|
+
import { TXEArchiver } from './state_machine/archiver.js';
|
|
40
57
|
import { TXEStateMachine } from './state_machine/index.js';
|
|
41
|
-
import
|
|
42
|
-
import { TXEAccountDataProvider } from './util/txe_account_data_provider.js';
|
|
43
|
-
import { TXEContractDataProvider } from './util/txe_contract_data_provider.js';
|
|
58
|
+
import { TXE_ORACLE_VERSION_MAJOR, TXE_ORACLE_VERSION_MINOR } from './txe_oracle_version.js';
|
|
44
59
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
|
|
60
|
+
import type { ForeignCallArgs, ForeignCallResult } from './utils/encoding.js';
|
|
45
61
|
import { makeTxEffect } from './utils/tx_effect_creation.js';
|
|
62
|
+
import { TXEAccountStore } from './utils/txe_account_store.js';
|
|
46
63
|
|
|
47
64
|
/**
|
|
48
65
|
* A TXE Session can be in one of four states, which change as the test progresses and different oracles are called.
|
|
@@ -63,7 +80,6 @@ type SessionState =
|
|
|
63
80
|
| {
|
|
64
81
|
name: 'PRIVATE';
|
|
65
82
|
nextBlockGlobalVariables: GlobalVariables;
|
|
66
|
-
protocolNullifier: Fr;
|
|
67
83
|
noteCache: ExecutionNoteCache;
|
|
68
84
|
taggingIndexCache: ExecutionTaggingIndexCache;
|
|
69
85
|
}
|
|
@@ -96,13 +112,81 @@ export type TXEOracleFunctionName = Exclude<
|
|
|
96
112
|
>;
|
|
97
113
|
|
|
98
114
|
export interface TXESessionStateHandler {
|
|
115
|
+
/** Records the TXE oracle version reported by the Noir test code for diagnostics. */
|
|
116
|
+
setTxeOracleVersion(major: number, minor: number): void;
|
|
117
|
+
|
|
99
118
|
enterTopLevelState(): Promise<void>;
|
|
100
119
|
enterPublicState(contractAddress?: AztecAddress): Promise<void>;
|
|
101
|
-
enterPrivateState(
|
|
120
|
+
enterPrivateState(
|
|
121
|
+
contractAddress: AztecAddress | undefined,
|
|
122
|
+
anchorBlockNumber: BlockNumber | undefined,
|
|
123
|
+
gasSettings: GasSettings,
|
|
124
|
+
): Promise<PrivateContextInputs>;
|
|
102
125
|
enterUtilityState(contractAddress?: AztecAddress): Promise<void>;
|
|
126
|
+
|
|
127
|
+
// TODO(F-335): Exposing the job info is abstraction breakage - drop the following 2 functions.
|
|
128
|
+
cycleJob(): Promise<string>;
|
|
129
|
+
getCurrentJob(): string;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Runs an executor-style top-level call (private/public call, utility execution) with last-call tracking.
|
|
133
|
+
*/
|
|
134
|
+
withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Captures a raw offchain effect payload for consumption from test environment. Called by the `emit_offchain_effect`
|
|
138
|
+
* oracle handler whenever a contract function emits an offchain message, at any call depth.
|
|
139
|
+
*/
|
|
140
|
+
recordOffchainEffect(data: Fr[]): void;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Returns the raw offchain effect payloads emitted by the last top-level call. Each payload follows the protocol
|
|
144
|
+
* convention documented on `OFFCHAIN_MESSAGE_IDENTIFIER`, i.e. `[identifier, recipient, ...ciphertext]`. Decoding into
|
|
145
|
+
* `OffchainMessage` structs happens on the Noir side of the test helper. Marks the buffer as queried so the
|
|
146
|
+
* unqueried-messages warning doesn't fire on the next reset.
|
|
147
|
+
*/
|
|
148
|
+
getLastCallOffchainEffects(): { effects: Fr[][] };
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Returns the context of the last top-level call: its tx hash (`Fr.ZERO` if the call was tx-less) and the anchor
|
|
152
|
+
* block timestamp captured at the start of the call. Does *not* mark the buffer as queried — context reads are
|
|
153
|
+
* metadata, not effect consumption.
|
|
154
|
+
*/
|
|
155
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Session state tracking the most recently completed top-level call: the offchain effect buffer it produced, and the
|
|
160
|
+
* call's context (tx hash + anchor block timestamp). The context is refreshed on every top-level call, independently
|
|
161
|
+
* of whether the call produced offchain effects.
|
|
162
|
+
*/
|
|
163
|
+
interface LastCallState {
|
|
164
|
+
/**
|
|
165
|
+
* Raw offchain effect payloads emitted by the currently-executing (or most recently completed) top-level call. Wiped
|
|
166
|
+
* at the start of every top-level entry point, appended to on every `emit_offchain_effect` oracle invocation.
|
|
167
|
+
*/
|
|
168
|
+
offchainEffects: Fr[][];
|
|
169
|
+
/**
|
|
170
|
+
* Tracks whether the test has queried `effects` since the last reset. If a new top-level call clobbers the buffer
|
|
171
|
+
* without it being queried first, any accumulated messages are lost and we emit a warning so tests don't silently
|
|
172
|
+
* drop delivery.
|
|
173
|
+
*/
|
|
174
|
+
queried: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Tx hash of the most recently completed top-level call, or `Fr.ZERO` if the call was tx-less (context setters,
|
|
177
|
+
* utility execution). Populated by call executor handlers after execution completes.
|
|
178
|
+
*/
|
|
179
|
+
txHash: Fr;
|
|
180
|
+
/**
|
|
181
|
+
* Anchor block timestamp of the most recently completed top-level call, captured from the anchor block header that
|
|
182
|
+
* was active when the call started. Populated by call executor handlers after execution completes.
|
|
183
|
+
*/
|
|
184
|
+
anchorBlockTimestamp: bigint;
|
|
103
185
|
}
|
|
104
186
|
|
|
105
|
-
|
|
187
|
+
function emptyLastCallState(): LastCallState {
|
|
188
|
+
return { offchainEffects: [], queried: false, txHash: Fr.ZERO, anchorBlockTimestamp: 0n };
|
|
189
|
+
}
|
|
106
190
|
|
|
107
191
|
/**
|
|
108
192
|
* A `TXESession` corresponds to a Noir `#[test]` function, and handles all of its oracle calls, stores test-specific
|
|
@@ -111,85 +195,133 @@ export const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
|
|
|
111
195
|
export class TXESession implements TXESessionStateHandler {
|
|
112
196
|
private state: SessionState = { name: 'TOP_LEVEL' };
|
|
113
197
|
private authwits: Map<string, AuthWitness> = new Map();
|
|
198
|
+
private lastCallInfo: LastCallState = emptyLastCallState();
|
|
199
|
+
private txeOracleVersion: { major: number; minor: number } | undefined;
|
|
200
|
+
|
|
201
|
+
private disposed = false;
|
|
114
202
|
|
|
115
203
|
constructor(
|
|
116
204
|
private logger: Logger,
|
|
205
|
+
private sessionStore: AztecAsyncKVStore,
|
|
117
206
|
private stateMachine: TXEStateMachine,
|
|
118
207
|
private oracleHandler:
|
|
119
208
|
| IUtilityExecutionOracle
|
|
120
209
|
| IPrivateExecutionOracle
|
|
121
210
|
| IAvmExecutionOracle
|
|
122
211
|
| ITxeExecutionOracle,
|
|
123
|
-
private
|
|
124
|
-
private
|
|
212
|
+
private contractStore: ContractStore,
|
|
213
|
+
private noteStore: NoteStore,
|
|
125
214
|
private keyStore: KeyStore,
|
|
126
|
-
private
|
|
127
|
-
private
|
|
128
|
-
private
|
|
129
|
-
private
|
|
130
|
-
private
|
|
131
|
-
private
|
|
215
|
+
private addressStore: AddressStore,
|
|
216
|
+
private accountStore: TXEAccountStore,
|
|
217
|
+
private senderTaggingStore: SenderTaggingStore,
|
|
218
|
+
private recipientTaggingStore: RecipientTaggingStore,
|
|
219
|
+
private senderAddressBookStore: SenderAddressBookStore,
|
|
220
|
+
private capsuleStore: CapsuleStore,
|
|
221
|
+
private privateEventStore: PrivateEventStore,
|
|
222
|
+
private jobCoordinator: JobCoordinator,
|
|
223
|
+
private currentJobId: string,
|
|
132
224
|
private chainId: Fr,
|
|
133
225
|
private version: Fr,
|
|
134
226
|
private nextBlockTimestamp: bigint,
|
|
135
227
|
) {}
|
|
136
228
|
|
|
137
|
-
|
|
138
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Closes the per-session `txe-session` LMDB and the `NativeWorldStateService` .
|
|
231
|
+
* Called via IPC when the dispatcher detects the end of a test. Idempotent.
|
|
232
|
+
*/
|
|
233
|
+
async dispose(): Promise<void> {
|
|
234
|
+
if (this.disposed) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
this.disposed = true;
|
|
238
|
+
try {
|
|
239
|
+
await this.stateMachine.synchronizer.nativeWorldStateService.close();
|
|
240
|
+
} catch (err) {
|
|
241
|
+
this.logger.warn(`Error closing native world state during session dispose`, err);
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
await this.sessionStore.close();
|
|
245
|
+
} catch (err) {
|
|
246
|
+
this.logger.warn(`Error closing session LMDB during dispose`, err);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
139
249
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
250
|
+
static async init(contractStore: ContractStore) {
|
|
251
|
+
// Size LMDB's reader slots to the libuv pool (capped to 2 in bin/index.ts via
|
|
252
|
+
// HARDWARE_CONCURRENCY): each native LMDB read needs a libuv worker thread to run, so any
|
|
253
|
+
// slot beyond the pool size would sit idle while still consuming a semaphore + reader-table
|
|
254
|
+
// entry per session.
|
|
255
|
+
const store = await openEphemeralStore('txe-session', undefined, 2);
|
|
256
|
+
|
|
257
|
+
const addressStore = new AddressStore(store);
|
|
258
|
+
const privateEventStore = new PrivateEventStore(store);
|
|
259
|
+
const noteStore = new NoteStore(store);
|
|
260
|
+
const senderTaggingStore = new SenderTaggingStore(store);
|
|
261
|
+
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
262
|
+
const senderAddressBookStore = new SenderAddressBookStore(store);
|
|
263
|
+
const capsuleStore = new CapsuleStore(store);
|
|
147
264
|
const keyStore = new KeyStore(store);
|
|
148
|
-
const
|
|
265
|
+
const accountStore = new TXEAccountStore(store);
|
|
149
266
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
267
|
+
const jobCoordinator = new JobCoordinator(store);
|
|
268
|
+
jobCoordinator.registerStores([
|
|
269
|
+
capsuleStore,
|
|
270
|
+
senderTaggingStore,
|
|
271
|
+
recipientTaggingStore,
|
|
272
|
+
privateEventStore,
|
|
273
|
+
noteStore,
|
|
274
|
+
]);
|
|
155
275
|
|
|
156
|
-
const
|
|
276
|
+
const archiver = new TXEArchiver(store);
|
|
277
|
+
const anchorBlockStore = new AnchorBlockStore(store);
|
|
278
|
+
const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
|
|
157
279
|
|
|
158
280
|
const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
|
|
159
281
|
const version = new Fr(await stateMachine.node.getVersion());
|
|
160
282
|
const chainId = new Fr(await stateMachine.node.getChainId());
|
|
161
283
|
|
|
284
|
+
const initialJobId = jobCoordinator.beginJob();
|
|
285
|
+
|
|
286
|
+
const logger = createLogger('txe:session');
|
|
287
|
+
|
|
162
288
|
const topLevelOracleHandler = new TXEOracleTopLevelContext(
|
|
163
289
|
stateMachine,
|
|
164
|
-
|
|
165
|
-
|
|
290
|
+
contractStore,
|
|
291
|
+
noteStore,
|
|
166
292
|
keyStore,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
293
|
+
addressStore,
|
|
294
|
+
accountStore,
|
|
295
|
+
senderTaggingStore,
|
|
296
|
+
recipientTaggingStore,
|
|
297
|
+
senderAddressBookStore,
|
|
298
|
+
capsuleStore,
|
|
299
|
+
privateEventStore,
|
|
173
300
|
nextBlockTimestamp,
|
|
174
301
|
version,
|
|
175
302
|
chainId,
|
|
176
303
|
new Map(),
|
|
177
304
|
);
|
|
178
|
-
|
|
305
|
+
|
|
306
|
+
await topLevelOracleHandler.mineDeploymentNullifiers([STANDARD_AUTH_REGISTRY_ADDRESS]);
|
|
179
307
|
|
|
180
308
|
return new TXESession(
|
|
181
|
-
|
|
309
|
+
logger,
|
|
310
|
+
store,
|
|
182
311
|
stateMachine,
|
|
183
312
|
topLevelOracleHandler,
|
|
184
|
-
|
|
185
|
-
|
|
313
|
+
contractStore,
|
|
314
|
+
noteStore,
|
|
186
315
|
keyStore,
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
316
|
+
addressStore,
|
|
317
|
+
accountStore,
|
|
318
|
+
senderTaggingStore,
|
|
319
|
+
recipientTaggingStore,
|
|
320
|
+
senderAddressBookStore,
|
|
321
|
+
capsuleStore,
|
|
322
|
+
privateEventStore,
|
|
323
|
+
jobCoordinator,
|
|
324
|
+
initialJobId,
|
|
193
325
|
version,
|
|
194
326
|
chainId,
|
|
195
327
|
nextBlockTimestamp,
|
|
@@ -214,7 +346,28 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
214
346
|
return translator[validatedFunctionName](...inputs);
|
|
215
347
|
} catch (error) {
|
|
216
348
|
if (error instanceof z.ZodError) {
|
|
217
|
-
|
|
349
|
+
let versionHint: string;
|
|
350
|
+
if (!this.txeOracleVersion) {
|
|
351
|
+
versionHint =
|
|
352
|
+
' The test appears to use an older version of Aztec.nr that does not' +
|
|
353
|
+
' support test environment oracle versioning. Update Aztec.nr to a compatible version.' +
|
|
354
|
+
' See https://docs.aztec.network/errors/12';
|
|
355
|
+
} else if (this.txeOracleVersion.minor > TXE_ORACLE_VERSION_MINOR) {
|
|
356
|
+
versionHint =
|
|
357
|
+
` The test uses Aztec.nr test oracle version` +
|
|
358
|
+
` ${this.txeOracleVersion.major}.${this.txeOracleVersion.minor}, but this test environment` +
|
|
359
|
+
` only supports up to ${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}.` +
|
|
360
|
+
` Upgrade the Aztec CLI to a compatible version.` +
|
|
361
|
+
` See https://docs.aztec.network/errors/12`;
|
|
362
|
+
} else {
|
|
363
|
+
versionHint =
|
|
364
|
+
` The test's oracle version (${this.txeOracleVersion.major}.${this.txeOracleVersion.minor})` +
|
|
365
|
+
` is compatible with this test environment` +
|
|
366
|
+
` (${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}), so this oracle should be` +
|
|
367
|
+
` available. This is an unexpected error, please report it.` +
|
|
368
|
+
` See https://docs.aztec.network/errors/13`;
|
|
369
|
+
}
|
|
370
|
+
throw new Error(`Unknown oracle '${functionName}'.${versionHint}`);
|
|
218
371
|
} else if (error instanceof Error) {
|
|
219
372
|
throw new Error(
|
|
220
373
|
`Execution error while processing function ${functionName} in state ${this.state.name}: ${error.message}`,
|
|
@@ -227,6 +380,86 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
227
380
|
}
|
|
228
381
|
}
|
|
229
382
|
|
|
383
|
+
getCurrentJob(): string {
|
|
384
|
+
return this.currentJobId;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** Commits the current job and begins a new one. Returns the new job ID. */
|
|
388
|
+
async cycleJob(): Promise<string> {
|
|
389
|
+
await this.jobCoordinator.commitJob(this.currentJobId);
|
|
390
|
+
this.currentJobId = this.jobCoordinator.beginJob();
|
|
391
|
+
return this.currentJobId;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private resetLastCall(): void {
|
|
395
|
+
const notQueriedMessageCount = this.lastCallInfo.queried
|
|
396
|
+
? 0
|
|
397
|
+
: this.lastCallInfo.offchainEffects.filter(payload => payload[0]?.equals(OFFCHAIN_MESSAGE_IDENTIFIER)).length;
|
|
398
|
+
if (notQueriedMessageCount > 0) {
|
|
399
|
+
this.logger.warn(
|
|
400
|
+
`Dropping ${notQueriedMessageCount} unqueried offchain message(s) from the previous top-level call. ` +
|
|
401
|
+
`To deliver them, call \`env.offchain_messages()\` and forward the result to the recipient contract's ` +
|
|
402
|
+
`\`offchain_receive\` utility before issuing another top-level call. To intentionally discard, assign ` +
|
|
403
|
+
`to \`let _ = env.offchain_messages()\` to silence this warning.`,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
this.lastCallInfo = emptyLastCallState();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
recordOffchainEffect(data: Fr[]): void {
|
|
410
|
+
this.lastCallInfo.offchainEffects.push(data);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
private setLastCallContext(txHash: Fr, anchorBlockTimestamp: bigint): void {
|
|
414
|
+
this.lastCallInfo.txHash = txHash;
|
|
415
|
+
this.lastCallInfo.anchorBlockTimestamp = anchorBlockTimestamp;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
async withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T> {
|
|
419
|
+
this.resetLastCall();
|
|
420
|
+
// Capture the anchor *before* `work` runs: private/public executor calls mine a new block as a
|
|
421
|
+
// side effect, and that block's timestamp should not be attributed to this call's anchor.
|
|
422
|
+
const anchorBlockTimestamp = (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables
|
|
423
|
+
.timestamp;
|
|
424
|
+
const { result, txHash } = await work();
|
|
425
|
+
this.setLastCallContext(txHash ?? Fr.ZERO, anchorBlockTimestamp);
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
getLastCallOffchainEffects(): { effects: Fr[][] } {
|
|
430
|
+
this.lastCallInfo.queried = true;
|
|
431
|
+
const effects = this.lastCallInfo.offchainEffects;
|
|
432
|
+
|
|
433
|
+
if (effects.length > MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY) {
|
|
434
|
+
throw new Error(`${effects.length} offchain effects exceed max ${MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY}`);
|
|
435
|
+
}
|
|
436
|
+
if (effects.some(e => e.length > MAX_OFFCHAIN_EFFECT_LEN)) {
|
|
437
|
+
throw new Error(`Some offchain effect has length larger than max ${MAX_OFFCHAIN_EFFECT_LEN}`);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return { effects };
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint } {
|
|
444
|
+
const { txHash, anchorBlockTimestamp } = this.lastCallInfo;
|
|
445
|
+
return { txHash, anchorBlockTimestamp };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
setTxeOracleVersion(major: number, minor: number): void {
|
|
449
|
+
if (major !== TXE_ORACLE_VERSION_MAJOR) {
|
|
450
|
+
const hint =
|
|
451
|
+
major > TXE_ORACLE_VERSION_MAJOR
|
|
452
|
+
? 'The test was compiled with a newer version of Aztec.nr than your test environment supports. Upgrade your test environment to a compatible version.'
|
|
453
|
+
: 'The test was compiled with an older version of Aztec.nr than your test environment supports. Recompile the test with a compatible version of Aztec.nr.';
|
|
454
|
+
throw new Error(
|
|
455
|
+
`Incompatible test environment version: ${hint} See https://docs.aztec.network/errors/12 (expected test oracle major version ${TXE_ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
this.txeOracleVersion = { major, minor };
|
|
460
|
+
this.logger.debug(`Test compiled with test oracle version ${major}.${minor}`);
|
|
461
|
+
}
|
|
462
|
+
|
|
230
463
|
async enterTopLevelState() {
|
|
231
464
|
switch (this.state.name) {
|
|
232
465
|
case 'PRIVATE': {
|
|
@@ -249,17 +482,21 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
249
482
|
}
|
|
250
483
|
}
|
|
251
484
|
|
|
485
|
+
// Commit all staged stores from the job that was just completed, then begin a new job
|
|
486
|
+
await this.cycleJob();
|
|
487
|
+
|
|
252
488
|
this.oracleHandler = new TXEOracleTopLevelContext(
|
|
253
489
|
this.stateMachine,
|
|
254
|
-
this.
|
|
255
|
-
this.
|
|
490
|
+
this.contractStore,
|
|
491
|
+
this.noteStore,
|
|
256
492
|
this.keyStore,
|
|
257
|
-
this.
|
|
258
|
-
this.
|
|
259
|
-
this.
|
|
260
|
-
this.
|
|
261
|
-
this.
|
|
262
|
-
this.
|
|
493
|
+
this.addressStore,
|
|
494
|
+
this.accountStore,
|
|
495
|
+
this.senderTaggingStore,
|
|
496
|
+
this.recipientTaggingStore,
|
|
497
|
+
this.senderAddressBookStore,
|
|
498
|
+
this.capsuleStore,
|
|
499
|
+
this.privateEventStore,
|
|
263
500
|
this.nextBlockTimestamp,
|
|
264
501
|
this.version,
|
|
265
502
|
this.chainId,
|
|
@@ -272,26 +509,22 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
272
509
|
|
|
273
510
|
async enterPrivateState(
|
|
274
511
|
contractAddress: AztecAddress = DEFAULT_ADDRESS,
|
|
275
|
-
anchorBlockNumber
|
|
512
|
+
anchorBlockNumber: BlockNumber | undefined,
|
|
513
|
+
gasSettings: GasSettings,
|
|
276
514
|
): Promise<PrivateContextInputs> {
|
|
277
515
|
this.exitTopLevelState();
|
|
278
|
-
|
|
279
|
-
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
280
|
-
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
281
|
-
// we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
|
|
282
|
-
// be removed from the database.
|
|
283
|
-
// TODO(#12553): make the synchronizer sync here instead and remove this
|
|
284
|
-
await new NoteService(
|
|
285
|
-
this.noteDataProvider,
|
|
286
|
-
this.stateMachine.node,
|
|
287
|
-
this.stateMachine.anchorBlockDataProvider,
|
|
288
|
-
).syncNoteNullifiers(contractAddress);
|
|
516
|
+
this.resetLastCall();
|
|
289
517
|
|
|
290
518
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
291
519
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
292
520
|
// a single transaction with the effects of what was done in the test.
|
|
293
|
-
const anchorBlock = await this.stateMachine.node.
|
|
294
|
-
|
|
521
|
+
const anchorBlock = await this.stateMachine.node.getBlock(anchorBlockNumber ?? 'latest').then(b => b?.header);
|
|
522
|
+
|
|
523
|
+
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
524
|
+
contractAddress,
|
|
525
|
+
await this.keyStore.getAccounts(),
|
|
526
|
+
);
|
|
527
|
+
const latestBlock = await this.stateMachine.node.getBlock('latest').then(b => b?.header);
|
|
295
528
|
|
|
296
529
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
297
530
|
blockNumber: BlockNumber(latestBlock!.globalVariables.blockNumber + 1),
|
|
@@ -305,47 +538,60 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
305
538
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
306
539
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
307
540
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
new
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
541
|
+
const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
|
|
542
|
+
this.oracleHandler = new TXEPrivateExecutionOracle({
|
|
543
|
+
argsHash: Fr.ZERO,
|
|
544
|
+
txContext: new TxContext(this.chainId, this.version, gasSettings),
|
|
545
|
+
callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
|
|
546
|
+
anchorBlockHeader: anchorBlock!,
|
|
547
|
+
utilityExecutor,
|
|
548
|
+
authWitnesses: [],
|
|
549
|
+
capsules: [],
|
|
550
|
+
executionCache: new HashedValuesCache(),
|
|
316
551
|
noteCache,
|
|
317
552
|
taggingIndexCache,
|
|
318
|
-
this.
|
|
319
|
-
this.
|
|
320
|
-
this.keyStore,
|
|
321
|
-
this.
|
|
322
|
-
this.stateMachine.node,
|
|
323
|
-
this.
|
|
324
|
-
this.
|
|
325
|
-
this.
|
|
326
|
-
this.
|
|
327
|
-
this.
|
|
328
|
-
|
|
553
|
+
contractStore: this.contractStore,
|
|
554
|
+
noteStore: this.noteStore,
|
|
555
|
+
keyStore: this.keyStore,
|
|
556
|
+
addressStore: this.addressStore,
|
|
557
|
+
aztecNode: this.stateMachine.node,
|
|
558
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
559
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
560
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
561
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
562
|
+
privateEventStore: this.privateEventStore,
|
|
563
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
564
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
565
|
+
jobId: this.currentJobId,
|
|
566
|
+
scopes: await this.keyStore.getAccounts(),
|
|
567
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
568
|
+
simulator: new WASMSimulator(),
|
|
569
|
+
});
|
|
329
570
|
|
|
330
571
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
331
572
|
// data) in order to refer to it later, mimicking the way this object is used by the ContractFunctionSimulator. The
|
|
332
573
|
// difference resides in that the simulator has all information needed in order to run the simulation, while ours
|
|
333
574
|
// will be ongoing as the different oracles will be invoked from the Noir test, until eventually the private
|
|
334
575
|
// execution finishes.
|
|
335
|
-
this.state = { name: 'PRIVATE', nextBlockGlobalVariables,
|
|
576
|
+
this.state = { name: 'PRIVATE', nextBlockGlobalVariables, noteCache, taggingIndexCache };
|
|
336
577
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
337
578
|
|
|
338
|
-
|
|
579
|
+
// Record the *resolved* anchor's timestamp — if the caller pinned the anchor to a past block
|
|
580
|
+
// via `anchorBlockNumber`, "latest" would be the wrong anchor for offchain-message semantics.
|
|
581
|
+
this.setLastCallContext(Fr.ZERO, anchorBlock!.globalVariables.timestamp);
|
|
582
|
+
|
|
583
|
+
return (this.oracleHandler as TXEPrivateExecutionOracle).getPrivateContextInputs();
|
|
339
584
|
}
|
|
340
585
|
|
|
341
586
|
async enterPublicState(contractAddress?: AztecAddress) {
|
|
342
587
|
this.exitTopLevelState();
|
|
588
|
+
this.resetLastCall();
|
|
343
589
|
|
|
344
590
|
// The PublicContext will create a block with a single transaction in it, containing the effects of what was done in
|
|
345
591
|
// the test. The block therefore gets the *next* block number and timestamp.
|
|
346
|
-
const
|
|
592
|
+
const latestHeader = (await this.stateMachine.node.getBlockData('latest'))!.header;
|
|
347
593
|
const globalVariables = makeGlobalVariables(undefined, {
|
|
348
|
-
blockNumber: BlockNumber(
|
|
594
|
+
blockNumber: BlockNumber(latestHeader.globalVariables.blockNumber + 1),
|
|
349
595
|
timestamp: this.nextBlockTimestamp,
|
|
350
596
|
version: this.version,
|
|
351
597
|
chainId: this.chainId,
|
|
@@ -360,10 +606,16 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
360
606
|
|
|
361
607
|
this.state = { name: 'PUBLIC' };
|
|
362
608
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
609
|
+
|
|
610
|
+
// Public state is anchored at the latest block.
|
|
611
|
+
this.setLastCallContext(Fr.ZERO, latestHeader.globalVariables.timestamp);
|
|
363
612
|
}
|
|
364
613
|
|
|
365
614
|
async enterUtilityState(contractAddress: AztecAddress = DEFAULT_ADDRESS) {
|
|
366
615
|
this.exitTopLevelState();
|
|
616
|
+
this.resetLastCall();
|
|
617
|
+
|
|
618
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
367
619
|
|
|
368
620
|
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
369
621
|
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
@@ -371,32 +623,40 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
371
623
|
// be removed from the database.
|
|
372
624
|
// TODO(#12553): make the synchronizer sync here instead and remove this
|
|
373
625
|
await new NoteService(
|
|
374
|
-
this.
|
|
626
|
+
this.noteStore,
|
|
375
627
|
this.stateMachine.node,
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
const anchorBlockHeader = await this.stateMachine.anchorBlockDataProvider.getBlockHeader();
|
|
628
|
+
anchorBlockHeader,
|
|
629
|
+
this.currentJobId,
|
|
630
|
+
).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts());
|
|
380
631
|
|
|
381
|
-
this.oracleHandler = new UtilityExecutionOracle(
|
|
632
|
+
this.oracleHandler = new UtilityExecutionOracle({
|
|
382
633
|
contractAddress,
|
|
383
|
-
[],
|
|
384
|
-
[],
|
|
634
|
+
authWitnesses: [],
|
|
635
|
+
capsules: [],
|
|
385
636
|
anchorBlockHeader,
|
|
386
|
-
this.
|
|
387
|
-
this.
|
|
388
|
-
this.keyStore,
|
|
389
|
-
this.
|
|
390
|
-
this.stateMachine.node,
|
|
391
|
-
this.
|
|
392
|
-
this.
|
|
393
|
-
this.
|
|
394
|
-
this.
|
|
395
|
-
this.
|
|
396
|
-
|
|
637
|
+
contractStore: this.contractStore,
|
|
638
|
+
noteStore: this.noteStore,
|
|
639
|
+
keyStore: this.keyStore,
|
|
640
|
+
addressStore: this.addressStore,
|
|
641
|
+
aztecNode: this.stateMachine.node,
|
|
642
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
643
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
644
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
645
|
+
privateEventStore: this.privateEventStore,
|
|
646
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
647
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
648
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
649
|
+
jobId: this.currentJobId,
|
|
650
|
+
scopes: await this.keyStore.getAccounts(),
|
|
651
|
+
simulator: new WASMSimulator(),
|
|
652
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlockHeader),
|
|
653
|
+
});
|
|
397
654
|
|
|
398
655
|
this.state = { name: 'UTILITY' };
|
|
399
656
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
657
|
+
|
|
658
|
+
// Utility state anchors at whatever the anchor block store is pointing to (tracked as latest).
|
|
659
|
+
this.setLastCallContext(Fr.ZERO, anchorBlockHeader.globalVariables.timestamp);
|
|
400
660
|
}
|
|
401
661
|
|
|
402
662
|
private exitTopLevelState() {
|
|
@@ -406,8 +666,8 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
406
666
|
|
|
407
667
|
// Note that while all public and private contexts do is build a single block that we then process when exiting
|
|
408
668
|
// those, the top level context performs a large number of actions not captured in the following 'close' call. Among
|
|
409
|
-
// others, it will create empty blocks (via `
|
|
410
|
-
// `
|
|
669
|
+
// others, it will create empty blocks (via `advanceBlocksBy` and `deploy`), create blocks with transactions via
|
|
670
|
+
// `privateCallNewFlow` and `publicCallNewFlow`, add accounts to PXE via `addAccount`, etc. This is a
|
|
411
671
|
// slight inconsistency in the working model of this class, but is not too bad.
|
|
412
672
|
// TODO: it's quite unfortunate that we need to capture the authwits created to later pass them again when the top
|
|
413
673
|
// level context is re-created. This is because authwits create a temporary utility context that'd otherwise reset
|
|
@@ -428,11 +688,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
428
688
|
// We rely on the note cache to determine the effects of the transaction. This is incomplete as it doesn't private
|
|
429
689
|
// logs (other effects like enqueued public calls don't need to be considered since those are not allowed).
|
|
430
690
|
|
|
431
|
-
const txEffect = await makeTxEffect(
|
|
432
|
-
this.state.noteCache,
|
|
433
|
-
this.state.protocolNullifier,
|
|
434
|
-
this.state.nextBlockGlobalVariables.blockNumber,
|
|
435
|
-
);
|
|
691
|
+
const txEffect = await makeTxEffect(this.state.noteCache, this.state.nextBlockGlobalVariables.blockNumber);
|
|
436
692
|
|
|
437
693
|
// We build a block holding just this transaction
|
|
438
694
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
@@ -463,4 +719,55 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
463
719
|
throw new Error(`Expected to be in state 'UTILITY', but got '${this.state.name}' instead`);
|
|
464
720
|
}
|
|
465
721
|
}
|
|
722
|
+
|
|
723
|
+
private utilityExecutorForContractSync(anchorBlock: any) {
|
|
724
|
+
return async (call: FunctionCall, scopes: AztecAddress[]) => {
|
|
725
|
+
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
726
|
+
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
727
|
+
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
try {
|
|
731
|
+
const simulator = new WASMSimulator();
|
|
732
|
+
const oracle = new UtilityExecutionOracle({
|
|
733
|
+
contractAddress: call.to,
|
|
734
|
+
authWitnesses: [],
|
|
735
|
+
capsules: [],
|
|
736
|
+
anchorBlockHeader: anchorBlock!,
|
|
737
|
+
contractStore: this.contractStore,
|
|
738
|
+
noteStore: this.noteStore,
|
|
739
|
+
keyStore: this.keyStore,
|
|
740
|
+
addressStore: this.addressStore,
|
|
741
|
+
aztecNode: this.stateMachine.node,
|
|
742
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
743
|
+
senderAddressBookStore: this.senderAddressBookStore,
|
|
744
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
745
|
+
privateEventStore: this.privateEventStore,
|
|
746
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
747
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
748
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
749
|
+
jobId: this.currentJobId,
|
|
750
|
+
scopes,
|
|
751
|
+
simulator,
|
|
752
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlock),
|
|
753
|
+
});
|
|
754
|
+
await simulator
|
|
755
|
+
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
756
|
+
.catch((err: Error) => {
|
|
757
|
+
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
758
|
+
throw new ExecutionError(
|
|
759
|
+
err.message,
|
|
760
|
+
{
|
|
761
|
+
contractAddress: call.to,
|
|
762
|
+
functionSelector: call.selector,
|
|
763
|
+
},
|
|
764
|
+
extractCallStack(err, entryPointArtifact.debug),
|
|
765
|
+
{ cause: err },
|
|
766
|
+
);
|
|
767
|
+
});
|
|
768
|
+
} catch (err) {
|
|
769
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error contract data sync'));
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
}
|
|
466
773
|
}
|