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