@aztec/txe 0.0.1-commit.343b43af6 → 0.0.1-commit.350e0a4d
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/AuthRegistry-2RDAZOGB.js +3 -0
- package/dest/AuthRegistry-2RDAZOGB.js.map +7 -0
- package/dest/ContractClassRegistry-L5F3G33N.js +3 -0
- package/dest/ContractClassRegistry-L5F3G33N.js.map +7 -0
- package/dest/ContractInstanceRegistry-IJOBAWAC.js +3 -0
- package/dest/ContractInstanceRegistry-IJOBAWAC.js.map +7 -0
- package/dest/FeeJuice-J3XDQPFS.js +3 -0
- package/dest/FeeJuice-J3XDQPFS.js.map +7 -0
- package/dest/HandshakeRegistry-QGWZJYVS.js +3 -0
- package/dest/HandshakeRegistry-QGWZJYVS.js.map +7 -0
- package/dest/MultiCallEntrypoint-WZHPRFJ6.js +3 -0
- package/dest/MultiCallEntrypoint-WZHPRFJ6.js.map +7 -0
- package/dest/SchnorrAccount-II4XD6MI.js +3 -0
- package/dest/SchnorrAccount-II4XD6MI.js.map +7 -0
- package/dest/SchnorrInitializerlessAccount-FXIOXUQQ.js +3 -0
- package/dest/SchnorrInitializerlessAccount-FXIOXUQQ.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-BJVAAXNA.js +3 -0
- package/dest/chunk-BJVAAXNA.js.map +7 -0
- package/dest/chunk-OMH3BDML.js +304 -0
- package/dest/chunk-OMH3BDML.js.map +7 -0
- package/dest/chunk-R3ZWQEFL.js +260 -0
- package/dest/chunk-R3ZWQEFL.js.map +7 -0
- package/dest/constants.d.ts +5 -1
- package/dest/constants.d.ts.map +1 -1
- package/dest/constants.js +9 -1
- package/dest/dispatcher_pool.d.ts +67 -0
- package/dest/dispatcher_pool.d.ts.map +1 -0
- package/dest/dispatcher_pool.js +286 -0
- package/dest/index.d.ts +51 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +72 -190
- package/dest/metafile.json +38140 -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 +38 -8
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/test-resolver/default_fixtures.d.ts +9 -0
- package/dest/oracle/test-resolver/default_fixtures.d.ts.map +1 -0
- package/dest/oracle/test-resolver/default_fixtures.js +207 -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 +32 -0
- package/dest/oracle/test-resolver/resolver.d.ts +48 -0
- package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
- package/dest/oracle/test-resolver/resolver.js +181 -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 +49 -1
- package/dest/oracle/txe_oracle_registry.d.ts +169 -0
- package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
- package/dest/oracle/txe_oracle_registry.js +745 -0
- package/dest/oracle/txe_oracle_top_level_context.d.ts +43 -16
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +233 -86
- 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 +112 -227
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +769 -607
- 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 +24 -14
- package/dest/state_machine/dummy_p2p_client.d.ts +16 -7
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +25 -4
- package/dest/state_machine/global_variable_builder.d.ts +10 -6
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +8 -5
- package/dest/state_machine/index.d.ts +11 -5
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +50 -10
- 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 +9 -6
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +10 -6
- package/dest/txe_session.d.ts +89 -19
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +308 -60
- package/dest/utils/block_creation.d.ts +2 -2
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +2 -2
- package/dest/utils/encoding.d.ts +192 -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 +1 -1
- package/dest/utils/tx_effect_creation.d.ts.map +1 -1
- package/dest/utils/tx_effect_creation.js +0 -1
- 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 +8 -7
- 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 +11 -1
- package/src/dispatcher_pool.ts +317 -0
- package/src/index.ts +99 -227
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +35 -7
- package/src/oracle/test-resolver/default_fixtures.ts +282 -0
- package/src/oracle/test-resolver/index.ts +44 -0
- package/src/oracle/test-resolver/resolver.ts +245 -0
- package/src/oracle/txe_oracle_public_context.ts +62 -0
- package/src/oracle/txe_oracle_registry.ts +536 -0
- package/src/oracle/txe_oracle_top_level_context.ts +307 -98
- 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 +858 -866
- package/src/state_machine/archiver.ts +37 -16
- package/src/state_machine/dummy_p2p_client.ts +44 -11
- package/src/state_machine/global_variable_builder.ts +12 -11
- package/src/state_machine/index.ts +63 -28
- package/src/state_machine/mock_epoch_cache.ts +38 -3
- package/src/state_machine/synchronizer.ts +13 -7
- package/src/txe_session.ts +539 -74
- package/src/utils/block_creation.ts +2 -1
- package/src/{util → utils}/encoding.ts +8 -2
- package/src/utils/tx_effect_creation.ts +0 -2
- package/src/utils/txe_artifact_resolver.ts +217 -0
- package/src/{util → utils}/txe_public_contract_data_source.ts +6 -6
- 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,30 +2,39 @@ 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
|
+
AnchoredContractData,
|
|
11
|
+
CapsuleService,
|
|
10
12
|
CapsuleStore,
|
|
11
13
|
ContractStore,
|
|
14
|
+
FactService,
|
|
15
|
+
FactStore,
|
|
12
16
|
JobCoordinator,
|
|
13
17
|
NoteService,
|
|
14
18
|
NoteStore,
|
|
15
19
|
PrivateEventStore,
|
|
16
20
|
RecipientTaggingStore,
|
|
17
|
-
SenderAddressBookStore,
|
|
18
21
|
SenderTaggingStore,
|
|
22
|
+
TaggingSecretSourcesStore,
|
|
23
|
+
type TaggingSecretStrategy,
|
|
24
|
+
composeHooks,
|
|
19
25
|
} from '@aztec/pxe/server';
|
|
20
26
|
import {
|
|
21
27
|
ExecutionNoteCache,
|
|
22
28
|
ExecutionTaggingIndexCache,
|
|
23
29
|
HashedValuesCache,
|
|
30
|
+
type IMiscOracle,
|
|
24
31
|
type IPrivateExecutionOracle,
|
|
25
32
|
type IUtilityExecutionOracle,
|
|
26
|
-
|
|
27
|
-
|
|
33
|
+
LEGACY_ORACLE_REGISTRY,
|
|
34
|
+
Option,
|
|
35
|
+
TransientArrayService,
|
|
28
36
|
UtilityExecutionOracle,
|
|
37
|
+
buildACIRCallback,
|
|
29
38
|
} from '@aztec/pxe/simulator';
|
|
30
39
|
import {
|
|
31
40
|
ExecutionError,
|
|
@@ -35,28 +44,33 @@ import {
|
|
|
35
44
|
resolveAssertionMessageFromError,
|
|
36
45
|
toACVMWitness,
|
|
37
46
|
} from '@aztec/simulator/client';
|
|
38
|
-
import {
|
|
47
|
+
import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants';
|
|
48
|
+
import { EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
39
49
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
40
50
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
41
|
-
import { GasSettings } from '@aztec/stdlib/gas';
|
|
51
|
+
import type { GasSettings } from '@aztec/stdlib/gas';
|
|
42
52
|
import { computeProtocolNullifier } from '@aztec/stdlib/hash';
|
|
43
53
|
import { PrivateContextInputs } from '@aztec/stdlib/kernel';
|
|
44
54
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
45
|
-
import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
|
|
55
|
+
import { CallContext, GlobalVariables, OFFCHAIN_MESSAGE_IDENTIFIER, TxContext } from '@aztec/stdlib/tx';
|
|
46
56
|
|
|
47
57
|
import { z } from 'zod';
|
|
48
58
|
|
|
49
|
-
import { DEFAULT_ADDRESS } from './constants.js';
|
|
59
|
+
import { DEFAULT_ADDRESS, MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY, MAX_OFFCHAIN_EFFECT_LEN } from './constants.js';
|
|
50
60
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
51
61
|
import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
|
|
62
|
+
import { callTxeLegacyHandler } from './oracle/txe_oracle_registry.js';
|
|
52
63
|
import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
|
|
53
|
-
import {
|
|
64
|
+
import { TXE_ORACLE_VERSION_MAJOR, TXE_ORACLE_VERSION_MINOR } from './oracle/txe_oracle_version.js';
|
|
65
|
+
import { TXEPrivateExecutionOracle } from './oracle/txe_private_execution_oracle.js';
|
|
66
|
+
import { RPCTranslator, UnavailableOracleError } from './rpc_translator.js';
|
|
54
67
|
import { TXEArchiver } from './state_machine/archiver.js';
|
|
55
68
|
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
69
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
|
|
70
|
+
import type { ForeignCallArgs, ForeignCallResult } from './utils/encoding.js';
|
|
59
71
|
import { makeTxEffect } from './utils/tx_effect_creation.js';
|
|
72
|
+
import { TXEAccountStore } from './utils/txe_account_store.js';
|
|
73
|
+
import type { TXEArtifactResolver } from './utils/txe_artifact_resolver.js';
|
|
60
74
|
|
|
61
75
|
/**
|
|
62
76
|
* A TXE Session can be in one of four states, which change as the test progresses and different oracles are called.
|
|
@@ -109,14 +123,111 @@ export type TXEOracleFunctionName = Exclude<
|
|
|
109
123
|
>;
|
|
110
124
|
|
|
111
125
|
export interface TXESessionStateHandler {
|
|
126
|
+
/** Records the TXE oracle version reported by the Noir test code for diagnostics. */
|
|
127
|
+
setTxeOracleVersion(major: number, minor: number): void;
|
|
128
|
+
|
|
112
129
|
enterTopLevelState(): Promise<void>;
|
|
113
|
-
enterPublicState(contractAddress
|
|
114
|
-
enterPrivateState(
|
|
115
|
-
|
|
130
|
+
enterPublicState(contractAddress: Option<AztecAddress>): Promise<void>;
|
|
131
|
+
enterPrivateState(
|
|
132
|
+
contractAddress: Option<AztecAddress>,
|
|
133
|
+
anchorBlockNumber: Option<BlockNumber>,
|
|
134
|
+
gasSettings: GasSettings,
|
|
135
|
+
): Promise<PrivateContextInputs>;
|
|
136
|
+
enterUtilityState(contractAddress: Option<AztecAddress>): Promise<void>;
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Executes a top-level private call: runs the private function, drains its offchain effects into the session buffer,
|
|
140
|
+
* commits the job, and (for non-static calls) tags the result with the mined tx hash.
|
|
141
|
+
*/
|
|
142
|
+
executePrivateCall(
|
|
143
|
+
from: Option<AztecAddress>,
|
|
144
|
+
targetContractAddress: AztecAddress,
|
|
145
|
+
functionSelector: FunctionSelector,
|
|
146
|
+
args: Fr[],
|
|
147
|
+
argsHash: Fr,
|
|
148
|
+
isStaticCall: boolean,
|
|
149
|
+
additionalScopes: AztecAddress[],
|
|
150
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
151
|
+
gasSettings: GasSettings,
|
|
152
|
+
): Promise<Fr[]>;
|
|
153
|
+
|
|
154
|
+
/** Executes a top-level utility function and commits the job. */
|
|
155
|
+
executeUtilityFunction(
|
|
156
|
+
from: Option<AztecAddress>,
|
|
157
|
+
targetContractAddress: AztecAddress,
|
|
158
|
+
functionSelector: FunctionSelector,
|
|
159
|
+
args: Fr[],
|
|
160
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
161
|
+
): Promise<Fr[]>;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Executes a top-level public call, commits the job, and (for non-static calls) tags the result with the mined tx
|
|
165
|
+
* hash.
|
|
166
|
+
*/
|
|
167
|
+
executePublicCall(
|
|
168
|
+
from: Option<AztecAddress>,
|
|
169
|
+
targetContractAddress: AztecAddress,
|
|
170
|
+
calldata: Fr[],
|
|
171
|
+
isStaticCall: boolean,
|
|
172
|
+
gasSettings: GasSettings,
|
|
173
|
+
): Promise<Fr[]>;
|
|
174
|
+
|
|
175
|
+
/** Syncs the target contract and returns the private events it emitted matching the given selector and scope. */
|
|
176
|
+
getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress): Promise<Fr[][]>;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Captures a raw offchain effect payload for consumption from test environment. Called by the `emit_offchain_effect`
|
|
180
|
+
* oracle handler whenever a contract function emits an offchain message, at any call depth.
|
|
181
|
+
*/
|
|
182
|
+
recordOffchainEffect(data: Fr[]): void;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Returns the raw offchain effect payloads emitted by the last top-level call. Each payload follows the protocol
|
|
186
|
+
* convention documented on `OFFCHAIN_MESSAGE_IDENTIFIER`, i.e. `[identifier, recipient, ...ciphertext]`. Decoding into
|
|
187
|
+
* `OffchainMessage` structs happens on the Noir side of the test helper. Marks the buffer as queried so the
|
|
188
|
+
* unqueried-messages warning doesn't fire on the next reset.
|
|
189
|
+
*/
|
|
190
|
+
getLastCallOffchainEffects(): { effects: Fr[][] };
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Returns the context of the last top-level call: its tx hash (`Fr.ZERO` if the call was tx-less) and the anchor
|
|
194
|
+
* block timestamp captured at the start of the call. Does *not* mark the buffer as queried — context reads are
|
|
195
|
+
* metadata, not effect consumption.
|
|
196
|
+
*/
|
|
197
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Session state tracking the most recently completed top-level call: the offchain effect buffer it produced, and the
|
|
202
|
+
* call's context (tx hash + anchor block timestamp). The context is refreshed on every top-level call, independently
|
|
203
|
+
* of whether the call produced offchain effects.
|
|
204
|
+
*/
|
|
205
|
+
interface LastCallState {
|
|
206
|
+
/**
|
|
207
|
+
* Raw offchain effect payloads emitted by the currently-executing (or most recently completed) top-level call. Wiped
|
|
208
|
+
* at the start of every top-level entry point, appended to on every `emit_offchain_effect` oracle invocation.
|
|
209
|
+
*/
|
|
210
|
+
offchainEffects: Fr[][];
|
|
211
|
+
/**
|
|
212
|
+
* Tracks whether the test has queried `effects` since the last reset. If a new top-level call clobbers the buffer
|
|
213
|
+
* without it being queried first, any accumulated messages are lost and we emit a warning so tests don't silently
|
|
214
|
+
* drop delivery.
|
|
215
|
+
*/
|
|
216
|
+
queried: boolean;
|
|
217
|
+
/**
|
|
218
|
+
* Tx hash of the most recently completed top-level call, or `Fr.ZERO` if the call was tx-less (context setters,
|
|
219
|
+
* utility execution). Populated by call executor handlers after execution completes.
|
|
220
|
+
*/
|
|
221
|
+
txHash: Fr;
|
|
222
|
+
/**
|
|
223
|
+
* Anchor block timestamp of the most recently completed top-level call, captured from the anchor block header that
|
|
224
|
+
* was active when the call started. Populated by call executor handlers after execution completes.
|
|
225
|
+
*/
|
|
226
|
+
anchorBlockTimestamp: bigint;
|
|
227
|
+
}
|
|
116
228
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
getCurrentJob(): string;
|
|
229
|
+
function emptyLastCallState(): LastCallState {
|
|
230
|
+
return { offchainEffects: [], queried: false, txHash: Fr.ZERO, anchorBlockTimestamp: 0n };
|
|
120
231
|
}
|
|
121
232
|
|
|
122
233
|
/**
|
|
@@ -126,11 +237,18 @@ export interface TXESessionStateHandler {
|
|
|
126
237
|
export class TXESession implements TXESessionStateHandler {
|
|
127
238
|
private state: SessionState = { name: 'TOP_LEVEL' };
|
|
128
239
|
private authwits: Map<string, AuthWitness> = new Map();
|
|
240
|
+
private taggingSecretStrategy: TaggingSecretStrategy | undefined = undefined;
|
|
241
|
+
private lastCallInfo: LastCallState = emptyLastCallState();
|
|
242
|
+
private txeOracleVersion: { major: number; minor: number } | undefined;
|
|
243
|
+
|
|
244
|
+
private disposed = false;
|
|
129
245
|
|
|
130
246
|
constructor(
|
|
131
247
|
private logger: Logger,
|
|
248
|
+
private sessionStore: AztecAsyncKVStore,
|
|
132
249
|
private stateMachine: TXEStateMachine,
|
|
133
250
|
private oracleHandler:
|
|
251
|
+
| IMiscOracle
|
|
134
252
|
| IUtilityExecutionOracle
|
|
135
253
|
| IPrivateExecutionOracle
|
|
136
254
|
| IAvmExecutionOracle
|
|
@@ -142,33 +260,68 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
142
260
|
private accountStore: TXEAccountStore,
|
|
143
261
|
private senderTaggingStore: SenderTaggingStore,
|
|
144
262
|
private recipientTaggingStore: RecipientTaggingStore,
|
|
145
|
-
private
|
|
263
|
+
private taggingSecretSourcesStore: TaggingSecretSourcesStore,
|
|
146
264
|
private capsuleStore: CapsuleStore,
|
|
265
|
+
private factStore: FactStore,
|
|
147
266
|
private privateEventStore: PrivateEventStore,
|
|
148
267
|
private jobCoordinator: JobCoordinator,
|
|
149
268
|
private currentJobId: string,
|
|
150
269
|
private chainId: Fr,
|
|
151
270
|
private version: Fr,
|
|
152
271
|
private nextBlockTimestamp: bigint,
|
|
272
|
+
private readonly artifactResolver: TXEArtifactResolver,
|
|
273
|
+
private readonly rootPath: string,
|
|
274
|
+
private readonly packageName: string,
|
|
153
275
|
) {}
|
|
154
276
|
|
|
155
|
-
|
|
156
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Closes the per-session `txe-session` LMDB and the `NativeWorldStateService` .
|
|
279
|
+
* Called via IPC when the dispatcher detects the end of a test. Idempotent.
|
|
280
|
+
*/
|
|
281
|
+
async dispose(): Promise<void> {
|
|
282
|
+
if (this.disposed) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
this.disposed = true;
|
|
286
|
+
try {
|
|
287
|
+
await this.stateMachine.synchronizer.nativeWorldStateService.close();
|
|
288
|
+
} catch (err) {
|
|
289
|
+
this.logger.warn(`Error closing native world state during session dispose`, err);
|
|
290
|
+
}
|
|
291
|
+
try {
|
|
292
|
+
await this.sessionStore.close();
|
|
293
|
+
} catch (err) {
|
|
294
|
+
this.logger.warn(`Error closing session LMDB during dispose`, err);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
static async init(
|
|
299
|
+
contractStore: ContractStore,
|
|
300
|
+
artifactResolver: TXEArtifactResolver,
|
|
301
|
+
rootPath: string,
|
|
302
|
+
packageName: string,
|
|
303
|
+
) {
|
|
304
|
+
// Size LMDB's reader slots to the libuv pool (capped to 2 in bin/index.ts via
|
|
305
|
+
// HARDWARE_CONCURRENCY): each native LMDB read needs a libuv worker thread to run, so any
|
|
306
|
+
// slot beyond the pool size would sit idle while still consuming a semaphore + reader-table
|
|
307
|
+
// entry per session.
|
|
308
|
+
const store = await openEphemeralStore('txe-session', undefined, 2);
|
|
157
309
|
|
|
158
310
|
const addressStore = new AddressStore(store);
|
|
159
311
|
const privateEventStore = new PrivateEventStore(store);
|
|
160
312
|
const noteStore = new NoteStore(store);
|
|
161
313
|
const senderTaggingStore = new SenderTaggingStore(store);
|
|
162
314
|
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
163
|
-
const
|
|
315
|
+
const taggingSecretSourcesStore = new TaggingSecretSourcesStore(store);
|
|
164
316
|
const capsuleStore = new CapsuleStore(store);
|
|
317
|
+
const factStore = new FactStore(store);
|
|
165
318
|
const keyStore = new KeyStore(store);
|
|
166
319
|
const accountStore = new TXEAccountStore(store);
|
|
167
320
|
|
|
168
|
-
// Create job coordinator and register staged stores
|
|
169
321
|
const jobCoordinator = new JobCoordinator(store);
|
|
170
322
|
jobCoordinator.registerStores([
|
|
171
323
|
capsuleStore,
|
|
324
|
+
factStore,
|
|
172
325
|
senderTaggingStore,
|
|
173
326
|
recipientTaggingStore,
|
|
174
327
|
privateEventStore,
|
|
@@ -185,6 +338,8 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
185
338
|
|
|
186
339
|
const initialJobId = jobCoordinator.beginJob();
|
|
187
340
|
|
|
341
|
+
const logger = createLogger('txe:session');
|
|
342
|
+
|
|
188
343
|
const topLevelOracleHandler = new TXEOracleTopLevelContext(
|
|
189
344
|
stateMachine,
|
|
190
345
|
contractStore,
|
|
@@ -194,18 +349,25 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
194
349
|
accountStore,
|
|
195
350
|
senderTaggingStore,
|
|
196
351
|
recipientTaggingStore,
|
|
197
|
-
|
|
352
|
+
taggingSecretSourcesStore,
|
|
198
353
|
capsuleStore,
|
|
354
|
+
factStore,
|
|
199
355
|
privateEventStore,
|
|
200
356
|
nextBlockTimestamp,
|
|
201
357
|
version,
|
|
202
358
|
chainId,
|
|
203
359
|
new Map(),
|
|
360
|
+
undefined,
|
|
361
|
+
artifactResolver,
|
|
362
|
+
rootPath,
|
|
363
|
+
packageName,
|
|
204
364
|
);
|
|
205
|
-
|
|
365
|
+
|
|
366
|
+
await topLevelOracleHandler.mineDeploymentNullifiers([STANDARD_AUTH_REGISTRY_ADDRESS]);
|
|
206
367
|
|
|
207
368
|
return new TXESession(
|
|
208
|
-
|
|
369
|
+
logger,
|
|
370
|
+
store,
|
|
209
371
|
stateMachine,
|
|
210
372
|
topLevelOracleHandler,
|
|
211
373
|
contractStore,
|
|
@@ -215,14 +377,18 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
215
377
|
accountStore,
|
|
216
378
|
senderTaggingStore,
|
|
217
379
|
recipientTaggingStore,
|
|
218
|
-
|
|
380
|
+
taggingSecretSourcesStore,
|
|
219
381
|
capsuleStore,
|
|
382
|
+
factStore,
|
|
220
383
|
privateEventStore,
|
|
221
384
|
jobCoordinator,
|
|
222
385
|
initialJobId,
|
|
223
386
|
version,
|
|
224
387
|
chainId,
|
|
225
388
|
nextBlockTimestamp,
|
|
389
|
+
artifactResolver,
|
|
390
|
+
rootPath,
|
|
391
|
+
packageName,
|
|
226
392
|
);
|
|
227
393
|
}
|
|
228
394
|
|
|
@@ -234,6 +400,18 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
234
400
|
*/
|
|
235
401
|
processFunction(functionName: TXEOracleFunctionName, inputs: ForeignCallArgs): Promise<ForeignCallResult> {
|
|
236
402
|
try {
|
|
403
|
+
// Oracles retired into the PXE legacy registry have no translator method; dispatch them through the same
|
|
404
|
+
// buildACIRCallback legacy path that contract execution uses, keeping TXE's two oracle paths in sync.
|
|
405
|
+
// Use an own-property check: `in` would match inherited `Object.prototype` keys (e.g. `constructor`), routing
|
|
406
|
+
// them into the legacy path instead of letting them fall through to the unknown-oracle error.
|
|
407
|
+
if (Object.hasOwn(LEGACY_ORACLE_REGISTRY, functionName)) {
|
|
408
|
+
return callTxeLegacyHandler(
|
|
409
|
+
functionName,
|
|
410
|
+
inputs,
|
|
411
|
+
this.oracleHandler as Parameters<typeof buildACIRCallback>[0],
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
|
|
237
415
|
const translator = new RPCTranslator(this, this.oracleHandler) as any;
|
|
238
416
|
// We perform a runtime validation to check that the function name corresponds to a real oracle handler.
|
|
239
417
|
const validatedFunctionName = z
|
|
@@ -244,7 +422,28 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
244
422
|
return translator[validatedFunctionName](...inputs);
|
|
245
423
|
} catch (error) {
|
|
246
424
|
if (error instanceof z.ZodError) {
|
|
247
|
-
|
|
425
|
+
let versionHint: string;
|
|
426
|
+
if (!this.txeOracleVersion) {
|
|
427
|
+
versionHint =
|
|
428
|
+
' The test appears to use an older version of Aztec.nr that does not' +
|
|
429
|
+
' support test environment oracle versioning. Update Aztec.nr to a compatible version.' +
|
|
430
|
+
' See https://docs.aztec.network/errors/12';
|
|
431
|
+
} else if (this.txeOracleVersion.minor > TXE_ORACLE_VERSION_MINOR) {
|
|
432
|
+
versionHint =
|
|
433
|
+
` The test uses Aztec.nr test oracle version` +
|
|
434
|
+
` ${this.txeOracleVersion.major}.${this.txeOracleVersion.minor}, but this test environment` +
|
|
435
|
+
` only supports up to ${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}.` +
|
|
436
|
+
` Upgrade the Aztec CLI to a compatible version.` +
|
|
437
|
+
` See https://docs.aztec.network/errors/12`;
|
|
438
|
+
} else {
|
|
439
|
+
versionHint =
|
|
440
|
+
` The test's oracle version (${this.txeOracleVersion.major}.${this.txeOracleVersion.minor})` +
|
|
441
|
+
` is compatible with this test environment` +
|
|
442
|
+
` (${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}), so this oracle should be` +
|
|
443
|
+
` available. This is an unexpected error, please report it.` +
|
|
444
|
+
` See https://docs.aztec.network/errors/13`;
|
|
445
|
+
}
|
|
446
|
+
throw new Error(`Unknown oracle '${functionName}'.${versionHint}`);
|
|
248
447
|
} else if (error instanceof Error) {
|
|
249
448
|
throw new Error(
|
|
250
449
|
`Execution error while processing function ${functionName} in state ${this.state.name}: ${error.message}`,
|
|
@@ -257,17 +456,195 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
257
456
|
}
|
|
258
457
|
}
|
|
259
458
|
|
|
260
|
-
getCurrentJob(): string {
|
|
261
|
-
return this.currentJobId;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
459
|
/** Commits the current job and begins a new one. Returns the new job ID. */
|
|
265
|
-
async cycleJob(): Promise<string> {
|
|
460
|
+
private async cycleJob(): Promise<string> {
|
|
266
461
|
await this.jobCoordinator.commitJob(this.currentJobId);
|
|
267
462
|
this.currentJobId = this.jobCoordinator.beginJob();
|
|
268
463
|
return this.currentJobId;
|
|
269
464
|
}
|
|
270
465
|
|
|
466
|
+
private resetLastCall(): void {
|
|
467
|
+
const notQueriedMessageCount = this.lastCallInfo.queried
|
|
468
|
+
? 0
|
|
469
|
+
: this.lastCallInfo.offchainEffects.filter(payload => payload[0]?.equals(OFFCHAIN_MESSAGE_IDENTIFIER)).length;
|
|
470
|
+
if (notQueriedMessageCount > 0) {
|
|
471
|
+
this.logger.warn(
|
|
472
|
+
`Dropping ${notQueriedMessageCount} unqueried offchain message(s) from the previous top-level call. ` +
|
|
473
|
+
`To deliver them, call \`env.offchain_messages()\` and forward the result to the recipient contract's ` +
|
|
474
|
+
`\`offchain_receive\` utility before issuing another top-level call. To intentionally discard, assign ` +
|
|
475
|
+
`to \`let _ = env.offchain_messages()\` to silence this warning.`,
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
this.lastCallInfo = emptyLastCallState();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
recordOffchainEffect(data: Fr[]): void {
|
|
482
|
+
this.lastCallInfo.offchainEffects.push(data);
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
private setLastCallContext(txHash: Fr, anchorBlockTimestamp: bigint): void {
|
|
486
|
+
this.lastCallInfo.txHash = txHash;
|
|
487
|
+
this.lastCallInfo.anchorBlockTimestamp = anchorBlockTimestamp;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private async withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T> {
|
|
491
|
+
this.resetLastCall();
|
|
492
|
+
// Capture the anchor *before* `work` runs: private/public executor calls mine a new block as a
|
|
493
|
+
// side effect, and that block's timestamp should not be attributed to this call's anchor.
|
|
494
|
+
const anchorBlockTimestamp = (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables
|
|
495
|
+
.timestamp;
|
|
496
|
+
const { result, txHash } = await work();
|
|
497
|
+
this.setLastCallContext(txHash ?? Fr.ZERO, anchorBlockTimestamp);
|
|
498
|
+
return result;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
getLastCallOffchainEffects(): { effects: Fr[][] } {
|
|
502
|
+
this.lastCallInfo.queried = true;
|
|
503
|
+
const effects = this.lastCallInfo.offchainEffects;
|
|
504
|
+
|
|
505
|
+
if (effects.length > MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY) {
|
|
506
|
+
throw new Error(`${effects.length} offchain effects exceed max ${MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY}`);
|
|
507
|
+
}
|
|
508
|
+
if (effects.some(e => e.length > MAX_OFFCHAIN_EFFECT_LEN)) {
|
|
509
|
+
throw new Error(`Some offchain effect has length larger than max ${MAX_OFFCHAIN_EFFECT_LEN}`);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return { effects };
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint } {
|
|
516
|
+
const { txHash, anchorBlockTimestamp } = this.lastCallInfo;
|
|
517
|
+
return { txHash, anchorBlockTimestamp };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
async executePrivateCall(
|
|
521
|
+
from: Option<AztecAddress>,
|
|
522
|
+
targetContractAddress: AztecAddress,
|
|
523
|
+
functionSelector: FunctionSelector,
|
|
524
|
+
args: Fr[],
|
|
525
|
+
argsHash: Fr,
|
|
526
|
+
isStaticCall: boolean,
|
|
527
|
+
additionalScopes: AztecAddress[],
|
|
528
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
529
|
+
gasSettings: GasSettings,
|
|
530
|
+
): Promise<Fr[]> {
|
|
531
|
+
const handler = this.handlerAsTxe();
|
|
532
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
533
|
+
const { returnValues, offchainEffects } = await handler.privateCallNewFlow(
|
|
534
|
+
from?.value,
|
|
535
|
+
targetContractAddress,
|
|
536
|
+
functionSelector,
|
|
537
|
+
args,
|
|
538
|
+
argsHash,
|
|
539
|
+
isStaticCall,
|
|
540
|
+
additionalScopes,
|
|
541
|
+
this.currentJobId,
|
|
542
|
+
authorizedUtilityCallTargets,
|
|
543
|
+
gasSettings,
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// Private execution collects offchain effects inside PXE's PrivateExecutionOracle rather than round-tripping
|
|
547
|
+
// them through `aztec_utl_emitOffchainEffect`, so the session buffer is empty at this point. Drain the effects
|
|
548
|
+
// from the execution tree into the session buffer so the next `env.offchain_messages()` call in the test sees
|
|
549
|
+
// them.
|
|
550
|
+
for (const data of offchainEffects) {
|
|
551
|
+
this.recordOffchainEffect(data);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
await this.cycleJob();
|
|
555
|
+
|
|
556
|
+
if (isStaticCall) {
|
|
557
|
+
// Static calls revert their checkpoint and mine no block, so there is no tx hash to tag offchain effects
|
|
558
|
+
// with. Querying `getLastTxEffects()` here would return an unrelated predecessor tx.
|
|
559
|
+
return { result: returnValues };
|
|
560
|
+
}
|
|
561
|
+
const { txHash } = await handler.getLastTxEffects();
|
|
562
|
+
return { result: returnValues, txHash: txHash.hash };
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async executeUtilityFunction(
|
|
567
|
+
from: Option<AztecAddress>,
|
|
568
|
+
targetContractAddress: AztecAddress,
|
|
569
|
+
functionSelector: FunctionSelector,
|
|
570
|
+
args: Fr[],
|
|
571
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
572
|
+
): Promise<Fr[]> {
|
|
573
|
+
const handler = this.handlerAsTxe();
|
|
574
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
575
|
+
const returnValues = await handler.executeUtilityFunction(
|
|
576
|
+
from?.value,
|
|
577
|
+
targetContractAddress,
|
|
578
|
+
functionSelector,
|
|
579
|
+
args,
|
|
580
|
+
this.currentJobId,
|
|
581
|
+
authorizedUtilityCallTargets,
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
await this.cycleJob();
|
|
585
|
+
|
|
586
|
+
return { result: returnValues };
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
async executePublicCall(
|
|
591
|
+
from: Option<AztecAddress>,
|
|
592
|
+
targetContractAddress: AztecAddress,
|
|
593
|
+
calldata: Fr[],
|
|
594
|
+
isStaticCall: boolean,
|
|
595
|
+
gasSettings: GasSettings,
|
|
596
|
+
): Promise<Fr[]> {
|
|
597
|
+
const handler = this.handlerAsTxe();
|
|
598
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
599
|
+
const returnValues = await handler.publicCallNewFlow(
|
|
600
|
+
from?.value,
|
|
601
|
+
targetContractAddress,
|
|
602
|
+
calldata,
|
|
603
|
+
isStaticCall,
|
|
604
|
+
gasSettings,
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
await this.cycleJob();
|
|
608
|
+
|
|
609
|
+
if (isStaticCall) {
|
|
610
|
+
// See the equivalent branch in `executePrivateCall`.
|
|
611
|
+
return { result: returnValues };
|
|
612
|
+
}
|
|
613
|
+
const { txHash } = await handler.getLastTxEffects();
|
|
614
|
+
return { result: returnValues, txHash: txHash.hash };
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress): Promise<Fr[][]> {
|
|
619
|
+
const handler = this.handlerAsTxe();
|
|
620
|
+
await handler.syncContractNonOracleMethod(contractAddress, scope, this.currentJobId);
|
|
621
|
+
// Cycle the job to commit the stores after the contract sync.
|
|
622
|
+
await this.cycleJob();
|
|
623
|
+
return handler.getPrivateEvents(selector, contractAddress, scope);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
private handlerAsTxe(): ITxeExecutionOracle {
|
|
627
|
+
if (!('isTxe' in this.oracleHandler)) {
|
|
628
|
+
throw new UnavailableOracleError('Txe');
|
|
629
|
+
}
|
|
630
|
+
return this.oracleHandler;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
setTxeOracleVersion(major: number, minor: number): void {
|
|
634
|
+
if (major !== TXE_ORACLE_VERSION_MAJOR) {
|
|
635
|
+
const hint =
|
|
636
|
+
major > TXE_ORACLE_VERSION_MAJOR
|
|
637
|
+
? 'The test was compiled with a newer version of Aztec.nr than your test environment supports. Upgrade your test environment to a compatible version.'
|
|
638
|
+
: '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.';
|
|
639
|
+
throw new Error(
|
|
640
|
+
`Incompatible test environment version: ${hint} See https://docs.aztec.network/errors/12 (expected test oracle major version ${TXE_ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
this.txeOracleVersion = { major, minor };
|
|
645
|
+
this.logger.debug(`Test compiled with test oracle version ${major}.${minor}`);
|
|
646
|
+
}
|
|
647
|
+
|
|
271
648
|
async enterTopLevelState() {
|
|
272
649
|
switch (this.state.name) {
|
|
273
650
|
case 'PRIVATE': {
|
|
@@ -302,13 +679,18 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
302
679
|
this.accountStore,
|
|
303
680
|
this.senderTaggingStore,
|
|
304
681
|
this.recipientTaggingStore,
|
|
305
|
-
this.
|
|
682
|
+
this.taggingSecretSourcesStore,
|
|
306
683
|
this.capsuleStore,
|
|
684
|
+
this.factStore,
|
|
307
685
|
this.privateEventStore,
|
|
308
686
|
this.nextBlockTimestamp,
|
|
309
687
|
this.version,
|
|
310
688
|
this.chainId,
|
|
311
689
|
this.authwits,
|
|
690
|
+
this.taggingSecretStrategy,
|
|
691
|
+
this.artifactResolver,
|
|
692
|
+
this.rootPath,
|
|
693
|
+
this.packageName,
|
|
312
694
|
);
|
|
313
695
|
|
|
314
696
|
this.state = { name: 'TOP_LEVEL' };
|
|
@@ -316,21 +698,25 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
316
698
|
}
|
|
317
699
|
|
|
318
700
|
async enterPrivateState(
|
|
319
|
-
|
|
320
|
-
|
|
701
|
+
contractAddressOpt: Option<AztecAddress>,
|
|
702
|
+
anchorBlockNumberOpt: Option<BlockNumber>,
|
|
703
|
+
gasSettings: GasSettings,
|
|
321
704
|
): Promise<PrivateContextInputs> {
|
|
705
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
706
|
+
const anchorBlockNumber = anchorBlockNumberOpt?.value;
|
|
322
707
|
this.exitTopLevelState();
|
|
708
|
+
this.resetLastCall();
|
|
323
709
|
|
|
324
710
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
325
711
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
326
712
|
// a single transaction with the effects of what was done in the test.
|
|
327
|
-
const anchorBlock = await this.stateMachine.node.
|
|
713
|
+
const anchorBlock = await this.stateMachine.node.getBlock(anchorBlockNumber ?? 'latest').then(b => b?.header);
|
|
328
714
|
|
|
329
715
|
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
330
716
|
contractAddress,
|
|
331
|
-
|
|
717
|
+
await this.keyStore.getAccounts(),
|
|
332
718
|
);
|
|
333
|
-
const latestBlock = await this.stateMachine.node.
|
|
719
|
+
const latestBlock = await this.stateMachine.node.getBlock('latest').then(b => b?.header);
|
|
334
720
|
|
|
335
721
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
336
722
|
blockNumber: BlockNumber(latestBlock!.globalVariables.blockNumber + 1),
|
|
@@ -345,9 +731,17 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
345
731
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
346
732
|
|
|
347
733
|
const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
|
|
348
|
-
|
|
734
|
+
const transientArrayService = new TransientArrayService();
|
|
735
|
+
const anchoredContractData = new AnchoredContractData(
|
|
736
|
+
this.contractStore,
|
|
737
|
+
this.stateMachine.contractClassService,
|
|
738
|
+
anchorBlock!,
|
|
739
|
+
);
|
|
740
|
+
const taggingSecretStrategy = this.taggingSecretStrategy;
|
|
741
|
+
this.oracleHandler = new TXEPrivateExecutionOracle({
|
|
349
742
|
argsHash: Fr.ZERO,
|
|
350
|
-
txContext: new TxContext(this.chainId, this.version,
|
|
743
|
+
txContext: new TxContext(this.chainId, this.version, gasSettings),
|
|
744
|
+
txRequestSalt: Fr.ZERO,
|
|
351
745
|
callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
|
|
352
746
|
anchorBlockHeader: anchorBlock!,
|
|
353
747
|
utilityExecutor,
|
|
@@ -356,19 +750,27 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
356
750
|
executionCache: new HashedValuesCache(),
|
|
357
751
|
noteCache,
|
|
358
752
|
taggingIndexCache,
|
|
359
|
-
|
|
753
|
+
anchoredContractData,
|
|
360
754
|
noteStore: this.noteStore,
|
|
361
755
|
keyStore: this.keyStore,
|
|
362
756
|
addressStore: this.addressStore,
|
|
363
757
|
aztecNode: this.stateMachine.node,
|
|
364
758
|
senderTaggingStore: this.senderTaggingStore,
|
|
365
759
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
366
|
-
|
|
367
|
-
|
|
760
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
761
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
762
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
368
763
|
privateEventStore: this.privateEventStore,
|
|
369
764
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
765
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
370
766
|
jobId: this.currentJobId,
|
|
371
|
-
scopes:
|
|
767
|
+
scopes: await this.keyStore.getAccounts(),
|
|
768
|
+
txResolver: this.stateMachine.txResolver,
|
|
769
|
+
simulator: new WASMSimulator(),
|
|
770
|
+
hooks: composeHooks({
|
|
771
|
+
resolveTaggingSecretStrategy: taggingSecretStrategy ? () => Promise.resolve(taggingSecretStrategy) : undefined,
|
|
772
|
+
}),
|
|
773
|
+
transientArrayService,
|
|
372
774
|
});
|
|
373
775
|
|
|
374
776
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
@@ -379,35 +781,47 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
379
781
|
this.state = { name: 'PRIVATE', nextBlockGlobalVariables, noteCache, taggingIndexCache };
|
|
380
782
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
381
783
|
|
|
382
|
-
|
|
784
|
+
// Record the *resolved* anchor's timestamp — if the caller pinned the anchor to a past block
|
|
785
|
+
// via `anchorBlockNumber`, "latest" would be the wrong anchor for offchain-message semantics.
|
|
786
|
+
this.setLastCallContext(Fr.ZERO, anchorBlock!.globalVariables.timestamp);
|
|
787
|
+
|
|
788
|
+
return (this.oracleHandler as TXEPrivateExecutionOracle).getPrivateContextInputs();
|
|
383
789
|
}
|
|
384
790
|
|
|
385
|
-
async enterPublicState(
|
|
791
|
+
async enterPublicState(contractAddressOpt: Option<AztecAddress>) {
|
|
792
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
386
793
|
this.exitTopLevelState();
|
|
794
|
+
this.resetLastCall();
|
|
387
795
|
|
|
388
796
|
// The PublicContext will create a block with a single transaction in it, containing the effects of what was done in
|
|
389
797
|
// the test. The block therefore gets the *next* block number and timestamp.
|
|
390
|
-
const
|
|
798
|
+
const latestHeader = (await this.stateMachine.node.getBlockData('latest'))!.header;
|
|
391
799
|
const globalVariables = makeGlobalVariables(undefined, {
|
|
392
|
-
blockNumber: BlockNumber(
|
|
800
|
+
blockNumber: BlockNumber(latestHeader.globalVariables.blockNumber + 1),
|
|
393
801
|
timestamp: this.nextBlockTimestamp,
|
|
394
802
|
version: this.version,
|
|
395
803
|
chainId: this.chainId,
|
|
396
804
|
});
|
|
397
805
|
|
|
398
806
|
this.oracleHandler = new TXEOraclePublicContext(
|
|
399
|
-
contractAddress
|
|
807
|
+
contractAddress,
|
|
400
808
|
await this.stateMachine.synchronizer.nativeWorldStateService.fork(),
|
|
401
809
|
getSingleTxBlockRequestHash(globalVariables.blockNumber),
|
|
402
810
|
globalVariables,
|
|
811
|
+
this.contractStore,
|
|
403
812
|
);
|
|
404
813
|
|
|
405
814
|
this.state = { name: 'PUBLIC' };
|
|
406
815
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
816
|
+
|
|
817
|
+
// Public state is anchored at the latest block.
|
|
818
|
+
this.setLastCallContext(Fr.ZERO, latestHeader.globalVariables.timestamp);
|
|
407
819
|
}
|
|
408
820
|
|
|
409
|
-
async enterUtilityState(
|
|
821
|
+
async enterUtilityState(contractAddressOpt: Option<AztecAddress>) {
|
|
822
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
410
823
|
this.exitTopLevelState();
|
|
824
|
+
this.resetLastCall();
|
|
411
825
|
|
|
412
826
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
413
827
|
|
|
@@ -421,28 +835,49 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
421
835
|
this.stateMachine.node,
|
|
422
836
|
anchorBlockHeader,
|
|
423
837
|
this.currentJobId,
|
|
424
|
-
).syncNoteNullifiers(contractAddress,
|
|
838
|
+
).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts());
|
|
425
839
|
|
|
426
840
|
this.oracleHandler = new UtilityExecutionOracle({
|
|
427
|
-
|
|
841
|
+
callContext: CallContext.from({
|
|
842
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
843
|
+
contractAddress,
|
|
844
|
+
// No specific function is being executed in this inlined utility context, hence the empty selector.
|
|
845
|
+
functionSelector: FunctionSelector.empty(),
|
|
846
|
+
isStaticCall: true,
|
|
847
|
+
}),
|
|
428
848
|
authWitnesses: [],
|
|
429
849
|
capsules: [],
|
|
430
850
|
anchorBlockHeader,
|
|
431
|
-
|
|
851
|
+
anchoredContractData: new AnchoredContractData(
|
|
852
|
+
this.contractStore,
|
|
853
|
+
this.stateMachine.contractClassService,
|
|
854
|
+
anchorBlockHeader,
|
|
855
|
+
),
|
|
432
856
|
noteStore: this.noteStore,
|
|
433
857
|
keyStore: this.keyStore,
|
|
434
858
|
addressStore: this.addressStore,
|
|
435
859
|
aztecNode: this.stateMachine.node,
|
|
436
860
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
437
|
-
|
|
438
|
-
|
|
861
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
862
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
863
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
439
864
|
privateEventStore: this.privateEventStore,
|
|
865
|
+
txResolver: this.stateMachine.txResolver,
|
|
866
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
867
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
440
868
|
jobId: this.currentJobId,
|
|
441
|
-
scopes:
|
|
869
|
+
scopes: await this.keyStore.getAccounts(),
|
|
870
|
+
simulator: new WASMSimulator(),
|
|
871
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlockHeader),
|
|
872
|
+
// Execution-tree root (top-level utility run): own store; nested frames inherit it.
|
|
873
|
+
transientArrayService: new TransientArrayService(),
|
|
442
874
|
});
|
|
443
875
|
|
|
444
876
|
this.state = { name: 'UTILITY' };
|
|
445
877
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
878
|
+
|
|
879
|
+
// Utility state anchors at whatever the anchor block store is pointing to (tracked as latest).
|
|
880
|
+
this.setLastCallContext(Fr.ZERO, anchorBlockHeader.globalVariables.timestamp);
|
|
446
881
|
}
|
|
447
882
|
|
|
448
883
|
private exitTopLevelState() {
|
|
@@ -451,15 +886,20 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
451
886
|
}
|
|
452
887
|
|
|
453
888
|
// Note that while all public and private contexts do is build a single block that we then process when exiting
|
|
454
|
-
//
|
|
455
|
-
//
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
// the
|
|
461
|
-
|
|
462
|
-
|
|
889
|
+
// them, the top level context does most of its work as it goes: it creates empty blocks (via `advanceBlocksBy`
|
|
890
|
+
// and `deploy`), creates blocks with transactions (via `privateCallNewFlow` and `publicCallNewFlow`), adds
|
|
891
|
+
// accounts to PXE (via `addAccount`), etc. This is a slight inconsistency in the working model of this class, but
|
|
892
|
+
// is not too bad. The `close` call below therefore only hands back the session-scoped values that a test
|
|
893
|
+
// sets directly at the top level, outside any contract execution (e.g. via `advanceTimestampBy`,
|
|
894
|
+
// `addAuthWitness`, `setTaggingSecretStrategy`). The oracle handler is discarded on every state transition,
|
|
895
|
+
// so the session must seed these values into the contexts it creates later.
|
|
896
|
+
|
|
897
|
+
// TODO: persisting authwits this way is quite unfortunate: they create a temporary utility context that would
|
|
898
|
+
// otherwise reset them, so we'd not be able to pass more than one per execution. Ideally authwits would be passed
|
|
899
|
+
// alongside a contract call instead of pre-seeded.
|
|
900
|
+
[this.nextBlockTimestamp, this.authwits, this.taggingSecretStrategy] = (
|
|
901
|
+
this.oracleHandler as TXEOracleTopLevelContext
|
|
902
|
+
).close();
|
|
463
903
|
}
|
|
464
904
|
|
|
465
905
|
private async exitPrivateState() {
|
|
@@ -507,32 +947,57 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
507
947
|
}
|
|
508
948
|
|
|
509
949
|
private utilityExecutorForContractSync(anchorBlock: any) {
|
|
510
|
-
return async (call: FunctionCall, scopes:
|
|
511
|
-
const
|
|
950
|
+
return async (call: FunctionCall, scopes: AztecAddress[]) => {
|
|
951
|
+
const anchoredContractData = new AnchoredContractData(
|
|
952
|
+
this.contractStore,
|
|
953
|
+
this.stateMachine.contractClassService,
|
|
954
|
+
anchorBlock!,
|
|
955
|
+
);
|
|
956
|
+
const entryPointArtifact = await anchoredContractData.getFunctionArtifactWithDebugMetadata(
|
|
957
|
+
call.to,
|
|
958
|
+
call.selector,
|
|
959
|
+
);
|
|
960
|
+
if (!entryPointArtifact) {
|
|
961
|
+
throw new Error(`Cannot run function ${call.selector} on ${call.to}: the contract is not registered.`);
|
|
962
|
+
}
|
|
512
963
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
513
964
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
514
965
|
}
|
|
515
966
|
|
|
516
967
|
try {
|
|
968
|
+
const simulator = new WASMSimulator();
|
|
517
969
|
const oracle = new UtilityExecutionOracle({
|
|
518
|
-
|
|
970
|
+
callContext: CallContext.from({
|
|
971
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
972
|
+
contractAddress: call.to,
|
|
973
|
+
functionSelector: call.selector,
|
|
974
|
+
isStaticCall: true,
|
|
975
|
+
}),
|
|
519
976
|
authWitnesses: [],
|
|
520
977
|
capsules: [],
|
|
521
978
|
anchorBlockHeader: anchorBlock!,
|
|
522
|
-
|
|
979
|
+
anchoredContractData,
|
|
523
980
|
noteStore: this.noteStore,
|
|
524
981
|
keyStore: this.keyStore,
|
|
525
982
|
addressStore: this.addressStore,
|
|
526
983
|
aztecNode: this.stateMachine.node,
|
|
527
984
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
528
|
-
|
|
529
|
-
|
|
985
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
986
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
987
|
+
factService: new FactService(this.factStore, scopes),
|
|
530
988
|
privateEventStore: this.privateEventStore,
|
|
989
|
+
txResolver: this.stateMachine.txResolver,
|
|
990
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
991
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
531
992
|
jobId: this.currentJobId,
|
|
532
993
|
scopes,
|
|
994
|
+
simulator,
|
|
995
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlock),
|
|
996
|
+
// Top-level utility entrypoint: gets a fresh store. Nested frames inherit it via UtilityExecutionOracle.
|
|
997
|
+
transientArrayService: new TransientArrayService(),
|
|
533
998
|
});
|
|
534
|
-
await
|
|
535
|
-
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact,
|
|
999
|
+
await simulator
|
|
1000
|
+
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, buildACIRCallback(oracle))
|
|
536
1001
|
.catch((err: Error) => {
|
|
537
1002
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
538
1003
|
throw new ExecutionError(
|