@aztec/txe 0.0.1-commit.b655e406 → 0.0.1-commit.b8a057fa
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-HMC7WEOJ.js +3 -0
- package/dest/AuthRegistry-HMC7WEOJ.js.map +7 -0
- package/dest/ContractClassRegistry-TXCDCFNC.js +3 -0
- package/dest/ContractClassRegistry-TXCDCFNC.js.map +7 -0
- package/dest/ContractInstanceRegistry-2TZHWOTT.js +3 -0
- package/dest/ContractInstanceRegistry-2TZHWOTT.js.map +7 -0
- package/dest/FeeJuice-FDF3J2Q5.js +3 -0
- package/dest/FeeJuice-FDF3J2Q5.js.map +7 -0
- package/dest/HandshakeRegistry-C7JF4R54.js +3 -0
- package/dest/HandshakeRegistry-C7JF4R54.js.map +7 -0
- package/dest/MultiCallEntrypoint-IGLO227K.js +3 -0
- package/dest/MultiCallEntrypoint-IGLO227K.js.map +7 -0
- package/dest/SchnorrAccount-KCIHUCXS.js +3 -0
- package/dest/SchnorrAccount-KCIHUCXS.js.map +7 -0
- package/dest/SchnorrInitializerlessAccount-PVR6XUSN.js +3 -0
- package/dest/SchnorrInitializerlessAccount-PVR6XUSN.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.d.ts +1 -1
- 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-32UHX7YY.js +3 -0
- package/dest/chunk-32UHX7YY.js.map +7 -0
- package/dest/chunk-FRF5YZEO.js +304 -0
- package/dest/chunk-FRF5YZEO.js.map +7 -0
- package/dest/chunk-O57S6W5S.js +260 -0
- package/dest/chunk-O57S6W5S.js.map +7 -0
- package/dest/constants.d.ts +7 -0
- package/dest/constants.d.ts.map +1 -0
- package/dest/constants.js +10 -0
- 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 +75 -158
- package/dest/metafile.json +38497 -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 +65 -31
- 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 +41 -17
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +69 -23
- 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 +66 -30
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +630 -275
- 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 -213
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +877 -550
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +23 -52
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +76 -99
- package/dest/state_machine/dummy_p2p_client.d.ts +31 -15
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +63 -22
- package/dest/state_machine/global_variable_builder.d.ts +10 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +20 -5
- package/dest/state_machine/index.d.ts +14 -8
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +84 -27
- package/dest/state_machine/mock_epoch_cache.d.ts +29 -12
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +50 -15
- package/dest/state_machine/synchronizer.d.ts +15 -6
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +27 -13
- package/dest/txe_session.d.ts +102 -21
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +440 -76
- package/dest/utils/block_creation.d.ts +22 -7
- package/dest/utils/block_creation.d.ts.map +1 -1
- package/dest/utils/block_creation.js +40 -6
- package/dest/utils/encoding.d.ts +192 -0
- package/dest/utils/encoding.d.ts.map +1 -0
- package/dest/{util → utils}/encoding.js +8 -3
- package/dest/utils/expected_failure_error.d.ts +4 -0
- package/dest/utils/expected_failure_error.d.ts.map +1 -0
- package/dest/utils/tx_effect_creation.d.ts +3 -3
- package/dest/utils/tx_effect_creation.d.ts.map +1 -1
- package/dest/utils/tx_effect_creation.js +3 -7
- 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_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/utils/txe_public_contract_data_source.js +51 -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 +40 -22
- 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 +13 -0
- package/src/dispatcher_pool.ts +317 -0
- package/src/index.ts +113 -201
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +68 -36
- 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 +83 -28
- package/src/oracle/txe_oracle_registry.ts +536 -0
- package/src/oracle/txe_oracle_top_level_context.ts +539 -199
- 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 +1086 -909
- package/src/state_machine/archiver.ts +82 -115
- package/src/state_machine/dummy_p2p_client.ts +96 -33
- package/src/state_machine/global_variable_builder.ts +28 -9
- package/src/state_machine/index.ts +118 -44
- package/src/state_machine/mock_epoch_cache.ts +63 -23
- package/src/state_machine/synchronizer.ts +36 -14
- package/src/txe_session.ts +719 -125
- package/src/utils/block_creation.ts +51 -15
- package/src/{util → utils}/encoding.ts +9 -3
- package/src/utils/tx_effect_creation.ts +4 -13
- package/src/{util/txe_account_data_provider.ts → utils/txe_account_store.ts} +1 -1
- package/src/utils/txe_artifact_resolver.ts +217 -0
- package/src/utils/txe_public_contract_data_source.ts +60 -0
- package/src/worker.ts +98 -0
- package/dest/util/encoding.d.ts +0 -121
- package/dest/util/encoding.d.ts.map +0 -1
- package/dest/util/expected_failure_error.d.ts +0 -4
- 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 -20
- 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 -85
- /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
|
@@ -1,51 +1,76 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
3
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
4
|
import { KeyStore } from '@aztec/key-store';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
5
|
+
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
6
|
+
import { openEphemeralStore } from '@aztec/kv-store/lmdb-v2';
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
AddressStore,
|
|
9
|
+
AnchorBlockStore,
|
|
10
|
+
AnchoredContractData,
|
|
11
|
+
CapsuleService,
|
|
12
|
+
CapsuleStore,
|
|
13
|
+
ContractStore,
|
|
14
|
+
FactService,
|
|
15
|
+
FactStore,
|
|
16
|
+
JobCoordinator,
|
|
17
|
+
NoteService,
|
|
18
|
+
NoteStore,
|
|
19
|
+
PrivateEventStore,
|
|
20
|
+
RecipientTaggingStore,
|
|
21
|
+
SenderTaggingStore,
|
|
22
|
+
TaggingSecretSourcesStore,
|
|
23
|
+
type TaggingSecretStrategy,
|
|
24
|
+
composeHooks,
|
|
13
25
|
} from '@aztec/pxe/server';
|
|
14
26
|
import {
|
|
15
27
|
ExecutionNoteCache,
|
|
16
28
|
ExecutionTaggingIndexCache,
|
|
17
29
|
HashedValuesCache,
|
|
30
|
+
type IMiscOracle,
|
|
18
31
|
type IPrivateExecutionOracle,
|
|
19
32
|
type IUtilityExecutionOracle,
|
|
20
|
-
|
|
33
|
+
LEGACY_ORACLE_REGISTRY,
|
|
34
|
+
Option,
|
|
35
|
+
TransientArrayService,
|
|
21
36
|
UtilityExecutionOracle,
|
|
37
|
+
buildACIRCallback,
|
|
22
38
|
} from '@aztec/pxe/simulator';
|
|
23
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
ExecutionError,
|
|
41
|
+
WASMSimulator,
|
|
42
|
+
createSimulationError,
|
|
43
|
+
extractCallStack,
|
|
44
|
+
resolveAssertionMessageFromError,
|
|
45
|
+
toACVMWitness,
|
|
46
|
+
} from '@aztec/simulator/client';
|
|
47
|
+
import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants';
|
|
48
|
+
import { EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
24
49
|
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
25
50
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
51
|
+
import type { GasSettings } from '@aztec/stdlib/gas';
|
|
52
|
+
import { computeProtocolNullifier } from '@aztec/stdlib/hash';
|
|
28
53
|
import { PrivateContextInputs } from '@aztec/stdlib/kernel';
|
|
29
|
-
import {
|
|
30
|
-
import { CallContext, GlobalVariables, TxContext } from '@aztec/stdlib/tx';
|
|
31
|
-
import type { UInt32 } from '@aztec/stdlib/types';
|
|
54
|
+
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
55
|
+
import { CallContext, GlobalVariables, OFFCHAIN_MESSAGE_IDENTIFIER, TxContext } from '@aztec/stdlib/tx';
|
|
32
56
|
|
|
33
57
|
import { z } from 'zod';
|
|
34
58
|
|
|
59
|
+
import { DEFAULT_ADDRESS, MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY, MAX_OFFCHAIN_EFFECT_LEN } from './constants.js';
|
|
35
60
|
import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
|
|
36
61
|
import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
|
|
62
|
+
import { callTxeLegacyHandler } from './oracle/txe_oracle_registry.js';
|
|
37
63
|
import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
|
|
38
|
-
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';
|
|
67
|
+
import { TXEArchiver } from './state_machine/archiver.js';
|
|
39
68
|
import { TXEStateMachine } from './state_machine/index.js';
|
|
40
|
-
import
|
|
41
|
-
import {
|
|
42
|
-
import { TXEContractDataProvider } from './util/txe_contract_data_provider.js';
|
|
43
|
-
import {
|
|
44
|
-
getSingleTxBlockRequestHash,
|
|
45
|
-
insertTxEffectIntoWorldTrees,
|
|
46
|
-
makeTXEBlockHeader,
|
|
47
|
-
} from './utils/block_creation.js';
|
|
69
|
+
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
|
|
70
|
+
import type { ForeignCallArgs, ForeignCallResult } from './utils/encoding.js';
|
|
48
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';
|
|
49
74
|
|
|
50
75
|
/**
|
|
51
76
|
* A TXE Session can be in one of four states, which change as the test progresses and different oracles are called.
|
|
@@ -66,7 +91,6 @@ type SessionState =
|
|
|
66
91
|
| {
|
|
67
92
|
name: 'PRIVATE';
|
|
68
93
|
nextBlockGlobalVariables: GlobalVariables;
|
|
69
|
-
txRequestHash: Fr;
|
|
70
94
|
noteCache: ExecutionNoteCache;
|
|
71
95
|
taggingIndexCache: ExecutionTaggingIndexCache;
|
|
72
96
|
}
|
|
@@ -99,13 +123,112 @@ export type TXEOracleFunctionName = Exclude<
|
|
|
99
123
|
>;
|
|
100
124
|
|
|
101
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
|
+
|
|
102
129
|
enterTopLevelState(): Promise<void>;
|
|
103
|
-
enterPublicState(contractAddress
|
|
104
|
-
enterPrivateState(
|
|
105
|
-
|
|
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;
|
|
106
227
|
}
|
|
107
228
|
|
|
108
|
-
|
|
229
|
+
function emptyLastCallState(): LastCallState {
|
|
230
|
+
return { offchainEffects: [], queried: false, txHash: Fr.ZERO, anchorBlockTimestamp: 0n };
|
|
231
|
+
}
|
|
109
232
|
|
|
110
233
|
/**
|
|
111
234
|
* A `TXESession` corresponds to a Noir `#[test]` function, and handles all of its oracle calls, stores test-specific
|
|
@@ -114,87 +237,166 @@ const DEFAULT_ADDRESS = AztecAddress.fromNumber(42);
|
|
|
114
237
|
export class TXESession implements TXESessionStateHandler {
|
|
115
238
|
private state: SessionState = { name: 'TOP_LEVEL' };
|
|
116
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;
|
|
117
245
|
|
|
118
246
|
constructor(
|
|
119
247
|
private logger: Logger,
|
|
248
|
+
private sessionStore: AztecAsyncKVStore,
|
|
120
249
|
private stateMachine: TXEStateMachine,
|
|
121
250
|
private oracleHandler:
|
|
251
|
+
| IMiscOracle
|
|
122
252
|
| IUtilityExecutionOracle
|
|
123
253
|
| IPrivateExecutionOracle
|
|
124
254
|
| IAvmExecutionOracle
|
|
125
255
|
| ITxeExecutionOracle,
|
|
126
|
-
private
|
|
256
|
+
private contractStore: ContractStore,
|
|
257
|
+
private noteStore: NoteStore,
|
|
127
258
|
private keyStore: KeyStore,
|
|
128
|
-
private
|
|
129
|
-
private
|
|
259
|
+
private addressStore: AddressStore,
|
|
260
|
+
private accountStore: TXEAccountStore,
|
|
261
|
+
private senderTaggingStore: SenderTaggingStore,
|
|
262
|
+
private recipientTaggingStore: RecipientTaggingStore,
|
|
263
|
+
private taggingSecretSourcesStore: TaggingSecretSourcesStore,
|
|
264
|
+
private capsuleStore: CapsuleStore,
|
|
265
|
+
private factStore: FactStore,
|
|
266
|
+
private privateEventStore: PrivateEventStore,
|
|
267
|
+
private jobCoordinator: JobCoordinator,
|
|
268
|
+
private currentJobId: string,
|
|
130
269
|
private chainId: Fr,
|
|
131
270
|
private version: Fr,
|
|
132
271
|
private nextBlockTimestamp: bigint,
|
|
133
|
-
private
|
|
272
|
+
private readonly artifactResolver: TXEArtifactResolver,
|
|
273
|
+
private readonly rootPath: string,
|
|
274
|
+
private readonly packageName: string,
|
|
134
275
|
) {}
|
|
135
276
|
|
|
136
|
-
|
|
137
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Tears down the per-session AVM simulator (process pool + CDB server), the `NativeWorldStateService`,
|
|
279
|
+
* and the `txe-session` LMDB. 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
|
+
// Dispose the AVM pool before the world state: it kills the bb-avm-sim processes so they release their
|
|
287
|
+
// connection to the WSDB server, letting it shut down cleanly. Skipping this leaks a bb-avm-sim process
|
|
288
|
+
// (and keeps its WSDB alive) per session.
|
|
289
|
+
try {
|
|
290
|
+
await this.stateMachine.synchronizer.closeIpc();
|
|
291
|
+
} catch (err) {
|
|
292
|
+
this.logger.warn(`Error closing AVM simulator during session dispose`, err);
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
await this.stateMachine.synchronizer.nativeWorldStateService.close();
|
|
296
|
+
} catch (err) {
|
|
297
|
+
this.logger.warn(`Error closing native world state during session dispose`, err);
|
|
298
|
+
}
|
|
299
|
+
try {
|
|
300
|
+
await this.sessionStore.close();
|
|
301
|
+
} catch (err) {
|
|
302
|
+
this.logger.warn(`Error closing session LMDB during dispose`, err);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static async init(
|
|
307
|
+
contractStore: ContractStore,
|
|
308
|
+
artifactResolver: TXEArtifactResolver,
|
|
309
|
+
rootPath: string,
|
|
310
|
+
packageName: string,
|
|
311
|
+
) {
|
|
312
|
+
// Size LMDB's reader slots to the libuv pool (capped to 2 in bin/index.ts via
|
|
313
|
+
// HARDWARE_CONCURRENCY): each native LMDB read needs a libuv worker thread to run, so any
|
|
314
|
+
// slot beyond the pool size would sit idle while still consuming a semaphore + reader-table
|
|
315
|
+
// entry per session.
|
|
316
|
+
const store = await openEphemeralStore('txe-session', undefined, 2);
|
|
138
317
|
|
|
139
|
-
const
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
const
|
|
318
|
+
const addressStore = new AddressStore(store);
|
|
319
|
+
const privateEventStore = new PrivateEventStore(store);
|
|
320
|
+
const noteStore = new NoteStore(store);
|
|
321
|
+
const senderTaggingStore = new SenderTaggingStore(store);
|
|
322
|
+
const recipientTaggingStore = new RecipientTaggingStore(store);
|
|
323
|
+
const taggingSecretSourcesStore = new TaggingSecretSourcesStore(store);
|
|
324
|
+
const capsuleStore = new CapsuleStore(store);
|
|
325
|
+
const factStore = new FactStore(store);
|
|
145
326
|
const keyStore = new KeyStore(store);
|
|
146
|
-
const
|
|
327
|
+
const accountStore = new TXEAccountStore(store);
|
|
147
328
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
329
|
+
const jobCoordinator = new JobCoordinator(store);
|
|
330
|
+
jobCoordinator.registerStores([
|
|
331
|
+
capsuleStore,
|
|
332
|
+
factStore,
|
|
333
|
+
senderTaggingStore,
|
|
334
|
+
recipientTaggingStore,
|
|
335
|
+
privateEventStore,
|
|
336
|
+
noteStore,
|
|
337
|
+
]);
|
|
153
338
|
|
|
154
|
-
const
|
|
339
|
+
const archiver = new TXEArchiver(store);
|
|
340
|
+
const anchorBlockStore = new AnchorBlockStore(store);
|
|
341
|
+
const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
|
|
155
342
|
|
|
156
343
|
const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
|
|
157
344
|
const version = new Fr(await stateMachine.node.getVersion());
|
|
158
345
|
const chainId = new Fr(await stateMachine.node.getChainId());
|
|
159
346
|
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
contractDataProvider,
|
|
164
|
-
noteDataProvider,
|
|
165
|
-
capsuleDataProvider,
|
|
166
|
-
stateMachine.syncDataProvider,
|
|
167
|
-
taggingDataProvider,
|
|
168
|
-
addressDataProvider,
|
|
169
|
-
privateEventDataProvider,
|
|
170
|
-
);
|
|
347
|
+
const initialJobId = jobCoordinator.beginJob();
|
|
348
|
+
|
|
349
|
+
const logger = createLogger('txe:session');
|
|
171
350
|
|
|
172
351
|
const topLevelOracleHandler = new TXEOracleTopLevelContext(
|
|
173
352
|
stateMachine,
|
|
174
|
-
|
|
353
|
+
contractStore,
|
|
354
|
+
noteStore,
|
|
175
355
|
keyStore,
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
356
|
+
addressStore,
|
|
357
|
+
accountStore,
|
|
358
|
+
senderTaggingStore,
|
|
359
|
+
recipientTaggingStore,
|
|
360
|
+
taggingSecretSourcesStore,
|
|
361
|
+
capsuleStore,
|
|
362
|
+
factStore,
|
|
363
|
+
privateEventStore,
|
|
179
364
|
nextBlockTimestamp,
|
|
180
365
|
version,
|
|
181
366
|
chainId,
|
|
182
367
|
new Map(),
|
|
368
|
+
undefined,
|
|
369
|
+
artifactResolver,
|
|
370
|
+
rootPath,
|
|
371
|
+
packageName,
|
|
183
372
|
);
|
|
184
|
-
|
|
373
|
+
|
|
374
|
+
await topLevelOracleHandler.mineDeploymentNullifiers([STANDARD_AUTH_REGISTRY_ADDRESS]);
|
|
185
375
|
|
|
186
376
|
return new TXESession(
|
|
187
|
-
|
|
377
|
+
logger,
|
|
378
|
+
store,
|
|
188
379
|
stateMachine,
|
|
189
380
|
topLevelOracleHandler,
|
|
190
|
-
|
|
381
|
+
contractStore,
|
|
382
|
+
noteStore,
|
|
191
383
|
keyStore,
|
|
192
|
-
|
|
193
|
-
|
|
384
|
+
addressStore,
|
|
385
|
+
accountStore,
|
|
386
|
+
senderTaggingStore,
|
|
387
|
+
recipientTaggingStore,
|
|
388
|
+
taggingSecretSourcesStore,
|
|
389
|
+
capsuleStore,
|
|
390
|
+
factStore,
|
|
391
|
+
privateEventStore,
|
|
392
|
+
jobCoordinator,
|
|
393
|
+
initialJobId,
|
|
194
394
|
version,
|
|
195
395
|
chainId,
|
|
196
396
|
nextBlockTimestamp,
|
|
197
|
-
|
|
397
|
+
artifactResolver,
|
|
398
|
+
rootPath,
|
|
399
|
+
packageName,
|
|
198
400
|
);
|
|
199
401
|
}
|
|
200
402
|
|
|
@@ -206,6 +408,18 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
206
408
|
*/
|
|
207
409
|
processFunction(functionName: TXEOracleFunctionName, inputs: ForeignCallArgs): Promise<ForeignCallResult> {
|
|
208
410
|
try {
|
|
411
|
+
// Oracles retired into the PXE legacy registry have no translator method; dispatch them through the same
|
|
412
|
+
// buildACIRCallback legacy path that contract execution uses, keeping TXE's two oracle paths in sync.
|
|
413
|
+
// Use an own-property check: `in` would match inherited `Object.prototype` keys (e.g. `constructor`), routing
|
|
414
|
+
// them into the legacy path instead of letting them fall through to the unknown-oracle error.
|
|
415
|
+
if (Object.hasOwn(LEGACY_ORACLE_REGISTRY, functionName)) {
|
|
416
|
+
return callTxeLegacyHandler(
|
|
417
|
+
functionName,
|
|
418
|
+
inputs,
|
|
419
|
+
this.oracleHandler as Parameters<typeof buildACIRCallback>[0],
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
209
423
|
const translator = new RPCTranslator(this, this.oracleHandler) as any;
|
|
210
424
|
// We perform a runtime validation to check that the function name corresponds to a real oracle handler.
|
|
211
425
|
const validatedFunctionName = z
|
|
@@ -216,7 +430,28 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
216
430
|
return translator[validatedFunctionName](...inputs);
|
|
217
431
|
} catch (error) {
|
|
218
432
|
if (error instanceof z.ZodError) {
|
|
219
|
-
|
|
433
|
+
let versionHint: string;
|
|
434
|
+
if (!this.txeOracleVersion) {
|
|
435
|
+
versionHint =
|
|
436
|
+
' The test appears to use an older version of Aztec.nr that does not' +
|
|
437
|
+
' support test environment oracle versioning. Update Aztec.nr to a compatible version.' +
|
|
438
|
+
' See https://docs.aztec.network/errors/12';
|
|
439
|
+
} else if (this.txeOracleVersion.minor > TXE_ORACLE_VERSION_MINOR) {
|
|
440
|
+
versionHint =
|
|
441
|
+
` The test uses Aztec.nr test oracle version` +
|
|
442
|
+
` ${this.txeOracleVersion.major}.${this.txeOracleVersion.minor}, but this test environment` +
|
|
443
|
+
` only supports up to ${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}.` +
|
|
444
|
+
` Upgrade the Aztec CLI to a compatible version.` +
|
|
445
|
+
` See https://docs.aztec.network/errors/12`;
|
|
446
|
+
} else {
|
|
447
|
+
versionHint =
|
|
448
|
+
` The test's oracle version (${this.txeOracleVersion.major}.${this.txeOracleVersion.minor})` +
|
|
449
|
+
` is compatible with this test environment` +
|
|
450
|
+
` (${TXE_ORACLE_VERSION_MAJOR}.${TXE_ORACLE_VERSION_MINOR}), so this oracle should be` +
|
|
451
|
+
` available. This is an unexpected error, please report it.` +
|
|
452
|
+
` See https://docs.aztec.network/errors/13`;
|
|
453
|
+
}
|
|
454
|
+
throw new Error(`Unknown oracle '${functionName}'.${versionHint}`);
|
|
220
455
|
} else if (error instanceof Error) {
|
|
221
456
|
throw new Error(
|
|
222
457
|
`Execution error while processing function ${functionName} in state ${this.state.name}: ${error.message}`,
|
|
@@ -229,6 +464,195 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
229
464
|
}
|
|
230
465
|
}
|
|
231
466
|
|
|
467
|
+
/** Commits the current job and begins a new one. Returns the new job ID. */
|
|
468
|
+
private async cycleJob(): Promise<string> {
|
|
469
|
+
await this.jobCoordinator.commitJob(this.currentJobId);
|
|
470
|
+
this.currentJobId = this.jobCoordinator.beginJob();
|
|
471
|
+
return this.currentJobId;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
private resetLastCall(): void {
|
|
475
|
+
const notQueriedMessageCount = this.lastCallInfo.queried
|
|
476
|
+
? 0
|
|
477
|
+
: this.lastCallInfo.offchainEffects.filter(payload => payload[0]?.equals(OFFCHAIN_MESSAGE_IDENTIFIER)).length;
|
|
478
|
+
if (notQueriedMessageCount > 0) {
|
|
479
|
+
this.logger.warn(
|
|
480
|
+
`Dropping ${notQueriedMessageCount} unqueried offchain message(s) from the previous top-level call. ` +
|
|
481
|
+
`To deliver them, call \`env.offchain_messages()\` and forward the result to the recipient contract's ` +
|
|
482
|
+
`\`offchain_receive\` utility before issuing another top-level call. To intentionally discard, assign ` +
|
|
483
|
+
`to \`let _ = env.offchain_messages()\` to silence this warning.`,
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
this.lastCallInfo = emptyLastCallState();
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
recordOffchainEffect(data: Fr[]): void {
|
|
490
|
+
this.lastCallInfo.offchainEffects.push(data);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
private setLastCallContext(txHash: Fr, anchorBlockTimestamp: bigint): void {
|
|
494
|
+
this.lastCallInfo.txHash = txHash;
|
|
495
|
+
this.lastCallInfo.anchorBlockTimestamp = anchorBlockTimestamp;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private async withTopLevelCallTracking<T>(work: () => Promise<{ result: T; txHash?: Fr }>): Promise<T> {
|
|
499
|
+
this.resetLastCall();
|
|
500
|
+
// Capture the anchor *before* `work` runs: private/public executor calls mine a new block as a
|
|
501
|
+
// side effect, and that block's timestamp should not be attributed to this call's anchor.
|
|
502
|
+
const anchorBlockTimestamp = (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables
|
|
503
|
+
.timestamp;
|
|
504
|
+
const { result, txHash } = await work();
|
|
505
|
+
this.setLastCallContext(txHash ?? Fr.ZERO, anchorBlockTimestamp);
|
|
506
|
+
return result;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
getLastCallOffchainEffects(): { effects: Fr[][] } {
|
|
510
|
+
this.lastCallInfo.queried = true;
|
|
511
|
+
const effects = this.lastCallInfo.offchainEffects;
|
|
512
|
+
|
|
513
|
+
if (effects.length > MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY) {
|
|
514
|
+
throw new Error(`${effects.length} offchain effects exceed max ${MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY}`);
|
|
515
|
+
}
|
|
516
|
+
if (effects.some(e => e.length > MAX_OFFCHAIN_EFFECT_LEN)) {
|
|
517
|
+
throw new Error(`Some offchain effect has length larger than max ${MAX_OFFCHAIN_EFFECT_LEN}`);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return { effects };
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
getLastCallContext(): { txHash: Fr; anchorBlockTimestamp: bigint } {
|
|
524
|
+
const { txHash, anchorBlockTimestamp } = this.lastCallInfo;
|
|
525
|
+
return { txHash, anchorBlockTimestamp };
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
async executePrivateCall(
|
|
529
|
+
from: Option<AztecAddress>,
|
|
530
|
+
targetContractAddress: AztecAddress,
|
|
531
|
+
functionSelector: FunctionSelector,
|
|
532
|
+
args: Fr[],
|
|
533
|
+
argsHash: Fr,
|
|
534
|
+
isStaticCall: boolean,
|
|
535
|
+
additionalScopes: AztecAddress[],
|
|
536
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
537
|
+
gasSettings: GasSettings,
|
|
538
|
+
): Promise<Fr[]> {
|
|
539
|
+
const handler = this.handlerAsTxe();
|
|
540
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
541
|
+
const { returnValues, offchainEffects } = await handler.privateCallNewFlow(
|
|
542
|
+
from?.value,
|
|
543
|
+
targetContractAddress,
|
|
544
|
+
functionSelector,
|
|
545
|
+
args,
|
|
546
|
+
argsHash,
|
|
547
|
+
isStaticCall,
|
|
548
|
+
additionalScopes,
|
|
549
|
+
this.currentJobId,
|
|
550
|
+
authorizedUtilityCallTargets,
|
|
551
|
+
gasSettings,
|
|
552
|
+
);
|
|
553
|
+
|
|
554
|
+
// Private execution collects offchain effects inside PXE's PrivateExecutionOracle rather than round-tripping
|
|
555
|
+
// them through `aztec_utl_emitOffchainEffect`, so the session buffer is empty at this point. Drain the effects
|
|
556
|
+
// from the execution tree into the session buffer so the next `env.offchain_messages()` call in the test sees
|
|
557
|
+
// them.
|
|
558
|
+
for (const data of offchainEffects) {
|
|
559
|
+
this.recordOffchainEffect(data);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
await this.cycleJob();
|
|
563
|
+
|
|
564
|
+
if (isStaticCall) {
|
|
565
|
+
// Static calls revert their checkpoint and mine no block, so there is no tx hash to tag offchain effects
|
|
566
|
+
// with. Querying `getLastTxEffects()` here would return an unrelated predecessor tx.
|
|
567
|
+
return { result: returnValues };
|
|
568
|
+
}
|
|
569
|
+
const { txHash } = await handler.getLastTxEffects();
|
|
570
|
+
return { result: returnValues, txHash: txHash.hash };
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
async executeUtilityFunction(
|
|
575
|
+
from: Option<AztecAddress>,
|
|
576
|
+
targetContractAddress: AztecAddress,
|
|
577
|
+
functionSelector: FunctionSelector,
|
|
578
|
+
args: Fr[],
|
|
579
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
580
|
+
): Promise<Fr[]> {
|
|
581
|
+
const handler = this.handlerAsTxe();
|
|
582
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
583
|
+
const returnValues = await handler.executeUtilityFunction(
|
|
584
|
+
from?.value,
|
|
585
|
+
targetContractAddress,
|
|
586
|
+
functionSelector,
|
|
587
|
+
args,
|
|
588
|
+
this.currentJobId,
|
|
589
|
+
authorizedUtilityCallTargets,
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
await this.cycleJob();
|
|
593
|
+
|
|
594
|
+
return { result: returnValues };
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
async executePublicCall(
|
|
599
|
+
from: Option<AztecAddress>,
|
|
600
|
+
targetContractAddress: AztecAddress,
|
|
601
|
+
calldata: Fr[],
|
|
602
|
+
isStaticCall: boolean,
|
|
603
|
+
gasSettings: GasSettings,
|
|
604
|
+
): Promise<Fr[]> {
|
|
605
|
+
const handler = this.handlerAsTxe();
|
|
606
|
+
return await this.withTopLevelCallTracking(async () => {
|
|
607
|
+
const returnValues = await handler.publicCallNewFlow(
|
|
608
|
+
from?.value,
|
|
609
|
+
targetContractAddress,
|
|
610
|
+
calldata,
|
|
611
|
+
isStaticCall,
|
|
612
|
+
gasSettings,
|
|
613
|
+
);
|
|
614
|
+
|
|
615
|
+
await this.cycleJob();
|
|
616
|
+
|
|
617
|
+
if (isStaticCall) {
|
|
618
|
+
// See the equivalent branch in `executePrivateCall`.
|
|
619
|
+
return { result: returnValues };
|
|
620
|
+
}
|
|
621
|
+
const { txHash } = await handler.getLastTxEffects();
|
|
622
|
+
return { result: returnValues, txHash: txHash.hash };
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress): Promise<Fr[][]> {
|
|
627
|
+
const handler = this.handlerAsTxe();
|
|
628
|
+
await handler.syncContractNonOracleMethod(contractAddress, scope, this.currentJobId);
|
|
629
|
+
// Cycle the job to commit the stores after the contract sync.
|
|
630
|
+
await this.cycleJob();
|
|
631
|
+
return handler.getPrivateEvents(selector, contractAddress, scope);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
private handlerAsTxe(): ITxeExecutionOracle {
|
|
635
|
+
if (!('isTxe' in this.oracleHandler)) {
|
|
636
|
+
throw new UnavailableOracleError('Txe');
|
|
637
|
+
}
|
|
638
|
+
return this.oracleHandler;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
setTxeOracleVersion(major: number, minor: number): void {
|
|
642
|
+
if (major !== TXE_ORACLE_VERSION_MAJOR) {
|
|
643
|
+
const hint =
|
|
644
|
+
major > TXE_ORACLE_VERSION_MAJOR
|
|
645
|
+
? 'The test was compiled with a newer version of Aztec.nr than your test environment supports. Upgrade your test environment to a compatible version.'
|
|
646
|
+
: '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.';
|
|
647
|
+
throw new Error(
|
|
648
|
+
`Incompatible test environment version: ${hint} See https://docs.aztec.network/errors/12 (expected test oracle major version ${TXE_ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
this.txeOracleVersion = { major, minor };
|
|
653
|
+
this.logger.debug(`Test compiled with test oracle version ${major}.${minor}`);
|
|
654
|
+
}
|
|
655
|
+
|
|
232
656
|
async enterTopLevelState() {
|
|
233
657
|
switch (this.state.name) {
|
|
234
658
|
case 'PRIVATE': {
|
|
@@ -251,17 +675,30 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
251
675
|
}
|
|
252
676
|
}
|
|
253
677
|
|
|
678
|
+
// Commit all staged stores from the job that was just completed, then begin a new job
|
|
679
|
+
await this.cycleJob();
|
|
680
|
+
|
|
254
681
|
this.oracleHandler = new TXEOracleTopLevelContext(
|
|
255
682
|
this.stateMachine,
|
|
256
|
-
this.
|
|
683
|
+
this.contractStore,
|
|
684
|
+
this.noteStore,
|
|
257
685
|
this.keyStore,
|
|
258
|
-
this.
|
|
259
|
-
this.
|
|
260
|
-
this.
|
|
686
|
+
this.addressStore,
|
|
687
|
+
this.accountStore,
|
|
688
|
+
this.senderTaggingStore,
|
|
689
|
+
this.recipientTaggingStore,
|
|
690
|
+
this.taggingSecretSourcesStore,
|
|
691
|
+
this.capsuleStore,
|
|
692
|
+
this.factStore,
|
|
693
|
+
this.privateEventStore,
|
|
261
694
|
this.nextBlockTimestamp,
|
|
262
695
|
this.version,
|
|
263
696
|
this.chainId,
|
|
264
697
|
this.authwits,
|
|
698
|
+
this.taggingSecretStrategy,
|
|
699
|
+
this.artifactResolver,
|
|
700
|
+
this.rootPath,
|
|
701
|
+
this.packageName,
|
|
265
702
|
);
|
|
266
703
|
|
|
267
704
|
this.state = { name: 'TOP_LEVEL' };
|
|
@@ -269,97 +706,186 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
269
706
|
}
|
|
270
707
|
|
|
271
708
|
async enterPrivateState(
|
|
272
|
-
|
|
273
|
-
|
|
709
|
+
contractAddressOpt: Option<AztecAddress>,
|
|
710
|
+
anchorBlockNumberOpt: Option<BlockNumber>,
|
|
711
|
+
gasSettings: GasSettings,
|
|
274
712
|
): Promise<PrivateContextInputs> {
|
|
713
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
714
|
+
const anchorBlockNumber = anchorBlockNumberOpt?.value;
|
|
275
715
|
this.exitTopLevelState();
|
|
276
|
-
|
|
277
|
-
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
278
|
-
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
279
|
-
// we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
|
|
280
|
-
// be removed from the database.
|
|
281
|
-
// TODO(#12553): make the synchronizer sync here instead and remove this
|
|
282
|
-
await this.pxeOracleInterface.syncNoteNullifiers(contractAddress);
|
|
716
|
+
this.resetLastCall();
|
|
283
717
|
|
|
284
718
|
// Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
|
|
285
719
|
// build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
|
|
286
720
|
// a single transaction with the effects of what was done in the test.
|
|
287
|
-
const anchorBlock = await this.stateMachine.node.
|
|
288
|
-
|
|
721
|
+
const anchorBlock = await this.stateMachine.node.getBlock(anchorBlockNumber ?? 'latest').then(b => b?.header);
|
|
722
|
+
|
|
723
|
+
await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
|
|
724
|
+
contractAddress,
|
|
725
|
+
await this.keyStore.getAccounts(),
|
|
726
|
+
);
|
|
727
|
+
const latestBlock = await this.stateMachine.node.getBlock('latest').then(b => b?.header);
|
|
289
728
|
|
|
290
729
|
const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
|
|
291
|
-
blockNumber: latestBlock!.globalVariables.blockNumber + 1,
|
|
730
|
+
blockNumber: BlockNumber(latestBlock!.globalVariables.blockNumber + 1),
|
|
292
731
|
timestamp: this.nextBlockTimestamp,
|
|
293
732
|
version: this.version,
|
|
294
733
|
chainId: this.chainId,
|
|
295
734
|
});
|
|
296
735
|
|
|
297
736
|
const txRequestHash = getSingleTxBlockRequestHash(nextBlockGlobalVariables.blockNumber);
|
|
298
|
-
const
|
|
737
|
+
const protocolNullifier = await computeProtocolNullifier(txRequestHash);
|
|
738
|
+
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
299
739
|
const taggingIndexCache = new ExecutionTaggingIndexCache();
|
|
300
740
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
741
|
+
const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
|
|
742
|
+
const transientArrayService = new TransientArrayService();
|
|
743
|
+
const anchoredContractData = new AnchoredContractData(
|
|
744
|
+
this.contractStore,
|
|
745
|
+
this.stateMachine.contractClassService,
|
|
305
746
|
anchorBlock!,
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
747
|
+
);
|
|
748
|
+
const taggingSecretStrategy = this.taggingSecretStrategy;
|
|
749
|
+
this.oracleHandler = new TXEPrivateExecutionOracle({
|
|
750
|
+
argsHash: Fr.ZERO,
|
|
751
|
+
txContext: new TxContext(this.chainId, this.version, gasSettings),
|
|
752
|
+
txRequestSalt: Fr.ZERO,
|
|
753
|
+
callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
|
|
754
|
+
anchorBlockHeader: anchorBlock!,
|
|
755
|
+
utilityExecutor,
|
|
756
|
+
authWitnesses: [],
|
|
757
|
+
capsules: [],
|
|
758
|
+
executionCache: new HashedValuesCache(),
|
|
309
759
|
noteCache,
|
|
310
760
|
taggingIndexCache,
|
|
311
|
-
|
|
312
|
-
|
|
761
|
+
anchoredContractData,
|
|
762
|
+
noteStore: this.noteStore,
|
|
763
|
+
keyStore: this.keyStore,
|
|
764
|
+
addressStore: this.addressStore,
|
|
765
|
+
aztecNode: this.stateMachine.node,
|
|
766
|
+
senderTaggingStore: this.senderTaggingStore,
|
|
767
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
768
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
769
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
770
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
771
|
+
privateEventStore: this.privateEventStore,
|
|
772
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
773
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
774
|
+
jobId: this.currentJobId,
|
|
775
|
+
scopes: await this.keyStore.getAccounts(),
|
|
776
|
+
txResolver: this.stateMachine.txResolver,
|
|
777
|
+
simulator: new WASMSimulator(),
|
|
778
|
+
hooks: composeHooks({
|
|
779
|
+
resolveTaggingSecretStrategy: taggingSecretStrategy ? () => Promise.resolve(taggingSecretStrategy) : undefined,
|
|
780
|
+
}),
|
|
781
|
+
transientArrayService,
|
|
782
|
+
});
|
|
313
783
|
|
|
314
784
|
// We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
|
|
315
785
|
// data) in order to refer to it later, mimicking the way this object is used by the ContractFunctionSimulator. The
|
|
316
786
|
// difference resides in that the simulator has all information needed in order to run the simulation, while ours
|
|
317
787
|
// will be ongoing as the different oracles will be invoked from the Noir test, until eventually the private
|
|
318
788
|
// execution finishes.
|
|
319
|
-
this.state = { name: 'PRIVATE', nextBlockGlobalVariables,
|
|
789
|
+
this.state = { name: 'PRIVATE', nextBlockGlobalVariables, noteCache, taggingIndexCache };
|
|
320
790
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
321
791
|
|
|
322
|
-
|
|
792
|
+
// Record the *resolved* anchor's timestamp — if the caller pinned the anchor to a past block
|
|
793
|
+
// via `anchorBlockNumber`, "latest" would be the wrong anchor for offchain-message semantics.
|
|
794
|
+
this.setLastCallContext(Fr.ZERO, anchorBlock!.globalVariables.timestamp);
|
|
795
|
+
|
|
796
|
+
return (this.oracleHandler as TXEPrivateExecutionOracle).getPrivateContextInputs();
|
|
323
797
|
}
|
|
324
798
|
|
|
325
|
-
async enterPublicState(
|
|
799
|
+
async enterPublicState(contractAddressOpt: Option<AztecAddress>) {
|
|
800
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
326
801
|
this.exitTopLevelState();
|
|
802
|
+
this.resetLastCall();
|
|
327
803
|
|
|
328
804
|
// The PublicContext will create a block with a single transaction in it, containing the effects of what was done in
|
|
329
805
|
// the test. The block therefore gets the *next* block number and timestamp.
|
|
330
|
-
const
|
|
806
|
+
const latestHeader = (await this.stateMachine.node.getBlockData('latest'))!.header;
|
|
331
807
|
const globalVariables = makeGlobalVariables(undefined, {
|
|
332
|
-
blockNumber:
|
|
808
|
+
blockNumber: BlockNumber(latestHeader.globalVariables.blockNumber + 1),
|
|
333
809
|
timestamp: this.nextBlockTimestamp,
|
|
334
810
|
version: this.version,
|
|
335
811
|
chainId: this.chainId,
|
|
336
812
|
});
|
|
337
813
|
|
|
338
814
|
this.oracleHandler = new TXEOraclePublicContext(
|
|
339
|
-
contractAddress
|
|
815
|
+
contractAddress,
|
|
340
816
|
await this.stateMachine.synchronizer.nativeWorldStateService.fork(),
|
|
341
817
|
getSingleTxBlockRequestHash(globalVariables.blockNumber),
|
|
342
818
|
globalVariables,
|
|
819
|
+
this.contractStore,
|
|
343
820
|
);
|
|
344
821
|
|
|
345
822
|
this.state = { name: 'PUBLIC' };
|
|
346
823
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
824
|
+
|
|
825
|
+
// Public state is anchored at the latest block.
|
|
826
|
+
this.setLastCallContext(Fr.ZERO, latestHeader.globalVariables.timestamp);
|
|
347
827
|
}
|
|
348
828
|
|
|
349
|
-
async enterUtilityState(
|
|
829
|
+
async enterUtilityState(contractAddressOpt: Option<AztecAddress>) {
|
|
830
|
+
const contractAddress = contractAddressOpt?.value ?? DEFAULT_ADDRESS;
|
|
350
831
|
this.exitTopLevelState();
|
|
832
|
+
this.resetLastCall();
|
|
833
|
+
|
|
834
|
+
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
351
835
|
|
|
352
836
|
// There is no automatic message discovery and contract-driven syncing process in inlined private or utility
|
|
353
837
|
// contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
|
|
354
838
|
// we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
|
|
355
839
|
// be removed from the database.
|
|
356
840
|
// TODO(#12553): make the synchronizer sync here instead and remove this
|
|
357
|
-
await
|
|
841
|
+
await new NoteService(
|
|
842
|
+
this.noteStore,
|
|
843
|
+
this.stateMachine.node,
|
|
844
|
+
anchorBlockHeader,
|
|
845
|
+
this.currentJobId,
|
|
846
|
+
).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts());
|
|
358
847
|
|
|
359
|
-
this.oracleHandler = new UtilityExecutionOracle(
|
|
848
|
+
this.oracleHandler = new UtilityExecutionOracle({
|
|
849
|
+
callContext: CallContext.from({
|
|
850
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
851
|
+
contractAddress,
|
|
852
|
+
// No specific function is being executed in this inlined utility context, hence the empty selector.
|
|
853
|
+
functionSelector: FunctionSelector.empty(),
|
|
854
|
+
isStaticCall: true,
|
|
855
|
+
}),
|
|
856
|
+
authWitnesses: [],
|
|
857
|
+
capsules: [],
|
|
858
|
+
anchorBlockHeader,
|
|
859
|
+
anchoredContractData: new AnchoredContractData(
|
|
860
|
+
this.contractStore,
|
|
861
|
+
this.stateMachine.contractClassService,
|
|
862
|
+
anchorBlockHeader,
|
|
863
|
+
),
|
|
864
|
+
noteStore: this.noteStore,
|
|
865
|
+
keyStore: this.keyStore,
|
|
866
|
+
addressStore: this.addressStore,
|
|
867
|
+
aztecNode: this.stateMachine.node,
|
|
868
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
869
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
870
|
+
capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()),
|
|
871
|
+
factService: new FactService(this.factStore, await this.keyStore.getAccounts()),
|
|
872
|
+
privateEventStore: this.privateEventStore,
|
|
873
|
+
txResolver: this.stateMachine.txResolver,
|
|
874
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
875
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
876
|
+
jobId: this.currentJobId,
|
|
877
|
+
scopes: await this.keyStore.getAccounts(),
|
|
878
|
+
simulator: new WASMSimulator(),
|
|
879
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlockHeader),
|
|
880
|
+
// Execution-tree root (top-level utility run): own store; nested frames inherit it.
|
|
881
|
+
transientArrayService: new TransientArrayService(),
|
|
882
|
+
});
|
|
360
883
|
|
|
361
884
|
this.state = { name: 'UTILITY' };
|
|
362
885
|
this.logger.debug(`Entered state ${this.state.name}`);
|
|
886
|
+
|
|
887
|
+
// Utility state anchors at whatever the anchor block store is pointing to (tracked as latest).
|
|
888
|
+
this.setLastCallContext(Fr.ZERO, anchorBlockHeader.globalVariables.timestamp);
|
|
363
889
|
}
|
|
364
890
|
|
|
365
891
|
private exitTopLevelState() {
|
|
@@ -368,15 +894,20 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
368
894
|
}
|
|
369
895
|
|
|
370
896
|
// Note that while all public and private contexts do is build a single block that we then process when exiting
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
// the
|
|
378
|
-
|
|
379
|
-
|
|
897
|
+
// them, the top level context does most of its work as it goes: it creates empty blocks (via `advanceBlocksBy`
|
|
898
|
+
// and `deploy`), creates blocks with transactions (via `privateCallNewFlow` and `publicCallNewFlow`), adds
|
|
899
|
+
// accounts to PXE (via `addAccount`), etc. This is a slight inconsistency in the working model of this class, but
|
|
900
|
+
// is not too bad. The `close` call below therefore only hands back the session-scoped values that a test
|
|
901
|
+
// sets directly at the top level, outside any contract execution (e.g. via `advanceTimestampBy`,
|
|
902
|
+
// `addAuthWitness`, `setTaggingSecretStrategy`). The oracle handler is discarded on every state transition,
|
|
903
|
+
// so the session must seed these values into the contexts it creates later.
|
|
904
|
+
|
|
905
|
+
// TODO: persisting authwits this way is quite unfortunate: they create a temporary utility context that would
|
|
906
|
+
// otherwise reset them, so we'd not be able to pass more than one per execution. Ideally authwits would be passed
|
|
907
|
+
// alongside a contract call instead of pre-seeded.
|
|
908
|
+
[this.nextBlockTimestamp, this.authwits, this.taggingSecretStrategy] = (
|
|
909
|
+
this.oracleHandler as TXEOracleTopLevelContext
|
|
910
|
+
).close();
|
|
380
911
|
}
|
|
381
912
|
|
|
382
913
|
private async exitPrivateState() {
|
|
@@ -390,21 +921,14 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
390
921
|
|
|
391
922
|
// We rely on the note cache to determine the effects of the transaction. This is incomplete as it doesn't private
|
|
392
923
|
// logs (other effects like enqueued public calls don't need to be considered since those are not allowed).
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
this.state.txRequestHash,
|
|
396
|
-
this.state.nextBlockGlobalVariables.blockNumber,
|
|
397
|
-
);
|
|
924
|
+
|
|
925
|
+
const txEffect = await makeTxEffect(this.state.noteCache, this.state.nextBlockGlobalVariables.blockNumber);
|
|
398
926
|
|
|
399
927
|
// We build a block holding just this transaction
|
|
400
928
|
const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
|
|
401
929
|
await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
|
|
402
930
|
|
|
403
|
-
const block =
|
|
404
|
-
makeAppendOnlyTreeSnapshot(),
|
|
405
|
-
await makeTXEBlockHeader(forkedWorldTrees, this.state.nextBlockGlobalVariables),
|
|
406
|
-
new Body([txEffect]),
|
|
407
|
-
);
|
|
931
|
+
const block = await makeTXEBlock(forkedWorldTrees, this.state.nextBlockGlobalVariables, [txEffect]);
|
|
408
932
|
await this.stateMachine.handleL2Block(block);
|
|
409
933
|
|
|
410
934
|
await forkedWorldTrees.close();
|
|
@@ -429,4 +953,74 @@ export class TXESession implements TXESessionStateHandler {
|
|
|
429
953
|
throw new Error(`Expected to be in state 'UTILITY', but got '${this.state.name}' instead`);
|
|
430
954
|
}
|
|
431
955
|
}
|
|
956
|
+
|
|
957
|
+
private utilityExecutorForContractSync(anchorBlock: any) {
|
|
958
|
+
return async (call: FunctionCall, scopes: AztecAddress[]) => {
|
|
959
|
+
const anchoredContractData = new AnchoredContractData(
|
|
960
|
+
this.contractStore,
|
|
961
|
+
this.stateMachine.contractClassService,
|
|
962
|
+
anchorBlock!,
|
|
963
|
+
);
|
|
964
|
+
const entryPointArtifact = await anchoredContractData.getFunctionArtifactWithDebugMetadata(
|
|
965
|
+
call.to,
|
|
966
|
+
call.selector,
|
|
967
|
+
);
|
|
968
|
+
if (!entryPointArtifact) {
|
|
969
|
+
throw new Error(`Cannot run function ${call.selector} on ${call.to}: the contract is not registered.`);
|
|
970
|
+
}
|
|
971
|
+
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
972
|
+
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
try {
|
|
976
|
+
const simulator = new WASMSimulator();
|
|
977
|
+
const oracle = new UtilityExecutionOracle({
|
|
978
|
+
callContext: CallContext.from({
|
|
979
|
+
msgSender: AztecAddress.NULL_MSG_SENDER,
|
|
980
|
+
contractAddress: call.to,
|
|
981
|
+
functionSelector: call.selector,
|
|
982
|
+
isStaticCall: true,
|
|
983
|
+
}),
|
|
984
|
+
authWitnesses: [],
|
|
985
|
+
capsules: [],
|
|
986
|
+
anchorBlockHeader: anchorBlock!,
|
|
987
|
+
anchoredContractData,
|
|
988
|
+
noteStore: this.noteStore,
|
|
989
|
+
keyStore: this.keyStore,
|
|
990
|
+
addressStore: this.addressStore,
|
|
991
|
+
aztecNode: this.stateMachine.node,
|
|
992
|
+
recipientTaggingStore: this.recipientTaggingStore,
|
|
993
|
+
taggingSecretSourcesStore: this.taggingSecretSourcesStore,
|
|
994
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
995
|
+
factService: new FactService(this.factStore, scopes),
|
|
996
|
+
privateEventStore: this.privateEventStore,
|
|
997
|
+
txResolver: this.stateMachine.txResolver,
|
|
998
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
999
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
1000
|
+
jobId: this.currentJobId,
|
|
1001
|
+
scopes,
|
|
1002
|
+
simulator,
|
|
1003
|
+
utilityExecutor: this.utilityExecutorForContractSync(anchorBlock),
|
|
1004
|
+
// Top-level utility entrypoint: gets a fresh store. Nested frames inherit it via UtilityExecutionOracle.
|
|
1005
|
+
transientArrayService: new TransientArrayService(),
|
|
1006
|
+
});
|
|
1007
|
+
await simulator
|
|
1008
|
+
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, buildACIRCallback(oracle))
|
|
1009
|
+
.catch((err: Error) => {
|
|
1010
|
+
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
1011
|
+
throw new ExecutionError(
|
|
1012
|
+
err.message,
|
|
1013
|
+
{
|
|
1014
|
+
contractAddress: call.to,
|
|
1015
|
+
functionSelector: call.selector,
|
|
1016
|
+
},
|
|
1017
|
+
extractCallStack(err, entryPointArtifact.debug),
|
|
1018
|
+
{ cause: err },
|
|
1019
|
+
);
|
|
1020
|
+
});
|
|
1021
|
+
} catch (err) {
|
|
1022
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error contract data sync'));
|
|
1023
|
+
}
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
432
1026
|
}
|