@aztec/txe 0.0.1-commit.b33fc05d0 → 0.0.1-commit.b3d3157a
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-PII7Q556.js +3 -0
- package/dest/ContractClassRegistry-PII7Q556.js.map +7 -0
- package/dest/ContractInstanceRegistry-3MHLGFNZ.js +3 -0
- package/dest/ContractInstanceRegistry-3MHLGFNZ.js.map +7 -0
- package/dest/FeeJuice-TQV5AQK7.js +3 -0
- package/dest/FeeJuice-TQV5AQK7.js.map +7 -0
- package/dest/MultiCallEntrypoint-SBJUIJY7.js +3 -0
- package/dest/MultiCallEntrypoint-SBJUIJY7.js.map +7 -0
- package/dest/SchnorrAccount-MQXPIZ44.js +3 -0
- package/dest/SchnorrAccount-MQXPIZ44.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 +61 -0
- package/dest/bin/index.js +3 -30
- package/dest/bin/index.js.map +7 -0
- package/dest/bin/oracle_test_server.d.ts +3 -0
- package/dest/bin/oracle_test_server.d.ts.map +1 -0
- package/dest/bin/oracle_test_server.js +41 -0
- package/dest/chunk-2FGZE6YL.js +265 -0
- package/dest/chunk-2FGZE6YL.js.map +7 -0
- package/dest/chunk-6HRVNWJU.js +304 -0
- package/dest/chunk-6HRVNWJU.js.map +7 -0
- package/dest/chunk-BJVAAXNA.js +3 -0
- package/dest/chunk-BJVAAXNA.js.map +7 -0
- package/dest/constants.d.ts +5 -1
- package/dest/constants.d.ts.map +1 -1
- package/dest/constants.js +8 -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 +185 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +70 -190
- package/dest/metafile.json +38642 -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 +33 -8
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
- package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
- package/dest/oracle/test-resolver/fixtures.js +39 -0
- package/dest/oracle/test-resolver/index.d.ts +9 -0
- package/dest/oracle/test-resolver/index.d.ts.map +1 -0
- package/dest/oracle/test-resolver/index.js +33 -0
- package/dest/oracle/test-resolver/resolver.d.ts +34 -0
- package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
- package/dest/oracle/test-resolver/resolver.js +114 -0
- package/dest/oracle/txe_oracle_public_context.d.ts +26 -2
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +43 -1
- package/dest/oracle/txe_oracle_registry.d.ts +147 -0
- package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
- package/dest/oracle/txe_oracle_registry.js +562 -0
- package/dest/oracle/txe_oracle_top_level_context.d.ts +32 -12
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +146 -54
- package/dest/oracle/txe_oracle_version.d.ts +17 -0
- package/dest/oracle/txe_oracle_version.d.ts.map +1 -0
- package/dest/oracle/txe_oracle_version.js +14 -0
- 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 +96 -230
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +708 -616
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +4 -3
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +26 -15
- package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +16 -4
- 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 +9 -3
- package/dest/state_machine/index.d.ts +4 -2
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +17 -3
- package/dest/state_machine/mock_epoch_cache.d.ts +16 -3
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +29 -2
- package/dest/state_machine/synchronizer.d.ts +5 -5
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +4 -4
- package/dest/txe_session.d.ts +74 -12
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +171 -36
- 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/{util → utils}/txe_account_store.d.ts +1 -1
- package/dest/utils/txe_account_store.d.ts.map +1 -0
- package/dest/utils/txe_artifact_resolver.d.ts +37 -0
- package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
- package/dest/utils/txe_artifact_resolver.js +161 -0
- 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/{util → utils}/txe_public_contract_data_source.js +1 -3
- 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 -21
- package/src/bin/check_txe_oracle_version.ts +70 -0
- package/src/bin/index.ts +11 -2
- package/src/bin/oracle_test_server.ts +51 -0
- package/src/constants.ts +10 -0
- package/src/dispatcher_pool.ts +316 -0
- package/src/index.ts +97 -227
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +29 -7
- package/src/oracle/test-resolver/fixtures.ts +84 -0
- package/src/oracle/test-resolver/index.ts +45 -0
- package/src/oracle/test-resolver/resolver.ts +165 -0
- package/src/oracle/txe_oracle_public_context.ts +60 -0
- package/src/oracle/txe_oracle_registry.ts +401 -0
- package/src/oracle/txe_oracle_top_level_context.ts +177 -61
- package/src/oracle/txe_oracle_version.ts +17 -0
- package/src/oracle/txe_private_execution_oracle.ts +30 -0
- package/src/rpc_server.ts +87 -0
- package/src/rpc_translator.ts +789 -903
- package/src/state_machine/archiver.ts +38 -16
- package/src/state_machine/dummy_p2p_client.ts +31 -11
- package/src/state_machine/global_variable_builder.ts +18 -3
- package/src/state_machine/index.ts +20 -5
- package/src/state_machine/mock_epoch_cache.ts +38 -3
- package/src/state_machine/synchronizer.ts +5 -5
- package/src/txe_session.ts +281 -38
- package/src/{util → utils}/encoding.ts +8 -2
- package/src/utils/txe_artifact_resolver.ts +217 -0
- package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
- 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_store.d.ts.map +0 -1
- package/dest/util/txe_public_contract_data_source.d.ts +0 -20
- package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
- /package/dest/{util → utils}/expected_failure_error.js +0 -0
- /package/dest/{util → utils}/txe_account_store.js +0 -0
- /package/src/{util → utils}/expected_failure_error.ts +0 -0
- /package/src/{util → utils}/txe_account_store.ts +0 -0
package/src/txe_session.ts
CHANGED
|
@@ -2,11 +2,12 @@ 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
8
|
AddressStore,
|
|
9
9
|
AnchorBlockStore,
|
|
10
|
+
CapsuleService,
|
|
10
11
|
CapsuleStore,
|
|
11
12
|
ContractStore,
|
|
12
13
|
JobCoordinator,
|
|
@@ -21,10 +22,11 @@ import {
|
|
|
21
22
|
ExecutionNoteCache,
|
|
22
23
|
ExecutionTaggingIndexCache,
|
|
23
24
|
HashedValuesCache,
|
|
25
|
+
type IMiscOracle,
|
|
24
26
|
type IPrivateExecutionOracle,
|
|
25
27
|
type IUtilityExecutionOracle,
|
|
28
|
+
Option,
|
|
26
29
|
Oracle,
|
|
27
|
-
PrivateExecutionOracle,
|
|
28
30
|
UtilityExecutionOracle,
|
|
29
31
|
} from '@aztec/pxe/simulator';
|
|
30
32
|
import {
|
|
@@ -35,28 +37,32 @@ import {
|
|
|
35
37
|
resolveAssertionMessageFromError,
|
|
36
38
|
toACVMWitness,
|
|
37
39
|
} from '@aztec/simulator/client';
|
|
40
|
+
import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants';
|
|
38
41
|
import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
39
42
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
40
43
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
41
|
-
import { GasSettings } from '@aztec/stdlib/gas';
|
|
44
|
+
import type { GasSettings } from '@aztec/stdlib/gas';
|
|
42
45
|
import { computeProtocolNullifier } from '@aztec/stdlib/hash';
|
|
43
46
|
import { PrivateContextInputs } from '@aztec/stdlib/kernel';
|
|
44
47
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
45
|
-
import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
|
|
48
|
+
import { CallContext, GlobalVariables, OFFCHAIN_MESSAGE_IDENTIFIER, TxContext } from '@aztec/stdlib/tx';
|
|
46
49
|
|
|
47
50
|
import { z } from 'zod';
|
|
48
51
|
|
|
49
|
-
import { DEFAULT_ADDRESS } from './constants.js';
|
|
52
|
+
import { DEFAULT_ADDRESS, MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY, MAX_OFFCHAIN_EFFECT_LEN } from './constants.js';
|
|
50
53
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
51
54
|
import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
|
|
52
55
|
import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
|
|
56
|
+
import { TXE_ORACLE_VERSION_MAJOR, TXE_ORACLE_VERSION_MINOR } from './oracle/txe_oracle_version.js';
|
|
57
|
+
import { TXEPrivateExecutionOracle } from './oracle/txe_private_execution_oracle.js';
|
|
53
58
|
import { RPCTranslator } from './rpc_translator.js';
|
|
54
59
|
import { TXEArchiver } from './state_machine/archiver.js';
|
|
55
60
|
import { TXEStateMachine } from './state_machine/index.js';
|
|
56
|
-
import type { ForeignCallArgs, ForeignCallResult } from './util/encoding.js';
|
|
57
|
-
import { TXEAccountStore } from './util/txe_account_store.js';
|
|
58
61
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
|
|
62
|
+
import type { ForeignCallArgs, ForeignCallResult } from './utils/encoding.js';
|
|
59
63
|
import { makeTxEffect } from './utils/tx_effect_creation.js';
|
|
64
|
+
import { TXEAccountStore } from './utils/txe_account_store.js';
|
|
65
|
+
import type { TXEArtifactResolver } from './utils/txe_artifact_resolver.js';
|
|
60
66
|
|
|
61
67
|
/**
|
|
62
68
|
* A TXE Session can be in one of four states, which change as the test progresses and different oracles are called.
|
|
@@ -109,14 +115,80 @@ export type TXEOracleFunctionName = Exclude<
|
|
|
109
115
|
>;
|
|
110
116
|
|
|
111
117
|
export interface TXESessionStateHandler {
|
|
118
|
+
/** Records the TXE oracle version reported by the Noir test code for diagnostics. */
|
|
119
|
+
setTxeOracleVersion(major: number, minor: number): void;
|
|
120
|
+
|
|
112
121
|
enterTopLevelState(): Promise<void>;
|
|
113
|
-
enterPublicState(contractAddress
|
|
114
|
-
enterPrivateState(
|
|
115
|
-
|
|
122
|
+
enterPublicState(contractAddress: Option<AztecAddress>): Promise<void>;
|
|
123
|
+
enterPrivateState(
|
|
124
|
+
contractAddress: Option<AztecAddress>,
|
|
125
|
+
anchorBlockNumber: Option<BlockNumber>,
|
|
126
|
+
gasSettings: GasSettings,
|
|
127
|
+
): Promise<PrivateContextInputs>;
|
|
128
|
+
enterUtilityState(contractAddress: Option<AztecAddress>): Promise<void>;
|
|
116
129
|
|
|
117
130
|
// TODO(F-335): Exposing the job info is abstraction breakage - drop the following 2 functions.
|
|
118
131
|
cycleJob(): Promise<string>;
|
|
119
132
|
getCurrentJob(): string;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Runs an executor-style top-level call (private/public call, utility execution) with last-call tracking.
|
|
136
|
+
*/
|
|
137
|
+
withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Captures a raw offchain effect payload for consumption from test environment. Called by the `emit_offchain_effect`
|
|
141
|
+
* oracle handler whenever a contract function emits an offchain message, at any call depth.
|
|
142
|
+
*/
|
|
143
|
+
recordOffchainEffect(data: Fr[]): void;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Returns the raw offchain effect payloads emitted by the last top-level call. Each payload follows the protocol
|
|
147
|
+
* convention documented on `OFFCHAIN_MESSAGE_IDENTIFIER`, i.e. `[identifier, recipient, ...ciphertext]`. Decoding into
|
|
148
|
+
* `OffchainMessage` structs happens on the Noir side of the test helper. Marks the buffer as queried so the
|
|
149
|
+
* unqueried-messages warning doesn't fire on the next reset.
|
|
150
|
+
*/
|
|
151
|
+
getLastCallOffchainEffects(): { effects: Fr[][] };
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Returns the context of the last top-level call: its tx hash (`Fr.ZERO` if the call was tx-less) and the anchor
|
|
155
|
+
* block timestamp captured at the start of the call. Does *not* mark the buffer as queried — context reads are
|
|
156
|
+
* metadata, not effect consumption.
|
|
157
|
+
*/
|
|
158
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Session state tracking the most recently completed top-level call: the offchain effect buffer it produced, and the
|
|
163
|
+
* call's context (tx hash + anchor block timestamp). The context is refreshed on every top-level call, independently
|
|
164
|
+
* of whether the call produced offchain effects.
|
|
165
|
+
*/
|
|
166
|
+
interface LastCallState {
|
|
167
|
+
/**
|
|
168
|
+
* Raw offchain effect payloads emitted by the currently-executing (or most recently completed) top-level call. Wiped
|
|
169
|
+
* at the start of every top-level entry point, appended to on every `emit_offchain_effect` oracle invocation.
|
|
170
|
+
*/
|
|
171
|
+
offchainEffects: Fr[][];
|
|
172
|
+
/**
|
|
173
|
+
* Tracks whether the test has queried `effects` since the last reset. If a new top-level call clobbers the buffer
|
|
174
|
+
* without it being queried first, any accumulated messages are lost and we emit a warning so tests don't silently
|
|
175
|
+
* drop delivery.
|
|
176
|
+
*/
|
|
177
|
+
queried: boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Tx hash of the most recently completed top-level call, or `Fr.ZERO` if the call was tx-less (context setters,
|
|
180
|
+
* utility execution). Populated by call executor handlers after execution completes.
|
|
181
|
+
*/
|
|
182
|
+
txHash: Fr;
|
|
183
|
+
/**
|
|
184
|
+
* Anchor block timestamp of the most recently completed top-level call, captured from the anchor block header that
|
|
185
|
+
* was active when the call started. Populated by call executor handlers after execution completes.
|
|
186
|
+
*/
|
|
187
|
+
anchorBlockTimestamp: bigint;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function emptyLastCallState(): LastCallState {
|
|
191
|
+
return { offchainEffects: [], queried: false, txHash: Fr.ZERO, anchorBlockTimestamp: 0n };
|
|
120
192
|
}
|
|
121
193
|
|
|
122
194
|
/**
|
|
@@ -126,11 +198,17 @@ export interface TXESessionStateHandler {
|
|
|
126
198
|
export class TXESession implements TXESessionStateHandler {
|
|
127
199
|
private state: SessionState = { name: 'TOP_LEVEL' };
|
|
128
200
|
private authwits: Map<string, AuthWitness> = new Map();
|
|
201
|
+
private lastCallInfo: LastCallState = emptyLastCallState();
|
|
202
|
+
private txeOracleVersion: { major: number; minor: number } | undefined;
|
|
203
|
+
|
|
204
|
+
private disposed = false;
|
|
129
205
|
|
|
130
206
|
constructor(
|
|
131
207
|
private logger: Logger,
|
|
208
|
+
private sessionStore: AztecAsyncKVStore,
|
|
132
209
|
private stateMachine: TXEStateMachine,
|
|
133
210
|
private oracleHandler:
|
|
211
|
+
| IMiscOracle
|
|
134
212
|
| IUtilityExecutionOracle
|
|
135
213
|
| IPrivateExecutionOracle
|
|
136
214
|
| IAvmExecutionOracle
|
|
@@ -150,10 +228,43 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
150
228
|
private chainId: Fr,
|
|
151
229
|
private version: Fr,
|
|
152
230
|
private nextBlockTimestamp: bigint,
|
|
231
|
+
private readonly artifactResolver: TXEArtifactResolver,
|
|
232
|
+
private readonly rootPath: string,
|
|
233
|
+
private readonly packageName: string,
|
|
153
234
|
) {}
|
|
154
235
|
|
|
155
|
-
|
|
156
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Closes the per-session `txe-session` LMDB and the `NativeWorldStateService` .
|
|
238
|
+
* Called via IPC when the dispatcher detects the end of a test. Idempotent.
|
|
239
|
+
*/
|
|
240
|
+
async dispose(): Promise<void> {
|
|
241
|
+
if (this.disposed) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
this.disposed = true;
|
|
245
|
+
try {
|
|
246
|
+
await this.stateMachine.synchronizer.nativeWorldStateService.close();
|
|
247
|
+
} catch (err) {
|
|
248
|
+
this.logger.warn(`Error closing native world state during session dispose`, err);
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
await this.sessionStore.close();
|
|
252
|
+
} catch (err) {
|
|
253
|
+
this.logger.warn(`Error closing session LMDB during dispose`, err);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
static async init(
|
|
258
|
+
contractStore: ContractStore,
|
|
259
|
+
artifactResolver: TXEArtifactResolver,
|
|
260
|
+
rootPath: string,
|
|
261
|
+
packageName: string,
|
|
262
|
+
) {
|
|
263
|
+
// Size LMDB's reader slots to the libuv pool (capped to 2 in bin/index.ts via
|
|
264
|
+
// HARDWARE_CONCURRENCY): each native LMDB read needs a libuv worker thread to run, so any
|
|
265
|
+
// slot beyond the pool size would sit idle while still consuming a semaphore + reader-table
|
|
266
|
+
// entry per session.
|
|
267
|
+
const store = await openEphemeralStore('txe-session', undefined, 2);
|
|
157
268
|
|
|
158
269
|
const addressStore = new AddressStore(store);
|
|
159
270
|
const privateEventStore = new PrivateEventStore(store);
|
|
@@ -165,7 +276,6 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
165
276
|
const keyStore = new KeyStore(store);
|
|
166
277
|
const accountStore = new TXEAccountStore(store);
|
|
167
278
|
|
|
168
|
-
// Create job coordinator and register staged stores
|
|
169
279
|
const jobCoordinator = new JobCoordinator(store);
|
|
170
280
|
jobCoordinator.registerStores([
|
|
171
281
|
capsuleStore,
|
|
@@ -185,6 +295,8 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
185
295
|
|
|
186
296
|
const initialJobId = jobCoordinator.beginJob();
|
|
187
297
|
|
|
298
|
+
const logger = createLogger('txe:session');
|
|
299
|
+
|
|
188
300
|
const topLevelOracleHandler = new TXEOracleTopLevelContext(
|
|
189
301
|
stateMachine,
|
|
190
302
|
contractStore,
|
|
@@ -201,11 +313,16 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
201
313
|
version,
|
|
202
314
|
chainId,
|
|
203
315
|
new Map(),
|
|
316
|
+
artifactResolver,
|
|
317
|
+
rootPath,
|
|
318
|
+
packageName,
|
|
204
319
|
);
|
|
205
|
-
|
|
320
|
+
|
|
321
|
+
await topLevelOracleHandler.mineDeploymentNullifiers([STANDARD_AUTH_REGISTRY_ADDRESS]);
|
|
206
322
|
|
|
207
323
|
return new TXESession(
|
|
208
|
-
|
|
324
|
+
logger,
|
|
325
|
+
store,
|
|
209
326
|
stateMachine,
|
|
210
327
|
topLevelOracleHandler,
|
|
211
328
|
contractStore,
|
|
@@ -223,6 +340,9 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
223
340
|
version,
|
|
224
341
|
chainId,
|
|
225
342
|
nextBlockTimestamp,
|
|
343
|
+
artifactResolver,
|
|
344
|
+
rootPath,
|
|
345
|
+
packageName,
|
|
226
346
|
);
|
|
227
347
|
}
|
|
228
348
|
|
|
@@ -244,7 +364,28 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
244
364
|
return translator[validatedFunctionName](...inputs);
|
|
245
365
|
} catch (error) {
|
|
246
366
|
if (error instanceof z.ZodError) {
|
|
247
|
-
|
|
367
|
+
let versionHint: string;
|
|
368
|
+
if (!this.txeOracleVersion) {
|
|
369
|
+
versionHint =
|
|
370
|
+
' The test appears to use an older version of Aztec.nr that does not' +
|
|
371
|
+
' support test environment oracle versioning. Update Aztec.nr to a compatible version.' +
|
|
372
|
+
' See https://docs.aztec.network/errors/12';
|
|
373
|
+
} else if (this.txeOracleVersion.minor > TXE_ORACLE_VERSION_MINOR) {
|
|
374
|
+
versionHint =
|
|
375
|
+
` The test uses Aztec.nr test oracle version` +
|
|
376
|
+
` ${this.txeOracleVersion.major}.${this.txeOracleVersion.minor}, but this test environment` +
|
|
377
|
+
` only supports up to ${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}.` +
|
|
378
|
+
` Upgrade the Aztec CLI to a compatible version.` +
|
|
379
|
+
` See https://docs.aztec.network/errors/12`;
|
|
380
|
+
} else {
|
|
381
|
+
versionHint =
|
|
382
|
+
` The test's oracle version (${this.txeOracleVersion.major}.${this.txeOracleVersion.minor})` +
|
|
383
|
+
` is compatible with this test environment` +
|
|
384
|
+
` (${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}), so this oracle should be` +
|
|
385
|
+
` available. This is an unexpected error, please report it.` +
|
|
386
|
+
` See https://docs.aztec.network/errors/13`;
|
|
387
|
+
}
|
|
388
|
+
throw new Error(`Unknown oracle '${functionName}'.${versionHint}`);
|
|
248
389
|
} else if (error instanceof Error) {
|
|
249
390
|
throw new Error(
|
|
250
391
|
`Execution error while processing function ${functionName} in state ${this.state.name}: ${error.message}`,
|
|
@@ -268,6 +409,75 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
268
409
|
return this.currentJobId;
|
|
269
410
|
}
|
|
270
411
|
|
|
412
|
+
private resetLastCall(): void {
|
|
413
|
+
const notQueriedMessageCount = this.lastCallInfo.queried
|
|
414
|
+
? 0
|
|
415
|
+
: this.lastCallInfo.offchainEffects.filter(payload => payload[0]?.equals(OFFCHAIN_MESSAGE_IDENTIFIER)).length;
|
|
416
|
+
if (notQueriedMessageCount > 0) {
|
|
417
|
+
this.logger.warn(
|
|
418
|
+
`Dropping ${notQueriedMessageCount} unqueried offchain message(s) from the previous top-level call. ` +
|
|
419
|
+
`To deliver them, call \`env.offchain_messages()\` and forward the result to the recipient contract's ` +
|
|
420
|
+
`\`offchain_receive\` utility before issuing another top-level call. To intentionally discard, assign ` +
|
|
421
|
+
`to \`let _ = env.offchain_messages()\` to silence this warning.`,
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
this.lastCallInfo = emptyLastCallState();
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
recordOffchainEffect(data: Fr[]): void {
|
|
428
|
+
this.lastCallInfo.offchainEffects.push(data);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
private setLastCallContext(txHash: Fr, anchorBlockTimestamp: bigint): void {
|
|
432
|
+
this.lastCallInfo.txHash = txHash;
|
|
433
|
+
this.lastCallInfo.anchorBlockTimestamp = anchorBlockTimestamp;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T> {
|
|
437
|
+
this.resetLastCall();
|
|
438
|
+
// Capture the anchor *before* `work` runs: private/public executor calls mine a new block as a
|
|
439
|
+
// side effect, and that block's timestamp should not be attributed to this call's anchor.
|
|
440
|
+
const anchorBlockTimestamp = (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables
|
|
441
|
+
.timestamp;
|
|
442
|
+
const { result, txHash } = await work();
|
|
443
|
+
this.setLastCallContext(txHash ?? Fr.ZERO, anchorBlockTimestamp);
|
|
444
|
+
return result;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
getLastCallOffchainEffects(): { effects: Fr[][] } {
|
|
448
|
+
this.lastCallInfo.queried = true;
|
|
449
|
+
const effects = this.lastCallInfo.offchainEffects;
|
|
450
|
+
|
|
451
|
+
if (effects.length > MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY) {
|
|
452
|
+
throw new Error(`${effects.length} offchain effects exceed max ${MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY}`);
|
|
453
|
+
}
|
|
454
|
+
if (effects.some(e => e.length > MAX_OFFCHAIN_EFFECT_LEN)) {
|
|
455
|
+
throw new Error(`Some offchain effect has length larger than max ${MAX_OFFCHAIN_EFFECT_LEN}`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return { effects };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint } {
|
|
462
|
+
const { txHash, anchorBlockTimestamp } = this.lastCallInfo;
|
|
463
|
+
return { txHash, anchorBlockTimestamp };
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
setTxeOracleVersion(major: number, minor: number): void {
|
|
467
|
+
if (major !== TXE_ORACLE_VERSION_MAJOR) {
|
|
468
|
+
const hint =
|
|
469
|
+
major > TXE_ORACLE_VERSION_MAJOR
|
|
470
|
+
? 'The test was compiled with a newer version of Aztec.nr than your test environment supports. Upgrade your test environment to a compatible version.'
|
|
471
|
+
: '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.';
|
|
472
|
+
throw new Error(
|
|
473
|
+
`Incompatible test environment version: ${hint} See https://docs.aztec.network/errors/12 (expected test oracle major version ${TXE_ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
this.txeOracleVersion = { major, minor };
|
|
478
|
+
this.logger.debug(`Test compiled with test oracle version ${major}.${minor}`);
|
|
479
|
+
}
|
|
480
|
+
|
|
271
481
|
async enterTopLevelState() {
|
|
272
482
|
switch (this.state.name) {
|
|
273
483
|
case 'PRIVATE': {
|
|
@@ -309,6 +519,9 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
309
519
|
this.version,
|
|
310
520
|
this.chainId,
|
|
311
521
|
this.authwits,
|
|
522
|
+
this.artifactResolver,
|
|
523
|
+
this.rootPath,
|
|
524
|
+
this.packageName,
|
|
312
525
|
);
|
|
313
526
|
|
|
314
527
|
this.state = { name: 'TOP_LEVEL' };
|
|
@@ -316,21 +529,25 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
316
529
|
}
|
|
317
530
|
|
|
318
531
|
async enterPrivateState(
|
|
319
|
-
|
|
320
|
-
|
|
532
|
+
contractAddressOpt: Option<AztecAddress>,
|
|
533
|
+
anchorBlockNumberOpt: Option<BlockNumber>,
|
|
534
|
+
gasSettings: GasSettings,
|
|
321
535
|
): Promise<PrivateContextInputs> {
|
|
536
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
537
|
+
const anchorBlockNumber = anchorBlockNumberOpt?.value;
|
|
322
538
|
this.exitTopLevelState();
|
|
539
|
+
this.resetLastCall();
|
|
323
540
|
|
|
324
541
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
325
542
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
326
543
|
// a single transaction with the effects of what was done in the test.
|
|
327
|
-
const anchorBlock = await this.stateMachine.node.
|
|
544
|
+
const anchorBlock = await this.stateMachine.node.getBlock(anchorBlockNumber ?? 'latest').then(b => b?.header);
|
|
328
545
|
|
|
329
546
|
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
330
547
|
contractAddress,
|
|
331
|
-
|
|
548
|
+
await this.keyStore.getAccounts(),
|
|
332
549
|
);
|
|
333
|
-
const latestBlock = await this.stateMachine.node.
|
|
550
|
+
const latestBlock = await this.stateMachine.node.getBlock('latest').then(b => b?.header);
|
|
334
551
|
|
|
335
552
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
336
553
|
blockNumber: BlockNumber(latestBlock!.globalVariables.blockNumber + 1),
|
|
@@ -345,9 +562,9 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
345
562
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
346
563
|
|
|
347
564
|
const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
|
|
348
|
-
this.oracleHandler = new
|
|
565
|
+
this.oracleHandler = new TXEPrivateExecutionOracle({
|
|
349
566
|
argsHash: Fr.ZERO,
|
|
350
|
-
txContext: new TxContext(this.chainId, this.version,
|
|
567
|
+
txContext: new TxContext(this.chainId, this.version, gasSettings),
|
|
351
568
|
callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
|
|
352
569
|
anchorBlockHeader: anchorBlock!,
|
|
353
570
|
utilityExecutor,
|
|
@@ -364,12 +581,14 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
364
581
|
senderTaggingStore: this.senderTaggingStore,
|
|
365
582
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
366
583
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
367
|
-
|
|
584
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
368
585
|
privateEventStore: this.privateEventStore,
|
|
369
586
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
587
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
370
588
|
jobId: this.currentJobId,
|
|
371
|
-
scopes:
|
|
589
|
+
scopes: await this.keyStore.getAccounts(),
|
|
372
590
|
messageContextService: this.stateMachine.messageContextService,
|
|
591
|
+
simulator: new WASMSimulator(),
|
|
373
592
|
});
|
|
374
593
|
|
|
375
594
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
@@ -380,35 +599,47 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
380
599
|
this.state = { name: 'PRIVATE', nextBlockGlobalVariables, noteCache, taggingIndexCache };
|
|
381
600
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
382
601
|
|
|
383
|
-
|
|
602
|
+
// Record the *resolved* anchor's timestamp — if the caller pinned the anchor to a past block
|
|
603
|
+
// via `anchorBlockNumber`, "latest" would be the wrong anchor for offchain-message semantics.
|
|
604
|
+
this.setLastCallContext(Fr.ZERO, anchorBlock!.globalVariables.timestamp);
|
|
605
|
+
|
|
606
|
+
return (this.oracleHandler as TXEPrivateExecutionOracle).getPrivateContextInputs();
|
|
384
607
|
}
|
|
385
608
|
|
|
386
|
-
async enterPublicState(
|
|
609
|
+
async enterPublicState(contractAddressOpt: Option<AztecAddress>) {
|
|
610
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
387
611
|
this.exitTopLevelState();
|
|
612
|
+
this.resetLastCall();
|
|
388
613
|
|
|
389
614
|
// The PublicContext will create a block with a single transaction in it, containing the effects of what was done in
|
|
390
615
|
// the test. The block therefore gets the *next* block number and timestamp.
|
|
391
|
-
const
|
|
616
|
+
const latestHeader = (await this.stateMachine.node.getBlockData('latest'))!.header;
|
|
392
617
|
const globalVariables = makeGlobalVariables(undefined, {
|
|
393
|
-
blockNumber: BlockNumber(
|
|
618
|
+
blockNumber: BlockNumber(latestHeader.globalVariables.blockNumber + 1),
|
|
394
619
|
timestamp: this.nextBlockTimestamp,
|
|
395
620
|
version: this.version,
|
|
396
621
|
chainId: this.chainId,
|
|
397
622
|
});
|
|
398
623
|
|
|
399
624
|
this.oracleHandler = new TXEOraclePublicContext(
|
|
400
|
-
contractAddress
|
|
625
|
+
contractAddress,
|
|
401
626
|
await this.stateMachine.synchronizer.nativeWorldStateService.fork(),
|
|
402
627
|
getSingleTxBlockRequestHash(globalVariables.blockNumber),
|
|
403
628
|
globalVariables,
|
|
629
|
+
this.contractStore,
|
|
404
630
|
);
|
|
405
631
|
|
|
406
632
|
this.state = { name: 'PUBLIC' };
|
|
407
633
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
634
|
+
|
|
635
|
+
// Public state is anchored at the latest block.
|
|
636
|
+
this.setLastCallContext(Fr.ZERO, latestHeader.globalVariables.timestamp);
|
|
408
637
|
}
|
|
409
638
|
|
|
410
|
-
async enterUtilityState(
|
|
639
|
+
async enterUtilityState(contractAddressOpt: Option<AztecAddress>) {
|
|
640
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
411
641
|
this.exitTopLevelState();
|
|
642
|
+
this.resetLastCall();
|
|
412
643
|
|
|
413
644
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
414
645
|
|
|
@@ -422,7 +653,7 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
422
653
|
this.stateMachine.node,
|
|
423
654
|
anchorBlockHeader,
|
|
424
655
|
this.currentJobId,
|
|
425
|
-
).syncNoteNullifiers(contractAddress,
|
|
656
|
+
).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts());
|
|
426
657
|
|
|
427
658
|
this.oracleHandler = new UtilityExecutionOracle({
|
|
428
659
|
contractAddress,
|
|
@@ -436,15 +667,22 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
436
667
|
aztecNode: this.stateMachine.node,
|
|
437
668
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
438
669
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
439
|
-
|
|
670
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
440
671
|
privateEventStore: this.privateEventStore,
|
|
441
672
|
messageContextService: this.stateMachine.messageContextService,
|
|
673
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
674
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
442
675
|
jobId: this.currentJobId,
|
|
443
|
-
scopes:
|
|
676
|
+
scopes: await this.keyStore.getAccounts(),
|
|
677
|
+
simulator: new WASMSimulator(),
|
|
678
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlockHeader),
|
|
444
679
|
});
|
|
445
680
|
|
|
446
681
|
this.state = { name: 'UTILITY' };
|
|
447
682
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
683
|
+
|
|
684
|
+
// Utility state anchors at whatever the anchor block store is pointing to (tracked as latest).
|
|
685
|
+
this.setLastCallContext(Fr.ZERO, anchorBlockHeader.globalVariables.timestamp);
|
|
448
686
|
}
|
|
449
687
|
|
|
450
688
|
private exitTopLevelState() {
|
|
@@ -509,13 +747,14 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
509
747
|
}
|
|
510
748
|
|
|
511
749
|
private utilityExecutorForContractSync(anchorBlock: any) {
|
|
512
|
-
return async (call: FunctionCall, scopes:
|
|
750
|
+
return async (call: FunctionCall, scopes: AztecAddress[]) => {
|
|
513
751
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
514
752
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
515
753
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
516
754
|
}
|
|
517
755
|
|
|
518
756
|
try {
|
|
757
|
+
const simulator = new WASMSimulator();
|
|
519
758
|
const oracle = new UtilityExecutionOracle({
|
|
520
759
|
contractAddress: call.to,
|
|
521
760
|
authWitnesses: [],
|
|
@@ -528,13 +767,17 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
528
767
|
aztecNode: this.stateMachine.node,
|
|
529
768
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
530
769
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
531
|
-
|
|
770
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
532
771
|
privateEventStore: this.privateEventStore,
|
|
533
772
|
messageContextService: this.stateMachine.messageContextService,
|
|
773
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
774
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
534
775
|
jobId: this.currentJobId,
|
|
535
776
|
scopes,
|
|
777
|
+
simulator,
|
|
778
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlock),
|
|
536
779
|
});
|
|
537
|
-
await
|
|
780
|
+
await simulator
|
|
538
781
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
539
782
|
.catch((err: Error) => {
|
|
540
783
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
@@ -3,6 +3,7 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import { hexToBuffer } from '@aztec/foundation/string';
|
|
4
4
|
import { type ContractArtifact, ContractArtifactSchema } from '@aztec/stdlib/abi';
|
|
5
5
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
6
|
+
import { BlockHash } from '@aztec/stdlib/block';
|
|
6
7
|
import { type ContractInstanceWithAddress, ContractInstanceWithAddressSchema } from '@aztec/stdlib/contract';
|
|
7
8
|
|
|
8
9
|
import { z } from 'zod';
|
|
@@ -25,6 +26,10 @@ export function addressFromSingle(obj: ForeignCallSingle) {
|
|
|
25
26
|
return new AztecAddress(fromSingle(obj));
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
export function blockHashFromSingle(obj: ForeignCallSingle) {
|
|
30
|
+
return new BlockHash(fromSingle(obj));
|
|
31
|
+
}
|
|
32
|
+
|
|
28
33
|
export function fromArray(obj: ForeignCallArray) {
|
|
29
34
|
return obj.map(str => Fr.fromBuffer(hexToBuffer(str)));
|
|
30
35
|
}
|
|
@@ -142,9 +147,10 @@ export function arrayOfArraysToBoundedVecOfArrays(
|
|
|
142
147
|
|
|
143
148
|
const numFieldsToPad = maxLen * nestedArrayLength - flattenedStorage.length;
|
|
144
149
|
|
|
145
|
-
|
|
150
|
+
// Pad with hex-encoded zeros so the result is uniformly `ForeignCallSingle` (string); raw Fr
|
|
151
|
+
// instances would JSON-serialize as `{ asBigInt: "0" }` and nargo would reject the response.
|
|
152
|
+
const flattenedStorageWithPadding = flattenedStorage.concat(toArray(Array(numFieldsToPad).fill(new Fr(0))));
|
|
146
153
|
|
|
147
|
-
// At last we get the actual length of the BoundedVec and return the values.
|
|
148
154
|
const len = toSingle(new Fr(bVecStorage.length));
|
|
149
155
|
return [flattenedStorageWithPadding, len];
|
|
150
156
|
}
|