@aztec/txe 0.0.1-commit.b6e433891 → 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.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 +5 -1
- package/dest/constants.d.ts.map +1 -1
- package/dest/constants.js +8 -0
- package/dest/dispatcher_pool.d.ts +67 -0
- package/dest/dispatcher_pool.d.ts.map +1 -0
- package/dest/dispatcher_pool.js +284 -0
- package/dest/index.d.ts +185 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +70 -190
- package/dest/metafile.json +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 +33 -8
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
- package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
- package/dest/oracle/test-resolver/fixtures.js +39 -0
- package/dest/oracle/test-resolver/index.d.ts +9 -0
- package/dest/oracle/test-resolver/index.d.ts.map +1 -0
- package/dest/oracle/test-resolver/index.js +33 -0
- package/dest/oracle/test-resolver/resolver.d.ts +34 -0
- package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
- package/dest/oracle/test-resolver/resolver.js +114 -0
- package/dest/oracle/txe_oracle_public_context.d.ts +26 -2
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +43 -1
- package/dest/oracle/txe_oracle_registry.d.ts +147 -0
- package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
- package/dest/oracle/txe_oracle_registry.js +562 -0
- package/dest/oracle/txe_oracle_top_level_context.d.ts +33 -14
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +149 -60
- 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 -233
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +706 -637
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +4 -3
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +26 -15
- package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +16 -4
- package/dest/state_machine/global_variable_builder.d.ts +9 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +9 -3
- package/dest/state_machine/index.d.ts +4 -2
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +17 -3
- package/dest/state_machine/mock_epoch_cache.d.ts +1 -2
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +0 -3
- package/dest/state_machine/synchronizer.js +1 -1
- package/dest/txe_session.d.ts +75 -14
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +170 -41
- package/dest/utils/encoding.d.ts +191 -0
- package/dest/utils/encoding.d.ts.map +1 -0
- package/dest/{util → utils}/encoding.js +7 -2
- package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
- package/dest/utils/expected_failure_error.d.ts.map +1 -0
- package/dest/{util → utils}/txe_account_store.d.ts +1 -1
- package/dest/utils/txe_account_store.d.ts.map +1 -0
- package/dest/utils/txe_artifact_resolver.d.ts +37 -0
- package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
- package/dest/utils/txe_artifact_resolver.js +161 -0
- package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
- package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
- package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
- package/dest/worker.bundle.js +3 -0
- package/dest/worker.bundle.js.map +7 -0
- package/dest/worker.d.ts +2 -0
- package/dest/worker.d.ts.map +1 -0
- package/dest/worker.js +92 -0
- package/package.json +38 -21
- package/src/bin/check_txe_oracle_version.ts +70 -0
- package/src/bin/index.ts +11 -2
- package/src/bin/oracle_test_server.ts +51 -0
- package/src/constants.ts +10 -0
- package/src/dispatcher_pool.ts +316 -0
- package/src/index.ts +97 -227
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +29 -7
- package/src/oracle/test-resolver/fixtures.ts +84 -0
- package/src/oracle/test-resolver/index.ts +45 -0
- package/src/oracle/test-resolver/resolver.ts +165 -0
- package/src/oracle/txe_oracle_public_context.ts +60 -0
- package/src/oracle/txe_oracle_registry.ts +401 -0
- package/src/oracle/txe_oracle_top_level_context.ts +180 -67
- 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 +787 -925
- package/src/state_machine/archiver.ts +38 -16
- package/src/state_machine/dummy_p2p_client.ts +31 -11
- package/src/state_machine/global_variable_builder.ts +18 -3
- package/src/state_machine/index.ts +20 -5
- package/src/state_machine/mock_epoch_cache.ts +0 -4
- package/src/state_machine/synchronizer.ts +1 -1
- package/src/txe_session.ts +278 -45
- package/src/{util → utils}/encoding.ts +8 -2
- package/src/utils/txe_artifact_resolver.ts +217 -0
- package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
- package/src/worker.ts +98 -0
- package/dest/util/encoding.d.ts +0 -720
- package/dest/util/encoding.d.ts.map +0 -1
- package/dest/util/expected_failure_error.d.ts.map +0 -1
- package/dest/util/txe_account_store.d.ts.map +0 -1
- package/dest/util/txe_public_contract_data_source.d.ts +0 -20
- package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
- /package/dest/{util → utils}/expected_failure_error.js +0 -0
- /package/dest/{util → utils}/txe_account_store.js +0 -0
- /package/src/{util → utils}/expected_failure_error.ts +0 -0
- /package/src/{util → utils}/txe_account_store.ts +0 -0
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
3
|
-
|
|
4
|
-
DEFAULT_L2_GAS_LIMIT,
|
|
5
|
-
DEFAULT_TEARDOWN_DA_GAS_LIMIT,
|
|
6
|
-
DEFAULT_TEARDOWN_L2_GAS_LIMIT,
|
|
3
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
7
4
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
8
5
|
} from '@aztec/constants';
|
|
9
6
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
@@ -12,18 +9,19 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
12
9
|
import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
13
10
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
14
11
|
import type { KeyStore } from '@aztec/key-store';
|
|
15
|
-
import type { AccessScopes } from '@aztec/pxe/client/lazy';
|
|
16
12
|
import {
|
|
17
13
|
AddressStore,
|
|
14
|
+
CapsuleService,
|
|
18
15
|
CapsuleStore,
|
|
19
16
|
type ContractStore,
|
|
20
|
-
type
|
|
17
|
+
type ExecutionHooks,
|
|
21
18
|
NoteStore,
|
|
22
|
-
|
|
19
|
+
ORACLE_VERSION_MAJOR,
|
|
23
20
|
PrivateEventStore,
|
|
24
21
|
RecipientTaggingStore,
|
|
25
22
|
SenderAddressBookStore,
|
|
26
23
|
SenderTaggingStore,
|
|
24
|
+
composeHooks,
|
|
27
25
|
enrichPublicSimulationError,
|
|
28
26
|
} from '@aztec/pxe/server';
|
|
29
27
|
import {
|
|
@@ -47,10 +45,10 @@ import {
|
|
|
47
45
|
witnessMapToFields,
|
|
48
46
|
} from '@aztec/simulator/client';
|
|
49
47
|
import {
|
|
50
|
-
CppPublicTxSimulator,
|
|
51
48
|
GuardedMerkleTreeOperations,
|
|
52
49
|
PublicContractsDB,
|
|
53
50
|
PublicProcessor,
|
|
51
|
+
PublicTxSimulator,
|
|
54
52
|
} from '@aztec/simulator/server';
|
|
55
53
|
import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
|
|
56
54
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
@@ -65,6 +63,7 @@ import {
|
|
|
65
63
|
PrivateToPublicAccumulatedData,
|
|
66
64
|
PublicCallRequest,
|
|
67
65
|
} from '@aztec/stdlib/kernel';
|
|
66
|
+
import { hashPublicKey } from '@aztec/stdlib/keys';
|
|
68
67
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
69
68
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
70
69
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
@@ -81,13 +80,14 @@ import {
|
|
|
81
80
|
collectNested,
|
|
82
81
|
} from '@aztec/stdlib/tx';
|
|
83
82
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
84
|
-
import { ForkCheckpoint } from '@aztec/world-state';
|
|
83
|
+
import { ForkCheckpoint } from '@aztec/world-state/native';
|
|
85
84
|
|
|
86
|
-
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
85
|
+
import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
|
|
87
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
88
|
-
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
89
|
-
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
90
87
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
88
|
+
import type { TXEAccountStore } from '../utils/txe_account_store.js';
|
|
89
|
+
import type { TXEArtifactResolver } from '../utils/txe_artifact_resolver.js';
|
|
90
|
+
import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
|
|
91
91
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
92
92
|
|
|
93
93
|
export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
|
|
@@ -112,18 +112,32 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
112
112
|
private version: Fr,
|
|
113
113
|
private chainId: Fr,
|
|
114
114
|
private authwits: Map<string, AuthWitness>,
|
|
115
|
-
private readonly
|
|
115
|
+
private readonly artifactResolver: TXEArtifactResolver,
|
|
116
|
+
private readonly rootPath: string,
|
|
117
|
+
private readonly packageName: string,
|
|
116
118
|
) {
|
|
117
119
|
this.logger = createLogger('txe:top_level_context');
|
|
118
120
|
this.logger.debug('Entering Top Level Context');
|
|
119
121
|
}
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
+
private contractOracleVersion: { major: number; minor: number } | undefined;
|
|
124
|
+
|
|
125
|
+
assertCompatibleOracleVersion(major: number, minor: number): void {
|
|
126
|
+
if (major !== ORACLE_VERSION_MAJOR) {
|
|
127
|
+
const hint =
|
|
128
|
+
major > ORACLE_VERSION_MAJOR
|
|
129
|
+
? 'The contract was compiled with a newer version of Aztec.nr than this aztec cli version supports. Upgrade your aztec cli version to a compatible version.'
|
|
130
|
+
: 'The contract was compiled with an older version of Aztec.nr than this aztec cli version supports. Recompile the contract with a compatible version of Aztec.nr.';
|
|
123
131
|
throw new Error(
|
|
124
|
-
`Incompatible
|
|
132
|
+
`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
125
133
|
);
|
|
126
134
|
}
|
|
135
|
+
this.contractOracleVersion = { major, minor };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
|
|
139
|
+
nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
|
|
140
|
+
return this.contractOracleVersion;
|
|
127
141
|
}
|
|
128
142
|
|
|
129
143
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
@@ -133,7 +147,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
133
147
|
}
|
|
134
148
|
|
|
135
149
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
136
|
-
log(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
150
|
+
log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
|
|
137
151
|
if (!LogLevels[level]) {
|
|
138
152
|
throw new Error(`Invalid log level: ${level}`);
|
|
139
153
|
}
|
|
@@ -156,12 +170,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
156
170
|
}
|
|
157
171
|
|
|
158
172
|
async getLastBlockTimestamp() {
|
|
159
|
-
return (await this.stateMachine.node.
|
|
173
|
+
return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
|
|
160
174
|
}
|
|
161
175
|
|
|
162
176
|
async getLastTxEffects() {
|
|
163
177
|
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
164
|
-
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
178
|
+
const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
|
|
165
179
|
|
|
166
180
|
if (block!.body.txEffects.length != 1) {
|
|
167
181
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
@@ -170,7 +184,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
170
184
|
|
|
171
185
|
const txEffects = block!.body.txEffects[0];
|
|
172
186
|
|
|
173
|
-
|
|
187
|
+
const privateLogs = txEffects.privateLogs;
|
|
188
|
+
if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
|
|
189
|
+
throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
txHash: txEffects.txHash,
|
|
194
|
+
noteHashes: txEffects.noteHashes,
|
|
195
|
+
nullifiers: txEffects.nullifiers,
|
|
196
|
+
privateLogs,
|
|
197
|
+
};
|
|
174
198
|
}
|
|
175
199
|
|
|
176
200
|
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
@@ -193,7 +217,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
193
217
|
}
|
|
194
218
|
|
|
195
219
|
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
196
|
-
|
|
220
|
+
const events = (
|
|
197
221
|
await this.privateEventStore.getPrivateEvents(selector, {
|
|
198
222
|
contractAddress,
|
|
199
223
|
scopes: [scope],
|
|
@@ -201,6 +225,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
201
225
|
toBlock: (await this.getLastBlockNumber()) + 1,
|
|
202
226
|
})
|
|
203
227
|
).map(e => e.packedEvent);
|
|
228
|
+
|
|
229
|
+
if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
|
|
230
|
+
throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
|
|
231
|
+
}
|
|
232
|
+
if (events.some(e => e.length > MAX_PRIVATE_EVENT_LEN)) {
|
|
233
|
+
throw new Error(`Some private event has length larger than maxLen ${MAX_PRIVATE_EVENT_LEN}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return events;
|
|
204
237
|
}
|
|
205
238
|
|
|
206
239
|
async advanceBlocksBy(blocks: number) {
|
|
@@ -216,27 +249,71 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
216
249
|
this.nextBlockTimestamp += duration;
|
|
217
250
|
}
|
|
218
251
|
|
|
219
|
-
|
|
252
|
+
private deploymentNullifier(address: AztecAddress): Promise<Fr> {
|
|
253
|
+
return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async deploy(
|
|
257
|
+
contractPath: string,
|
|
258
|
+
initializer: string,
|
|
259
|
+
args: Fr[],
|
|
260
|
+
secret: Fr,
|
|
261
|
+
salt: Fr,
|
|
262
|
+
deployer: AztecAddress,
|
|
263
|
+
): Promise<Fr[]> {
|
|
264
|
+
const { artifact, instance } = await this.artifactResolver.resolveDeployArtifact({
|
|
265
|
+
rootPath: this.rootPath,
|
|
266
|
+
packageName: this.packageName,
|
|
267
|
+
contractPath,
|
|
268
|
+
initializer,
|
|
269
|
+
args,
|
|
270
|
+
secret,
|
|
271
|
+
salt,
|
|
272
|
+
deployer,
|
|
273
|
+
});
|
|
274
|
+
|
|
220
275
|
// Emit deployment nullifier
|
|
221
276
|
await this.mineBlock({
|
|
222
|
-
nullifiers: [
|
|
223
|
-
await siloNullifier(
|
|
224
|
-
AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
|
|
225
|
-
instance.address.toField(),
|
|
226
|
-
),
|
|
227
|
-
],
|
|
277
|
+
nullifiers: [await this.deploymentNullifier(instance.address)],
|
|
228
278
|
});
|
|
229
279
|
|
|
230
280
|
if (!secret.equals(Fr.ZERO)) {
|
|
231
|
-
await this.
|
|
281
|
+
await this.registerContractAndAddAccount(artifact, instance, secret);
|
|
232
282
|
} else {
|
|
233
283
|
await this.contractStore.addContractInstance(instance);
|
|
234
284
|
await this.contractStore.addContractArtifact(artifact);
|
|
235
285
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
236
286
|
}
|
|
287
|
+
|
|
288
|
+
return [
|
|
289
|
+
instance.salt,
|
|
290
|
+
instance.deployer.toField(),
|
|
291
|
+
instance.currentContractClassId,
|
|
292
|
+
instance.initializationHash,
|
|
293
|
+
instance.immutablesHash,
|
|
294
|
+
...instance.publicKeys.toFields(),
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
|
|
300
|
+
*/
|
|
301
|
+
async mineDeploymentNullifiers(addresses: AztecAddress[]) {
|
|
302
|
+
await this.mineBlock({
|
|
303
|
+
nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async addAccount(secret: Fr) {
|
|
308
|
+
const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
|
|
309
|
+
return this.registerContractAndAddAccount(artifact, instance, secret);
|
|
237
310
|
}
|
|
238
311
|
|
|
239
|
-
async
|
|
312
|
+
private async registerContractAndAddAccount(
|
|
313
|
+
artifact: ContractArtifact,
|
|
314
|
+
instance: ContractInstanceWithAddress,
|
|
315
|
+
secret: Fr,
|
|
316
|
+
) {
|
|
240
317
|
const partialAddress = await computePartialAddress(instance);
|
|
241
318
|
|
|
242
319
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
@@ -263,12 +340,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
263
340
|
|
|
264
341
|
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
265
342
|
const account = await this.accountStore.getAccount(address);
|
|
266
|
-
const
|
|
343
|
+
const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
|
|
344
|
+
const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
|
|
267
345
|
|
|
268
346
|
const schnorr = new Schnorr();
|
|
269
|
-
const signature = await schnorr.constructSignature(messageHash
|
|
347
|
+
const signature = await schnorr.constructSignature(messageHash, privateKey);
|
|
270
348
|
|
|
271
|
-
const authWitness = new AuthWitness(messageHash,
|
|
349
|
+
const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
|
|
272
350
|
|
|
273
351
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
274
352
|
}
|
|
@@ -299,13 +377,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
299
377
|
}
|
|
300
378
|
|
|
301
379
|
async privateCallNewFlow(
|
|
302
|
-
from: AztecAddress,
|
|
380
|
+
from: AztecAddress | undefined,
|
|
303
381
|
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
304
382
|
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
305
383
|
args: Fr[],
|
|
306
384
|
argsHash: Fr = Fr.zero(),
|
|
307
385
|
isStaticCall: boolean = false,
|
|
386
|
+
additionalScopes: AztecAddress[] = [],
|
|
308
387
|
jobId: string,
|
|
388
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
389
|
+
gasSettings: GasSettings,
|
|
309
390
|
) {
|
|
310
391
|
this.logger.verbose(
|
|
311
392
|
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -319,12 +400,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
319
400
|
throw new Error(message);
|
|
320
401
|
}
|
|
321
402
|
|
|
322
|
-
|
|
323
|
-
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
324
|
-
const effectiveScopes = from.isZero() ? [] : [from];
|
|
403
|
+
const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
|
|
325
404
|
|
|
326
405
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
327
|
-
const utilityExecutor = async (call: FunctionCall, execScopes:
|
|
406
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
|
|
328
407
|
await this.executeUtilityCall(call, execScopes, jobId);
|
|
329
408
|
};
|
|
330
409
|
|
|
@@ -335,16 +414,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
335
414
|
utilityExecutor,
|
|
336
415
|
blockHeader,
|
|
337
416
|
jobId,
|
|
338
|
-
|
|
417
|
+
scopes,
|
|
339
418
|
);
|
|
340
419
|
|
|
341
420
|
const blockNumber = await this.getNextBlockNumber();
|
|
342
421
|
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
346
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
347
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
422
|
+
const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
|
|
423
|
+
const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
|
|
348
424
|
|
|
349
425
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
350
426
|
|
|
@@ -378,18 +454,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
378
454
|
senderTaggingStore: this.senderTaggingStore,
|
|
379
455
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
380
456
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
381
|
-
|
|
457
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
382
458
|
privateEventStore: this.privateEventStore,
|
|
383
459
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
384
460
|
jobId,
|
|
385
461
|
totalPublicCalldataCount: 0,
|
|
386
462
|
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
387
|
-
scopes
|
|
463
|
+
scopes,
|
|
388
464
|
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
389
465
|
// contract would perform, including setting senderForTags.
|
|
390
466
|
senderForTags: from,
|
|
391
467
|
simulator,
|
|
392
468
|
messageContextService: this.stateMachine.messageContextService,
|
|
469
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
470
|
+
hooks: composeHooks({
|
|
471
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
|
|
472
|
+
isStaticCall ? 'private view' : 'private',
|
|
473
|
+
authorizedUtilityCallTargets,
|
|
474
|
+
),
|
|
475
|
+
}),
|
|
393
476
|
});
|
|
394
477
|
|
|
395
478
|
// Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
|
|
@@ -412,7 +495,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
412
495
|
);
|
|
413
496
|
const publicFunctionsCalldata = await Promise.all(
|
|
414
497
|
publicCallRequests.map(async r => {
|
|
415
|
-
const calldata = await privateExecutionOracle.
|
|
498
|
+
const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
|
|
416
499
|
return new HashedValues(calldata, r.calldataHash);
|
|
417
500
|
}),
|
|
418
501
|
);
|
|
@@ -460,7 +543,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
460
543
|
globals,
|
|
461
544
|
guardedMerkleTrees,
|
|
462
545
|
contractsDB,
|
|
463
|
-
new
|
|
546
|
+
new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
|
|
464
547
|
new TestDateProvider(),
|
|
465
548
|
undefined,
|
|
466
549
|
createLogger('simulator:public-processor', bindings),
|
|
@@ -497,11 +580,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
497
580
|
}
|
|
498
581
|
}
|
|
499
582
|
|
|
583
|
+
// Walk the nested private-call tree and collect every offchain effect the transaction emitted.
|
|
584
|
+
// PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
|
|
585
|
+
// `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
|
|
586
|
+
// we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
|
|
587
|
+
const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
|
|
588
|
+
|
|
500
589
|
if (isStaticCall) {
|
|
501
590
|
await checkpoint!.revert();
|
|
502
591
|
|
|
503
592
|
await forkedWorldTrees.close();
|
|
504
|
-
return executionResult.returnValues ?? [];
|
|
593
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
505
594
|
}
|
|
506
595
|
|
|
507
596
|
const txEffect = TxEffect.empty();
|
|
@@ -523,14 +612,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
523
612
|
|
|
524
613
|
await forkedWorldTrees.close();
|
|
525
614
|
|
|
526
|
-
return executionResult.returnValues ?? [];
|
|
615
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
527
616
|
}
|
|
528
617
|
|
|
529
618
|
async publicCallNewFlow(
|
|
530
|
-
from: AztecAddress,
|
|
619
|
+
from: AztecAddress | undefined,
|
|
531
620
|
targetContractAddress: AztecAddress,
|
|
532
621
|
calldata: Fr[],
|
|
533
622
|
isStaticCall: boolean,
|
|
623
|
+
gasSettings: GasSettings,
|
|
534
624
|
) {
|
|
535
625
|
this.logger.verbose(
|
|
536
626
|
`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -538,12 +628,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
538
628
|
|
|
539
629
|
const blockNumber = await this.getNextBlockNumber();
|
|
540
630
|
|
|
541
|
-
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
542
|
-
|
|
543
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
544
|
-
|
|
545
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
546
|
-
|
|
547
631
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
548
632
|
|
|
549
633
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
@@ -573,7 +657,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
573
657
|
collectStatistics: false,
|
|
574
658
|
collectCallMetadata: true,
|
|
575
659
|
});
|
|
576
|
-
const simulator = new
|
|
660
|
+
const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
|
|
577
661
|
const processor = new PublicProcessor(
|
|
578
662
|
globals,
|
|
579
663
|
guardedMerkleTrees,
|
|
@@ -595,7 +679,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
595
679
|
// may require producing reverts.
|
|
596
680
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
597
681
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
|
|
598
|
-
from,
|
|
682
|
+
from ?? AztecAddress.NULL_MSG_SENDER,
|
|
599
683
|
targetContractAddress,
|
|
600
684
|
isStaticCall,
|
|
601
685
|
calldataHash,
|
|
@@ -686,6 +770,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
686
770
|
functionSelector: FunctionSelector,
|
|
687
771
|
args: Fr[],
|
|
688
772
|
jobId: string,
|
|
773
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
689
774
|
) {
|
|
690
775
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
691
776
|
if (!artifact) {
|
|
@@ -702,7 +787,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
702
787
|
},
|
|
703
788
|
blockHeader,
|
|
704
789
|
jobId,
|
|
705
|
-
|
|
790
|
+
await this.keyStore.getAccounts(),
|
|
706
791
|
);
|
|
707
792
|
|
|
708
793
|
const call = FunctionCall.from({
|
|
@@ -716,10 +801,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
716
801
|
returnTypes: [],
|
|
717
802
|
});
|
|
718
803
|
|
|
719
|
-
return this.executeUtilityCall(call,
|
|
804
|
+
return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
|
|
720
805
|
}
|
|
721
806
|
|
|
722
|
-
private async executeUtilityCall(
|
|
807
|
+
private async executeUtilityCall(
|
|
808
|
+
call: FunctionCall,
|
|
809
|
+
scopes: AztecAddress[],
|
|
810
|
+
jobId: string,
|
|
811
|
+
authorizedUtilityCallTargets: AztecAddress[] = [],
|
|
812
|
+
): Promise<Fr[]> {
|
|
723
813
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
724
814
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
725
815
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -732,6 +822,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
732
822
|
|
|
733
823
|
try {
|
|
734
824
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
825
|
+
const simulator = new WASMSimulator();
|
|
826
|
+
const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
|
|
827
|
+
await this.executeUtilityCall(syncCall, execScopes, jobId);
|
|
828
|
+
};
|
|
735
829
|
const oracle = new UtilityExecutionOracle({
|
|
736
830
|
contractAddress: call.to,
|
|
737
831
|
authWitnesses: [],
|
|
@@ -744,14 +838,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
744
838
|
aztecNode: this.stateMachine.node,
|
|
745
839
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
746
840
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
747
|
-
|
|
841
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
748
842
|
privateEventStore: this.privateEventStore,
|
|
749
843
|
messageContextService: this.stateMachine.messageContextService,
|
|
750
|
-
contractSyncService: this.contractSyncService,
|
|
844
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
845
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
751
846
|
jobId,
|
|
752
847
|
scopes,
|
|
848
|
+
simulator,
|
|
849
|
+
hooks: composeHooks({
|
|
850
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
|
|
851
|
+
}),
|
|
852
|
+
utilityExecutor,
|
|
753
853
|
});
|
|
754
|
-
const acirExecutionResult = await
|
|
854
|
+
const acirExecutionResult = await simulator
|
|
755
855
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
756
856
|
.catch((err: Error) => {
|
|
757
857
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
@@ -779,7 +879,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
779
879
|
}
|
|
780
880
|
|
|
781
881
|
private async getLastBlockNumber(): Promise<BlockNumber> {
|
|
782
|
-
const
|
|
783
|
-
return
|
|
882
|
+
const block = await this.stateMachine.node.getBlock('latest');
|
|
883
|
+
return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
private buildAuthorizeUtilityCallHook(
|
|
887
|
+
callerContext: 'private' | 'private view' | 'utility',
|
|
888
|
+
authorizedTargets: AztecAddress[],
|
|
889
|
+
): ExecutionHooks['authorizeUtilityCall'] | undefined {
|
|
890
|
+
if (authorizedTargets.length === 0) {
|
|
891
|
+
return undefined;
|
|
892
|
+
}
|
|
893
|
+
return req =>
|
|
894
|
+
Promise.resolve({
|
|
895
|
+
authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
|
|
896
|
+
});
|
|
784
897
|
}
|
|
785
898
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The TXE oracle version constants are used to check that the oracle interface used for tests is in sync between
|
|
3
|
+
* TXE and Aztec.nr. This is separate from the contract oracle version in `pxe/src/oracle_version.ts`, which covers
|
|
4
|
+
* oracles used during contract execution by PXE.
|
|
5
|
+
*
|
|
6
|
+
* The Noir counterparts are in `noir-projects/aztec-nr/aztec/src/test/helpers/txe_oracles.nr`.
|
|
7
|
+
*/
|
|
8
|
+
export const TXE_ORACLE_VERSION_MAJOR = 1;
|
|
9
|
+
export const TXE_ORACLE_VERSION_MINOR = 2;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* This hash is computed from the TXE oracle interfaces (IAvmExecutionOracle and ITxeExecutionOracle) and is used to
|
|
13
|
+
* detect when those interfaces change. When it does, bump:
|
|
14
|
+
* - TXE_ORACLE_VERSION_MAJOR (and reset MINOR to 0) for breaking changes, or
|
|
15
|
+
* - TXE_ORACLE_VERSION_MINOR for additive changes (new oracle method added).
|
|
16
|
+
*/
|
|
17
|
+
export const TXE_ORACLE_INTERFACE_HASH = '9e5f6ad5fd170d1de5ddd417f19cce47b17382567e08360dc6a783154828e218';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
+
import { PrivateExecutionOracle } from '@aztec/pxe/simulator';
|
|
3
|
+
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
4
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
|
|
8
|
+
* TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
|
|
9
|
+
*/
|
|
10
|
+
export class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
|
|
11
|
+
override callPrivateFunction(
|
|
12
|
+
_targetContractAddress: AztecAddress,
|
|
13
|
+
_functionSelector: FunctionSelector,
|
|
14
|
+
_argsHash: Fr,
|
|
15
|
+
_sideEffectCounter: number,
|
|
16
|
+
_isStaticCall: boolean,
|
|
17
|
+
): Promise<{ endSideEffectCounter: Fr; returnsHash: Fr }> {
|
|
18
|
+
throw new Error(
|
|
19
|
+
'Contract calls are forbidden inside a `TestEnvironment::private_context`, use `private_call` instead',
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
override assertValidPublicCalldata(_calldataHash: Fr): Promise<void> {
|
|
24
|
+
throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter: number): Promise<void> {
|
|
28
|
+
throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
2
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
3
|
+
|
|
4
|
+
import type { Socket } from 'node:net';
|
|
5
|
+
|
|
6
|
+
import { TXEDispatcherPool, buildSharedContractStore } from './dispatcher_pool.js';
|
|
7
|
+
import { TXEDispatcher, TXEDispatcherApiSchema } from './index.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Symbol used to tag an incoming TCP socket with the `session_id` it has been associated with.
|
|
11
|
+
* Hidden under a Symbol so we don't risk colliding with anything koa or http core adds.
|
|
12
|
+
*/
|
|
13
|
+
const SESSION_SYMBOL = Symbol('txeSessionId');
|
|
14
|
+
|
|
15
|
+
type TaggedSocket = Socket & { [SESSION_SYMBOL]?: number };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
|
|
19
|
+
* worker_threads, no IPC overhead). With any other value oracle calls are
|
|
20
|
+
* routed to a pool of worker threads sized to that value, sticky by `session_id`.
|
|
21
|
+
*
|
|
22
|
+
* Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
|
|
23
|
+
* nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
|
|
24
|
+
* closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
|
|
25
|
+
*
|
|
26
|
+
* Lives in its own module so the worker bundle does not pull in the HTTP server stack.
|
|
27
|
+
*/
|
|
28
|
+
export async function createTXERpcServer(logger: Logger) {
|
|
29
|
+
const workerCount = Number(process.env.TXE_WORKERS);
|
|
30
|
+
let dispatcher: TXEDispatcher | TXEDispatcherPool;
|
|
31
|
+
if (workerCount === 1) {
|
|
32
|
+
const { dataDir, schnorrClassId } = await buildSharedContractStore();
|
|
33
|
+
dispatcher = new TXEDispatcher(logger, { contractStoreSourceDir: dataDir, schnorrClassId });
|
|
34
|
+
} else {
|
|
35
|
+
dispatcher = new TXEDispatcherPool(logger, {
|
|
36
|
+
workers: Number.isFinite(workerCount) && workerCount > 1 ? workerCount : undefined,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const server = createSafeJsonRpcServer(dispatcher, TXEDispatcherApiSchema, {
|
|
40
|
+
http200OnError: true,
|
|
41
|
+
middlewares: [
|
|
42
|
+
async (ctx, next) => {
|
|
43
|
+
// The body parser runs further down the chain, so `ctx.request.body` is populated only
|
|
44
|
+
// after `next()` resolves.
|
|
45
|
+
await next();
|
|
46
|
+
const socket = ctx.req.socket as TaggedSocket;
|
|
47
|
+
if (socket[SESSION_SYMBOL] !== undefined) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const body = (ctx.request as { body?: unknown }).body;
|
|
51
|
+
const sessionId =
|
|
52
|
+
body && typeof body === 'object' && 'params' in body
|
|
53
|
+
? extractSessionId((body as { params: unknown }).params)
|
|
54
|
+
: undefined;
|
|
55
|
+
if (sessionId === undefined) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
socket[SESSION_SYMBOL] = sessionId;
|
|
59
|
+
logger.debug(`Tagged socket with session`, {
|
|
60
|
+
sessionId,
|
|
61
|
+
remoteAddress: socket.remoteAddress,
|
|
62
|
+
remotePort: socket.remotePort,
|
|
63
|
+
});
|
|
64
|
+
socket.once('close', () => {
|
|
65
|
+
logger.debug(`Disposing session on socket close`, { sessionId });
|
|
66
|
+
void dispatcher.disposeSession(sessionId);
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
return server;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Extracts `session_id` from a JSON-RPC `params` array. Always a `number` because session_id
|
|
75
|
+
// comes off `JSON.parse`, which never produces BigInt; values above MAX_SAFE_INTEGER lose
|
|
76
|
+
// precision but still work as a Map key.
|
|
77
|
+
function extractSessionId(params: unknown): number | undefined {
|
|
78
|
+
if (!Array.isArray(params) || params.length === 0) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
const first = params[0];
|
|
82
|
+
if (first && typeof first === 'object' && 'session_id' in first) {
|
|
83
|
+
const sid = (first as { session_id: unknown }).session_id;
|
|
84
|
+
return typeof sid === 'number' ? sid : undefined;
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|