@aztec/txe 0.0.1-commit.2448fdb → 0.0.1-commit.2606882
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-3VX4QA7B.js +265 -0
- package/dest/chunk-3VX4QA7B.js.map +7 -0
- package/dest/chunk-BJVAAXNA.js +3 -0
- package/dest/chunk-BJVAAXNA.js.map +7 -0
- package/dest/chunk-FU3LBVE4.js +304 -0
- package/dest/chunk-FU3LBVE4.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 +38352 -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 +27 -13
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +129 -52
- 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 -266
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +699 -731
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +4 -3
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +26 -15
- package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +16 -4
- package/dest/state_machine/global_variable_builder.d.ts +9 -4
- package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
- package/dest/state_machine/global_variable_builder.js +9 -3
- package/dest/state_machine/index.d.ts +4 -2
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +17 -3
- package/dest/state_machine/mock_epoch_cache.d.ts +16 -3
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +29 -2
- package/dest/state_machine/synchronizer.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 +164 -38
- 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 +157 -62
- 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 +774 -1043
- package/src/state_machine/archiver.ts +38 -16
- package/src/state_machine/dummy_p2p_client.ts +31 -11
- package/src/state_machine/global_variable_builder.ts +18 -3
- package/src/state_machine/index.ts +20 -5
- package/src/state_machine/mock_epoch_cache.ts +38 -3
- package/src/state_machine/synchronizer.ts +1 -1
- package/src/txe_session.ts +269 -39
- 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 -719
- 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,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
3
|
-
|
|
4
|
-
MAX_PROCESSABLE_L2_GAS,
|
|
3
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
5
4
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
6
5
|
} from '@aztec/constants';
|
|
7
6
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
@@ -15,13 +14,14 @@ import {
|
|
|
15
14
|
CapsuleService,
|
|
16
15
|
CapsuleStore,
|
|
17
16
|
type ContractStore,
|
|
18
|
-
type
|
|
17
|
+
type ExecutionHooks,
|
|
19
18
|
NoteStore,
|
|
20
19
|
ORACLE_VERSION_MAJOR,
|
|
21
20
|
PrivateEventStore,
|
|
22
21
|
RecipientTaggingStore,
|
|
23
22
|
SenderAddressBookStore,
|
|
24
23
|
SenderTaggingStore,
|
|
24
|
+
composeHooks,
|
|
25
25
|
enrichPublicSimulationError,
|
|
26
26
|
} from '@aztec/pxe/server';
|
|
27
27
|
import {
|
|
@@ -55,13 +55,7 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
|
55
55
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
56
56
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
57
57
|
import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
|
|
58
|
-
import {
|
|
59
|
-
FALLBACK_TEARDOWN_DA_GAS_LIMIT,
|
|
60
|
-
FALLBACK_TEARDOWN_L2_GAS_LIMIT,
|
|
61
|
-
Gas,
|
|
62
|
-
GasFees,
|
|
63
|
-
GasSettings,
|
|
64
|
-
} from '@aztec/stdlib/gas';
|
|
58
|
+
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
65
59
|
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
66
60
|
import {
|
|
67
61
|
PartialPrivateTailPublicInputsForPublic,
|
|
@@ -69,6 +63,7 @@ import {
|
|
|
69
63
|
PrivateToPublicAccumulatedData,
|
|
70
64
|
PublicCallRequest,
|
|
71
65
|
} from '@aztec/stdlib/kernel';
|
|
66
|
+
import { hashPublicKey } from '@aztec/stdlib/keys';
|
|
72
67
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
73
68
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
74
69
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
@@ -85,13 +80,14 @@ import {
|
|
|
85
80
|
collectNested,
|
|
86
81
|
} from '@aztec/stdlib/tx';
|
|
87
82
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
88
|
-
import { ForkCheckpoint } from '@aztec/world-state';
|
|
83
|
+
import { ForkCheckpoint } from '@aztec/world-state/native';
|
|
89
84
|
|
|
90
|
-
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
85
|
+
import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
|
|
91
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
92
|
-
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
93
|
-
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
94
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';
|
|
95
91
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
96
92
|
|
|
97
93
|
export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
|
|
@@ -116,7 +112,9 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
116
112
|
private version: Fr,
|
|
117
113
|
private chainId: Fr,
|
|
118
114
|
private authwits: Map<string, AuthWitness>,
|
|
119
|
-
private readonly
|
|
115
|
+
private readonly artifactResolver: TXEArtifactResolver,
|
|
116
|
+
private readonly rootPath: string,
|
|
117
|
+
private readonly packageName: string,
|
|
120
118
|
) {
|
|
121
119
|
this.logger = createLogger('txe:top_level_context');
|
|
122
120
|
this.logger.debug('Entering Top Level Context');
|
|
@@ -149,7 +147,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
149
147
|
}
|
|
150
148
|
|
|
151
149
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
152
|
-
log(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
150
|
+
log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
|
|
153
151
|
if (!LogLevels[level]) {
|
|
154
152
|
throw new Error(`Invalid log level: ${level}`);
|
|
155
153
|
}
|
|
@@ -172,12 +170,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
async getLastBlockTimestamp() {
|
|
175
|
-
return (await this.stateMachine.node.
|
|
173
|
+
return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
|
|
176
174
|
}
|
|
177
175
|
|
|
178
176
|
async getLastTxEffects() {
|
|
179
177
|
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
180
|
-
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
178
|
+
const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
|
|
181
179
|
|
|
182
180
|
if (block!.body.txEffects.length != 1) {
|
|
183
181
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
@@ -186,7 +184,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
186
184
|
|
|
187
185
|
const txEffects = block!.body.txEffects[0];
|
|
188
186
|
|
|
189
|
-
|
|
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
|
+
};
|
|
190
198
|
}
|
|
191
199
|
|
|
192
200
|
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
@@ -209,7 +217,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
209
217
|
}
|
|
210
218
|
|
|
211
219
|
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
212
|
-
|
|
220
|
+
const events = (
|
|
213
221
|
await this.privateEventStore.getPrivateEvents(selector, {
|
|
214
222
|
contractAddress,
|
|
215
223
|
scopes: [scope],
|
|
@@ -217,6 +225,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
217
225
|
toBlock: (await this.getLastBlockNumber()) + 1,
|
|
218
226
|
})
|
|
219
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;
|
|
220
237
|
}
|
|
221
238
|
|
|
222
239
|
async advanceBlocksBy(blocks: number) {
|
|
@@ -232,27 +249,71 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
232
249
|
this.nextBlockTimestamp += duration;
|
|
233
250
|
}
|
|
234
251
|
|
|
235
|
-
|
|
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
|
+
|
|
236
275
|
// Emit deployment nullifier
|
|
237
276
|
await this.mineBlock({
|
|
238
|
-
nullifiers: [
|
|
239
|
-
await siloNullifier(
|
|
240
|
-
AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
|
|
241
|
-
instance.address.toField(),
|
|
242
|
-
),
|
|
243
|
-
],
|
|
277
|
+
nullifiers: [await this.deploymentNullifier(instance.address)],
|
|
244
278
|
});
|
|
245
279
|
|
|
246
280
|
if (!secret.equals(Fr.ZERO)) {
|
|
247
|
-
await this.
|
|
281
|
+
await this.registerContractAndAddAccount(artifact, instance, secret);
|
|
248
282
|
} else {
|
|
249
283
|
await this.contractStore.addContractInstance(instance);
|
|
250
284
|
await this.contractStore.addContractArtifact(artifact);
|
|
251
285
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
252
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
|
+
});
|
|
253
305
|
}
|
|
254
306
|
|
|
255
|
-
async addAccount(
|
|
307
|
+
async addAccount(secret: Fr) {
|
|
308
|
+
const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
|
|
309
|
+
return this.registerContractAndAddAccount(artifact, instance, secret);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private async registerContractAndAddAccount(
|
|
313
|
+
artifact: ContractArtifact,
|
|
314
|
+
instance: ContractInstanceWithAddress,
|
|
315
|
+
secret: Fr,
|
|
316
|
+
) {
|
|
256
317
|
const partialAddress = await computePartialAddress(instance);
|
|
257
318
|
|
|
258
319
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
@@ -279,12 +340,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
279
340
|
|
|
280
341
|
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
281
342
|
const account = await this.accountStore.getAccount(address);
|
|
282
|
-
const
|
|
343
|
+
const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
|
|
344
|
+
const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
|
|
283
345
|
|
|
284
346
|
const schnorr = new Schnorr();
|
|
285
|
-
const signature = await schnorr.constructSignature(messageHash
|
|
347
|
+
const signature = await schnorr.constructSignature(messageHash, privateKey);
|
|
286
348
|
|
|
287
|
-
const authWitness = new AuthWitness(messageHash,
|
|
349
|
+
const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
|
|
288
350
|
|
|
289
351
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
290
352
|
}
|
|
@@ -315,13 +377,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
315
377
|
}
|
|
316
378
|
|
|
317
379
|
async privateCallNewFlow(
|
|
318
|
-
from: AztecAddress,
|
|
380
|
+
from: AztecAddress | undefined,
|
|
319
381
|
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
320
382
|
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
321
383
|
args: Fr[],
|
|
322
384
|
argsHash: Fr = Fr.zero(),
|
|
323
385
|
isStaticCall: boolean = false,
|
|
386
|
+
additionalScopes: AztecAddress[] = [],
|
|
324
387
|
jobId: string,
|
|
388
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
389
|
+
gasSettings: GasSettings,
|
|
325
390
|
) {
|
|
326
391
|
this.logger.verbose(
|
|
327
392
|
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -335,9 +400,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
335
400
|
throw new Error(message);
|
|
336
401
|
}
|
|
337
402
|
|
|
338
|
-
|
|
339
|
-
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
340
|
-
const effectiveScopes = from.isZero() ? [] : [from];
|
|
403
|
+
const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
|
|
341
404
|
|
|
342
405
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
343
406
|
const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
|
|
@@ -351,16 +414,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
351
414
|
utilityExecutor,
|
|
352
415
|
blockHeader,
|
|
353
416
|
jobId,
|
|
354
|
-
|
|
417
|
+
scopes,
|
|
355
418
|
);
|
|
356
419
|
|
|
357
420
|
const blockNumber = await this.getNextBlockNumber();
|
|
358
421
|
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
|
|
362
|
-
const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
|
|
363
|
-
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);
|
|
364
424
|
|
|
365
425
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
366
426
|
|
|
@@ -394,19 +454,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
394
454
|
senderTaggingStore: this.senderTaggingStore,
|
|
395
455
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
396
456
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
397
|
-
capsuleService: new CapsuleService(this.capsuleStore,
|
|
457
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
398
458
|
privateEventStore: this.privateEventStore,
|
|
399
459
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
400
460
|
jobId,
|
|
401
461
|
totalPublicCalldataCount: 0,
|
|
402
462
|
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
403
|
-
scopes
|
|
463
|
+
scopes,
|
|
404
464
|
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
405
465
|
// contract would perform, including setting senderForTags.
|
|
406
466
|
senderForTags: from,
|
|
407
467
|
simulator,
|
|
408
468
|
messageContextService: this.stateMachine.messageContextService,
|
|
409
|
-
l2TipsStore: this.stateMachine.
|
|
469
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
470
|
+
hooks: composeHooks({
|
|
471
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
|
|
472
|
+
isStaticCall ? 'private view' : 'private',
|
|
473
|
+
authorizedUtilityCallTargets,
|
|
474
|
+
),
|
|
475
|
+
}),
|
|
410
476
|
});
|
|
411
477
|
|
|
412
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.
|
|
@@ -514,11 +580,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
514
580
|
}
|
|
515
581
|
}
|
|
516
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
|
+
|
|
517
589
|
if (isStaticCall) {
|
|
518
590
|
await checkpoint!.revert();
|
|
519
591
|
|
|
520
592
|
await forkedWorldTrees.close();
|
|
521
|
-
return executionResult.returnValues ?? [];
|
|
593
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
522
594
|
}
|
|
523
595
|
|
|
524
596
|
const txEffect = TxEffect.empty();
|
|
@@ -540,14 +612,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
540
612
|
|
|
541
613
|
await forkedWorldTrees.close();
|
|
542
614
|
|
|
543
|
-
return executionResult.returnValues ?? [];
|
|
615
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
544
616
|
}
|
|
545
617
|
|
|
546
618
|
async publicCallNewFlow(
|
|
547
|
-
from: AztecAddress,
|
|
619
|
+
from: AztecAddress | undefined,
|
|
548
620
|
targetContractAddress: AztecAddress,
|
|
549
621
|
calldata: Fr[],
|
|
550
622
|
isStaticCall: boolean,
|
|
623
|
+
gasSettings: GasSettings,
|
|
551
624
|
) {
|
|
552
625
|
this.logger.verbose(
|
|
553
626
|
`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -555,12 +628,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
555
628
|
|
|
556
629
|
const blockNumber = await this.getNextBlockNumber();
|
|
557
630
|
|
|
558
|
-
const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
|
|
559
|
-
|
|
560
|
-
const teardownGasLimits = new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT);
|
|
561
|
-
|
|
562
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
563
|
-
|
|
564
631
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
565
632
|
|
|
566
633
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
@@ -612,7 +679,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
612
679
|
// may require producing reverts.
|
|
613
680
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
614
681
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
|
|
615
|
-
from,
|
|
682
|
+
from ?? AztecAddress.NULL_MSG_SENDER,
|
|
616
683
|
targetContractAddress,
|
|
617
684
|
isStaticCall,
|
|
618
685
|
calldataHash,
|
|
@@ -703,6 +770,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
703
770
|
functionSelector: FunctionSelector,
|
|
704
771
|
args: Fr[],
|
|
705
772
|
jobId: string,
|
|
773
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
706
774
|
) {
|
|
707
775
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
708
776
|
if (!artifact) {
|
|
@@ -733,10 +801,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
733
801
|
returnTypes: [],
|
|
734
802
|
});
|
|
735
803
|
|
|
736
|
-
return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId);
|
|
804
|
+
return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
|
|
737
805
|
}
|
|
738
806
|
|
|
739
|
-
private async executeUtilityCall(
|
|
807
|
+
private async executeUtilityCall(
|
|
808
|
+
call: FunctionCall,
|
|
809
|
+
scopes: AztecAddress[],
|
|
810
|
+
jobId: string,
|
|
811
|
+
authorizedUtilityCallTargets: AztecAddress[] = [],
|
|
812
|
+
): Promise<Fr[]> {
|
|
740
813
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
741
814
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
742
815
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -749,6 +822,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
749
822
|
|
|
750
823
|
try {
|
|
751
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
|
+
};
|
|
752
829
|
const oracle = new UtilityExecutionOracle({
|
|
753
830
|
contractAddress: call.to,
|
|
754
831
|
authWitnesses: [],
|
|
@@ -764,12 +841,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
764
841
|
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
765
842
|
privateEventStore: this.privateEventStore,
|
|
766
843
|
messageContextService: this.stateMachine.messageContextService,
|
|
767
|
-
contractSyncService: this.contractSyncService,
|
|
768
|
-
l2TipsStore: this.stateMachine.
|
|
844
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
845
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
769
846
|
jobId,
|
|
770
847
|
scopes,
|
|
848
|
+
simulator,
|
|
849
|
+
hooks: composeHooks({
|
|
850
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
|
|
851
|
+
}),
|
|
852
|
+
utilityExecutor,
|
|
771
853
|
});
|
|
772
|
-
const acirExecutionResult = await
|
|
854
|
+
const acirExecutionResult = await simulator
|
|
773
855
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
774
856
|
.catch((err: Error) => {
|
|
775
857
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
@@ -797,7 +879,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
797
879
|
}
|
|
798
880
|
|
|
799
881
|
private async getLastBlockNumber(): Promise<BlockNumber> {
|
|
800
|
-
const
|
|
801
|
-
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
|
+
});
|
|
802
897
|
}
|
|
803
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
|
+
}
|