@aztec/txe 0.0.1-commit.7b97ef96e → 0.0.1-commit.7cbc774
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-KKNT527R.js +3 -0
- package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
- package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
- package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
- package/dest/FeeJuice-GUJ5O6GB.js +3 -0
- package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
- package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
- package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
- package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
- package/dest/SchnorrAccount-QIXE5DXA.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 +32 -0
- package/dest/bin/index.js +3 -30
- package/dest/bin/index.js.map +7 -0
- package/dest/chunk-BJVAAXNA.js +3 -0
- package/dest/chunk-BJVAAXNA.js.map +7 -0
- package/dest/chunk-DF6RMOC6.js +304 -0
- package/dest/chunk-DF6RMOC6.js.map +7 -0
- package/dest/chunk-PPJTNNUG.js +265 -0
- package/dest/chunk-PPJTNNUG.js.map +7 -0
- package/dest/constants.d.ts +3 -1
- package/dest/constants.d.ts.map +1 -1
- package/dest/constants.js +5 -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 +188 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +160 -119
- package/dest/metafile.json +38147 -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 +40 -28
- package/dest/oracle/interfaces.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.d.ts +18 -13
- package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_public_context.js +27 -12
- package/dest/oracle/txe_oracle_top_level_context.d.ts +38 -22
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +141 -72
- 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 +139 -83
- package/dest/rpc_translator.d.ts.map +1 -1
- package/dest/rpc_translator.js +574 -238
- package/dest/server.bundle.js +3 -0
- package/dest/server.bundle.js.map +7 -0
- package/dest/state_machine/archiver.d.ts +4 -4
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +22 -20
- package/dest/state_machine/dummy_p2p_client.d.ts +14 -8
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +17 -5
- 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 +7 -3
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +23 -5
- package/dest/state_machine/mock_epoch_cache.d.ts +18 -3
- package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
- package/dest/state_machine/mock_epoch_cache.js +35 -2
- package/dest/state_machine/synchronizer.d.ts +5 -5
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +4 -4
- package/dest/txe_oracle_version.d.ts +17 -0
- package/dest/txe_oracle_version.d.ts.map +1 -0
- package/dest/txe_oracle_version.js +14 -0
- package/dest/txe_session.d.ts +69 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +170 -35
- 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_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 +37 -21
- package/src/bin/check_txe_oracle_version.ts +37 -0
- package/src/bin/index.ts +11 -2
- package/src/constants.ts +6 -0
- package/src/dispatcher_pool.ts +316 -0
- package/src/index.ts +178 -126
- package/src/msgpackr_fr_extension.ts +23 -0
- package/src/oracle/interfaces.ts +48 -34
- package/src/oracle/txe_oracle_public_context.ts +42 -12
- package/src/oracle/txe_oracle_top_level_context.ts +176 -83
- package/src/oracle/txe_private_execution_oracle.ts +30 -0
- package/src/rpc_server.ts +87 -0
- package/src/rpc_translator.ts +654 -319
- package/src/state_machine/archiver.ts +33 -18
- package/src/state_machine/dummy_p2p_client.ts +32 -12
- package/src/state_machine/global_variable_builder.ts +18 -3
- package/src/state_machine/index.ts +25 -6
- package/src/state_machine/mock_epoch_cache.ts +46 -3
- package/src/state_machine/synchronizer.ts +5 -5
- package/src/txe_oracle_version.ts +17 -0
- package/src/txe_session.ts +269 -37
- package/src/{util → utils}/encoding.ts +8 -2
- 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,10 +1,10 @@
|
|
|
1
|
-
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
1
|
+
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, MAX_PRIVATE_LOGS_PER_TX, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
3
|
import { Schnorr } from '@aztec/foundation/crypto/schnorr';
|
|
4
4
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
|
|
6
6
|
import { TestDateProvider } from '@aztec/foundation/timer';
|
|
7
|
-
import {
|
|
7
|
+
import { CapsuleService, ORACLE_VERSION_MAJOR, composeHooks, enrichPublicSimulationError } from '@aztec/pxe/server';
|
|
8
8
|
import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
|
|
9
9
|
import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
|
|
10
10
|
import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
|
|
@@ -13,17 +13,18 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
|
13
13
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
14
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
15
15
|
import { computePartialAddress } from '@aztec/stdlib/contract';
|
|
16
|
-
import { Gas, GasFees
|
|
16
|
+
import { Gas, GasFees } from '@aztec/stdlib/gas';
|
|
17
17
|
import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
|
|
18
18
|
import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
19
|
+
import { hashPublicKey } from '@aztec/stdlib/keys';
|
|
19
20
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
20
21
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
21
22
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
22
23
|
import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
|
|
23
|
-
import { ForkCheckpoint } from '@aztec/world-state';
|
|
24
|
+
import { ForkCheckpoint } from '@aztec/world-state/native';
|
|
24
25
|
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
25
|
-
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
26
26
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
27
|
+
import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
|
|
27
28
|
export class TXEOracleTopLevelContext {
|
|
28
29
|
stateMachine;
|
|
29
30
|
contractStore;
|
|
@@ -36,7 +37,6 @@ export class TXEOracleTopLevelContext {
|
|
|
36
37
|
senderAddressBookStore;
|
|
37
38
|
capsuleStore;
|
|
38
39
|
privateEventStore;
|
|
39
|
-
jobId;
|
|
40
40
|
nextBlockTimestamp;
|
|
41
41
|
version;
|
|
42
42
|
chainId;
|
|
@@ -44,7 +44,7 @@ export class TXEOracleTopLevelContext {
|
|
|
44
44
|
isMisc;
|
|
45
45
|
isTxe;
|
|
46
46
|
logger;
|
|
47
|
-
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore,
|
|
47
|
+
constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, authwits){
|
|
48
48
|
this.stateMachine = stateMachine;
|
|
49
49
|
this.contractStore = contractStore;
|
|
50
50
|
this.noteStore = noteStore;
|
|
@@ -56,7 +56,6 @@ export class TXEOracleTopLevelContext {
|
|
|
56
56
|
this.senderAddressBookStore = senderAddressBookStore;
|
|
57
57
|
this.capsuleStore = capsuleStore;
|
|
58
58
|
this.privateEventStore = privateEventStore;
|
|
59
|
-
this.jobId = jobId;
|
|
60
59
|
this.nextBlockTimestamp = nextBlockTimestamp;
|
|
61
60
|
this.version = version;
|
|
62
61
|
this.chainId = chainId;
|
|
@@ -66,18 +65,28 @@ export class TXEOracleTopLevelContext {
|
|
|
66
65
|
this.logger = createLogger('txe:top_level_context');
|
|
67
66
|
this.logger.debug('Entering Top Level Context');
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
contractOracleVersion;
|
|
69
|
+
assertCompatibleOracleVersion(major, minor) {
|
|
70
|
+
if (major !== ORACLE_VERSION_MAJOR) {
|
|
71
|
+
const hint = major > ORACLE_VERSION_MAJOR ? '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.' : '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.';
|
|
72
|
+
throw new Error(`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`);
|
|
72
73
|
}
|
|
74
|
+
this.contractOracleVersion = {
|
|
75
|
+
major,
|
|
76
|
+
minor
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
|
|
80
|
+
nonOracleFunctionGetContractOracleVersion() {
|
|
81
|
+
return this.contractOracleVersion;
|
|
73
82
|
}
|
|
74
83
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
75
84
|
// setup.
|
|
76
|
-
|
|
85
|
+
getRandomField() {
|
|
77
86
|
return Fr.random();
|
|
78
87
|
}
|
|
79
88
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
80
|
-
|
|
89
|
+
log(level, message, fields) {
|
|
81
90
|
if (!LogLevels[level]) {
|
|
82
91
|
throw new Error(`Invalid log level: ${level}`);
|
|
83
92
|
}
|
|
@@ -87,33 +96,52 @@ export class TXEOracleTopLevelContext {
|
|
|
87
96
|
});
|
|
88
97
|
return Promise.resolve();
|
|
89
98
|
}
|
|
90
|
-
|
|
99
|
+
getDefaultAddress() {
|
|
91
100
|
return DEFAULT_ADDRESS;
|
|
92
101
|
}
|
|
93
|
-
async
|
|
102
|
+
async getNextBlockNumber() {
|
|
94
103
|
return BlockNumber(await this.getLastBlockNumber() + 1);
|
|
95
104
|
}
|
|
96
|
-
|
|
105
|
+
getNextBlockTimestamp() {
|
|
97
106
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
98
107
|
}
|
|
99
|
-
async
|
|
100
|
-
return (await this.stateMachine.node.
|
|
108
|
+
async getLastBlockTimestamp() {
|
|
109
|
+
return (await this.stateMachine.node.getBlockData('latest')).header.globalVariables.timestamp;
|
|
101
110
|
}
|
|
102
|
-
async
|
|
111
|
+
async getLastTxEffects() {
|
|
103
112
|
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
104
|
-
const block = await this.stateMachine.archiver.getBlock(
|
|
113
|
+
const block = await this.stateMachine.archiver.getBlock({
|
|
114
|
+
number: latestBlockNumber
|
|
115
|
+
});
|
|
105
116
|
if (block.body.txEffects.length != 1) {
|
|
106
117
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
107
118
|
throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
|
|
108
119
|
}
|
|
109
120
|
const txEffects = block.body.txEffects[0];
|
|
121
|
+
const privateLogs = txEffects.privateLogs;
|
|
122
|
+
if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
|
|
123
|
+
throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
|
|
124
|
+
}
|
|
110
125
|
return {
|
|
111
126
|
txHash: txEffects.txHash,
|
|
112
127
|
noteHashes: txEffects.noteHashes,
|
|
113
|
-
nullifiers: txEffects.nullifiers
|
|
128
|
+
nullifiers: txEffects.nullifiers,
|
|
129
|
+
privateLogs
|
|
114
130
|
};
|
|
115
131
|
}
|
|
116
|
-
async
|
|
132
|
+
async syncContractNonOracleMethod(contractAddress, scope, jobId) {
|
|
133
|
+
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
134
|
+
this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
138
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
|
|
139
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
140
|
+
}, blockHeader, jobId, [
|
|
141
|
+
scope
|
|
142
|
+
]);
|
|
143
|
+
}
|
|
144
|
+
async getPrivateEvents(selector, contractAddress, scope) {
|
|
117
145
|
return (await this.privateEventStore.getPrivateEvents(selector, {
|
|
118
146
|
contractAddress,
|
|
119
147
|
scopes: [
|
|
@@ -123,32 +151,42 @@ export class TXEOracleTopLevelContext {
|
|
|
123
151
|
toBlock: await this.getLastBlockNumber() + 1
|
|
124
152
|
})).map((e)=>e.packedEvent);
|
|
125
153
|
}
|
|
126
|
-
async
|
|
154
|
+
async advanceBlocksBy(blocks) {
|
|
127
155
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
128
156
|
for(let i = 0; i < blocks; i++){
|
|
129
157
|
await this.mineBlock();
|
|
130
158
|
}
|
|
131
159
|
}
|
|
132
|
-
|
|
160
|
+
advanceTimestampBy(duration) {
|
|
133
161
|
this.logger.debug(`time traveling ${duration} seconds`);
|
|
134
162
|
this.nextBlockTimestamp += duration;
|
|
135
163
|
}
|
|
136
|
-
|
|
164
|
+
deploymentNullifier(address) {
|
|
165
|
+
return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
|
|
166
|
+
}
|
|
167
|
+
async deploy(artifact, instance, secret) {
|
|
137
168
|
// Emit deployment nullifier
|
|
138
169
|
await this.mineBlock({
|
|
139
170
|
nullifiers: [
|
|
140
|
-
await
|
|
171
|
+
await this.deploymentNullifier(instance.address)
|
|
141
172
|
]
|
|
142
173
|
});
|
|
143
174
|
if (!secret.equals(Fr.ZERO)) {
|
|
144
|
-
await this.
|
|
175
|
+
await this.addAccount(artifact, instance, secret);
|
|
145
176
|
} else {
|
|
146
177
|
await this.contractStore.addContractInstance(instance);
|
|
147
178
|
await this.contractStore.addContractArtifact(artifact);
|
|
148
179
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
149
180
|
}
|
|
150
181
|
}
|
|
151
|
-
|
|
182
|
+
/**
|
|
183
|
+
* Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
|
|
184
|
+
*/ async mineDeploymentNullifiers(addresses) {
|
|
185
|
+
await this.mineBlock({
|
|
186
|
+
nullifiers: await Promise.all(addresses.map((address)=>this.deploymentNullifier(address)))
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
async addAccount(artifact, instance, secret) {
|
|
152
190
|
const partialAddress = await computePartialAddress(instance);
|
|
153
191
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
154
192
|
await this.contractStore.addContractInstance(instance);
|
|
@@ -159,7 +197,7 @@ export class TXEOracleTopLevelContext {
|
|
|
159
197
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
160
198
|
return completeAddress;
|
|
161
199
|
}
|
|
162
|
-
async
|
|
200
|
+
async createAccount(secret) {
|
|
163
201
|
// This is a foot gun !
|
|
164
202
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
165
203
|
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
@@ -167,18 +205,17 @@ export class TXEOracleTopLevelContext {
|
|
|
167
205
|
this.logger.debug(`Created account ${completeAddress.address}`);
|
|
168
206
|
return completeAddress;
|
|
169
207
|
}
|
|
170
|
-
async
|
|
208
|
+
async addAuthWitness(address, messageHash) {
|
|
171
209
|
const account = await this.accountStore.getAccount(address);
|
|
172
|
-
const
|
|
210
|
+
const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
|
|
211
|
+
const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
|
|
173
212
|
const schnorr = new Schnorr();
|
|
174
|
-
const signature = await schnorr.constructSignature(messageHash
|
|
175
|
-
const authWitness = new AuthWitness(messageHash,
|
|
176
|
-
...signature.toBuffer()
|
|
177
|
-
]);
|
|
213
|
+
const signature = await schnorr.constructSignature(messageHash, privateKey);
|
|
214
|
+
const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
|
|
178
215
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
179
216
|
}
|
|
180
217
|
async mineBlock(options = {}) {
|
|
181
|
-
const blockNumber = await this.
|
|
218
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
182
219
|
const txEffect = TxEffect.empty();
|
|
183
220
|
txEffect.nullifiers = [
|
|
184
221
|
getSingleTxBlockRequestHash(blockNumber),
|
|
@@ -200,29 +237,26 @@ export class TXEOracleTopLevelContext {
|
|
|
200
237
|
this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
|
|
201
238
|
await this.stateMachine.handleL2Block(block);
|
|
202
239
|
}
|
|
203
|
-
async
|
|
240
|
+
async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, additionalScopes = [], jobId, authorizedUtilityCallTargets, gasSettings) {
|
|
204
241
|
this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
205
242
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
206
243
|
if (!artifact) {
|
|
207
244
|
const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
|
|
208
245
|
throw new Error(message);
|
|
209
246
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
from
|
|
247
|
+
const scopes = from === undefined ? additionalScopes : [
|
|
248
|
+
from,
|
|
249
|
+
...additionalScopes
|
|
214
250
|
];
|
|
215
251
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
216
252
|
const utilityExecutor = async (call, execScopes)=>{
|
|
217
|
-
await this.executeUtilityCall(call, execScopes);
|
|
253
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
218
254
|
};
|
|
219
255
|
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
220
|
-
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader,
|
|
221
|
-
const blockNumber = await this.
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
225
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
256
|
+
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, scopes);
|
|
257
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
258
|
+
const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
|
|
259
|
+
const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
|
|
226
260
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
227
261
|
const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
|
|
228
262
|
const noteCache = new ExecutionNoteCache(protocolNullifier);
|
|
@@ -254,17 +288,22 @@ export class TXEOracleTopLevelContext {
|
|
|
254
288
|
senderTaggingStore: this.senderTaggingStore,
|
|
255
289
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
256
290
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
257
|
-
|
|
291
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
258
292
|
privateEventStore: this.privateEventStore,
|
|
259
293
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
260
|
-
jobId
|
|
294
|
+
jobId,
|
|
261
295
|
totalPublicCalldataCount: 0,
|
|
262
296
|
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
263
|
-
scopes
|
|
297
|
+
scopes,
|
|
264
298
|
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
265
299
|
// contract would perform, including setting senderForTags.
|
|
266
300
|
senderForTags: from,
|
|
267
|
-
simulator
|
|
301
|
+
simulator,
|
|
302
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
303
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
304
|
+
hooks: composeHooks({
|
|
305
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(isStaticCall ? 'private view' : 'private', authorizedUtilityCallTargets)
|
|
306
|
+
})
|
|
268
307
|
});
|
|
269
308
|
// 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.
|
|
270
309
|
let result;
|
|
@@ -277,7 +316,7 @@ export class TXEOracleTopLevelContext {
|
|
|
277
316
|
r.publicInputs.publicTeardownCallRequest
|
|
278
317
|
]));
|
|
279
318
|
const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
|
|
280
|
-
const calldata = await privateExecutionOracle.
|
|
319
|
+
const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
|
|
281
320
|
return new HashedValues(calldata, r.calldataHash);
|
|
282
321
|
}));
|
|
283
322
|
noteCache.finish();
|
|
@@ -336,10 +375,20 @@ export class TXEOracleTopLevelContext {
|
|
|
336
375
|
throw new Error('Contract execution has reverted');
|
|
337
376
|
}
|
|
338
377
|
}
|
|
378
|
+
// Walk the nested private-call tree and collect every offchain effect the transaction emitted.
|
|
379
|
+
// PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
|
|
380
|
+
// `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
|
|
381
|
+
// we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
|
|
382
|
+
const offchainEffects = collectNested([
|
|
383
|
+
executionResult
|
|
384
|
+
], (r)=>r.offchainEffects.map((e)=>e.data));
|
|
339
385
|
if (isStaticCall) {
|
|
340
386
|
await checkpoint.revert();
|
|
341
387
|
await forkedWorldTrees.close();
|
|
342
|
-
return
|
|
388
|
+
return {
|
|
389
|
+
returnValues: executionResult.returnValues ?? [],
|
|
390
|
+
offchainEffects
|
|
391
|
+
};
|
|
343
392
|
}
|
|
344
393
|
const txEffect = TxEffect.empty();
|
|
345
394
|
txEffect.noteHashes = processedTx.txEffect.noteHashes;
|
|
@@ -355,14 +404,14 @@ export class TXEOracleTopLevelContext {
|
|
|
355
404
|
]);
|
|
356
405
|
await this.stateMachine.handleL2Block(l2Block);
|
|
357
406
|
await forkedWorldTrees.close();
|
|
358
|
-
return
|
|
407
|
+
return {
|
|
408
|
+
returnValues: executionResult.returnValues ?? [],
|
|
409
|
+
offchainEffects
|
|
410
|
+
};
|
|
359
411
|
}
|
|
360
|
-
async
|
|
412
|
+
async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall, gasSettings) {
|
|
361
413
|
this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
|
|
362
|
-
const blockNumber = await this.
|
|
363
|
-
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
364
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
365
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
414
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
366
415
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
367
416
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
368
417
|
const calldataHash = await computeCalldataHash(calldata);
|
|
@@ -395,7 +444,7 @@ export class TXEOracleTopLevelContext {
|
|
|
395
444
|
// The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
|
|
396
445
|
// may require producing reverts.
|
|
397
446
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
398
|
-
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
|
|
447
|
+
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from ?? AztecAddress.NULL_MSG_SENDER, targetContractAddress, isStaticCall, calldataHash);
|
|
399
448
|
const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
|
|
400
449
|
const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
|
|
401
450
|
const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
|
|
@@ -451,7 +500,7 @@ export class TXEOracleTopLevelContext {
|
|
|
451
500
|
await forkedWorldTrees.close();
|
|
452
501
|
return returnValues ?? [];
|
|
453
502
|
}
|
|
454
|
-
async
|
|
503
|
+
async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId, authorizedUtilityCallTargets) {
|
|
455
504
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
456
505
|
if (!artifact) {
|
|
457
506
|
throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
|
|
@@ -459,8 +508,8 @@ export class TXEOracleTopLevelContext {
|
|
|
459
508
|
// Sync notes before executing utility function to discover notes from previous transactions
|
|
460
509
|
const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
461
510
|
await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
|
|
462
|
-
await this.executeUtilityCall(call, execScopes);
|
|
463
|
-
}, blockHeader,
|
|
511
|
+
await this.executeUtilityCall(call, execScopes, jobId);
|
|
512
|
+
}, blockHeader, jobId, await this.keyStore.getAccounts());
|
|
464
513
|
const call = FunctionCall.from({
|
|
465
514
|
name: artifact.name,
|
|
466
515
|
to: targetContractAddress,
|
|
@@ -471,9 +520,9 @@ export class TXEOracleTopLevelContext {
|
|
|
471
520
|
args,
|
|
472
521
|
returnTypes: []
|
|
473
522
|
});
|
|
474
|
-
return this.executeUtilityCall(call,
|
|
523
|
+
return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
|
|
475
524
|
}
|
|
476
|
-
async executeUtilityCall(call, scopes) {
|
|
525
|
+
async executeUtilityCall(call, scopes, jobId, authorizedUtilityCallTargets = []) {
|
|
477
526
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
478
527
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
479
528
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -484,6 +533,10 @@ export class TXEOracleTopLevelContext {
|
|
|
484
533
|
});
|
|
485
534
|
try {
|
|
486
535
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
536
|
+
const simulator = new WASMSimulator();
|
|
537
|
+
const utilityExecutor = async (syncCall, execScopes)=>{
|
|
538
|
+
await this.executeUtilityCall(syncCall, execScopes, jobId);
|
|
539
|
+
};
|
|
487
540
|
const oracle = new UtilityExecutionOracle({
|
|
488
541
|
contractAddress: call.to,
|
|
489
542
|
authWitnesses: [],
|
|
@@ -496,12 +549,20 @@ export class TXEOracleTopLevelContext {
|
|
|
496
549
|
aztecNode: this.stateMachine.node,
|
|
497
550
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
498
551
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
499
|
-
|
|
552
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
500
553
|
privateEventStore: this.privateEventStore,
|
|
501
|
-
|
|
502
|
-
|
|
554
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
555
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
556
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
557
|
+
jobId,
|
|
558
|
+
scopes,
|
|
559
|
+
simulator,
|
|
560
|
+
hooks: composeHooks({
|
|
561
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets)
|
|
562
|
+
}),
|
|
563
|
+
utilityExecutor
|
|
503
564
|
});
|
|
504
|
-
const acirExecutionResult = await
|
|
565
|
+
const acirExecutionResult = await simulator.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
|
|
505
566
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
506
567
|
throw new ExecutionError(err.message, {
|
|
507
568
|
contractAddress: call.to,
|
|
@@ -524,7 +585,15 @@ export class TXEOracleTopLevelContext {
|
|
|
524
585
|
];
|
|
525
586
|
}
|
|
526
587
|
async getLastBlockNumber() {
|
|
527
|
-
const
|
|
528
|
-
return
|
|
588
|
+
const block = await this.stateMachine.node.getBlock('latest');
|
|
589
|
+
return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
590
|
+
}
|
|
591
|
+
buildAuthorizeUtilityCallHook(callerContext, authorizedTargets) {
|
|
592
|
+
if (authorizedTargets.length === 0) {
|
|
593
|
+
return undefined;
|
|
594
|
+
}
|
|
595
|
+
return (req)=>Promise.resolve({
|
|
596
|
+
authorized: req.callerContext === callerContext && authorizedTargets.some((t)=>t.equals(req.target))
|
|
597
|
+
});
|
|
529
598
|
}
|
|
530
599
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
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
|
+
* TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
|
|
7
|
+
* TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
|
|
8
|
+
*/
|
|
9
|
+
export declare class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
|
|
10
|
+
callPrivateFunction(_targetContractAddress: AztecAddress, _functionSelector: FunctionSelector, _argsHash: Fr, _sideEffectCounter: number, _isStaticCall: boolean): Promise<{
|
|
11
|
+
endSideEffectCounter: Fr;
|
|
12
|
+
returnsHash: Fr;
|
|
13
|
+
}>;
|
|
14
|
+
assertValidPublicCalldata(_calldataHash: Fr): Promise<void>;
|
|
15
|
+
notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter: number): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX3ByaXZhdGVfZXhlY3V0aW9uX29yYWNsZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29yYWNsZS90eGVfcHJpdmF0ZV9leGVjdXRpb25fb3JhY2xlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3pELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzlELE9BQU8sS0FBSyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDMUQsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFaEU7OztHQUdHO0FBQ0gscUJBQWEseUJBQTBCLFNBQVEsc0JBQXNCO0lBQzFELG1CQUFtQixDQUMxQixzQkFBc0IsRUFBRSxZQUFZLEVBQ3BDLGlCQUFpQixFQUFFLGdCQUFnQixFQUNuQyxTQUFTLEVBQUUsRUFBRSxFQUNiLGtCQUFrQixFQUFFLE1BQU0sRUFDMUIsYUFBYSxFQUFFLE9BQU8sR0FDckIsT0FBTyxDQUFDO1FBQUUsb0JBQW9CLEVBQUUsRUFBRSxDQUFDO1FBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQTtLQUFFLENBQUMsQ0FJeEQ7SUFFUSx5QkFBeUIsQ0FBQyxhQUFhLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFbkU7SUFFUSwwQkFBMEIsQ0FBQywrQkFBK0IsRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUUxRjtDQUNGIn0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"txe_private_execution_oracle.d.ts","sourceRoot":"","sources":["../../src/oracle/txe_private_execution_oracle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,sBAAsB;IAC1D,mBAAmB,CAC1B,sBAAsB,EAAE,YAAY,EACpC,iBAAiB,EAAE,gBAAgB,EACnC,SAAS,EAAE,EAAE,EACb,kBAAkB,EAAE,MAAM,EAC1B,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC;QAAE,oBAAoB,EAAE,EAAE,CAAC;QAAC,WAAW,EAAE,EAAE,CAAA;KAAE,CAAC,CAIxD;IAEQ,yBAAyB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnE;IAEQ,0BAA0B,CAAC,+BAA+B,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1F;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PrivateExecutionOracle } from '@aztec/pxe/simulator';
|
|
2
|
+
/**
|
|
3
|
+
* TXE-specific subclass of PrivateExecutionOracle that forbids operations not supported in
|
|
4
|
+
* TestEnvironment::private_context. TXE uses dedicated oracle flows (e.g. private_call) instead.
|
|
5
|
+
*/ export class TXEPrivateExecutionOracle extends PrivateExecutionOracle {
|
|
6
|
+
callPrivateFunction(_targetContractAddress, _functionSelector, _argsHash, _sideEffectCounter, _isStaticCall) {
|
|
7
|
+
throw new Error('Contract calls are forbidden inside a `TestEnvironment::private_context`, use `private_call` instead');
|
|
8
|
+
}
|
|
9
|
+
assertValidPublicCalldata(_calldataHash) {
|
|
10
|
+
throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
|
|
11
|
+
}
|
|
12
|
+
notifyRevertiblePhaseStart(_minRevertibleSideEffectCounter) {
|
|
13
|
+
throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
|
|
4
|
+
* worker_threads, no IPC overhead). With any other value oracle calls are
|
|
5
|
+
* routed to a pool of worker threads sized to that value, sticky by `session_id`.
|
|
6
|
+
*
|
|
7
|
+
* Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
|
|
8
|
+
* nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
|
|
9
|
+
* closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
|
|
10
|
+
*
|
|
11
|
+
* Lives in its own module so the worker bundle does not pull in the HTTP server stack.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createTXERpcServer(logger: Logger): Promise<import("@aztec/foundation/json-rpc/server").SafeJsonRpcServer>;
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnBjX3NlcnZlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3JwY19zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFlcEQ7Ozs7Ozs7Ozs7R0FVRztBQUNILHdCQUFzQixrQkFBa0IsQ0FBQyxNQUFNLEVBQUUsTUFBTSwwRUE0Q3REIn0=
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc_server.d.ts","sourceRoot":"","sources":["../src/rpc_server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAepD;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,0EA4CtD"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
|
|
2
|
+
import { TXEDispatcherPool, buildSharedContractStore } from './dispatcher_pool.js';
|
|
3
|
+
import { TXEDispatcher, TXEDispatcherApiSchema } from './index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Symbol used to tag an incoming TCP socket with the `session_id` it has been associated with.
|
|
6
|
+
* Hidden under a Symbol so we don't risk colliding with anything koa or http core adds.
|
|
7
|
+
*/ const SESSION_SYMBOL = Symbol('txeSessionId');
|
|
8
|
+
/**
|
|
9
|
+
* Creates the TXE RPC server. With `TXE_WORKERS=1` oracle calls run on the main thread (no
|
|
10
|
+
* worker_threads, no IPC overhead). With any other value oracle calls are
|
|
11
|
+
* routed to a pool of worker threads sized to that value, sticky by `session_id`.
|
|
12
|
+
*
|
|
13
|
+
* Each incoming TCP socket is tagged with the `session_id` of the first oracle call it carries —
|
|
14
|
+
* nargo uses one HTTP client per test, so the socket-to-session mapping is 1:1. When the socket
|
|
15
|
+
* closes (end of test), the dispatcher disposes the session and frees its world state + LMDB.
|
|
16
|
+
*
|
|
17
|
+
* Lives in its own module so the worker bundle does not pull in the HTTP server stack.
|
|
18
|
+
*/ export async function createTXERpcServer(logger) {
|
|
19
|
+
const workerCount = Number(process.env.TXE_WORKERS);
|
|
20
|
+
let dispatcher;
|
|
21
|
+
if (workerCount === 1) {
|
|
22
|
+
const { dataDir, schnorrClassId } = await buildSharedContractStore();
|
|
23
|
+
dispatcher = new TXEDispatcher(logger, {
|
|
24
|
+
contractStoreSourceDir: dataDir,
|
|
25
|
+
schnorrClassId
|
|
26
|
+
});
|
|
27
|
+
} else {
|
|
28
|
+
dispatcher = new TXEDispatcherPool(logger, {
|
|
29
|
+
workers: Number.isFinite(workerCount) && workerCount > 1 ? workerCount : undefined
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const server = createSafeJsonRpcServer(dispatcher, TXEDispatcherApiSchema, {
|
|
33
|
+
http200OnError: true,
|
|
34
|
+
middlewares: [
|
|
35
|
+
async (ctx, next)=>{
|
|
36
|
+
// The body parser runs further down the chain, so `ctx.request.body` is populated only
|
|
37
|
+
// after `next()` resolves.
|
|
38
|
+
await next();
|
|
39
|
+
const socket = ctx.req.socket;
|
|
40
|
+
if (socket[SESSION_SYMBOL] !== undefined) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const body = ctx.request.body;
|
|
44
|
+
const sessionId = body && typeof body === 'object' && 'params' in body ? extractSessionId(body.params) : undefined;
|
|
45
|
+
if (sessionId === undefined) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
socket[SESSION_SYMBOL] = sessionId;
|
|
49
|
+
logger.debug(`Tagged socket with session`, {
|
|
50
|
+
sessionId,
|
|
51
|
+
remoteAddress: socket.remoteAddress,
|
|
52
|
+
remotePort: socket.remotePort
|
|
53
|
+
});
|
|
54
|
+
socket.once('close', ()=>{
|
|
55
|
+
logger.debug(`Disposing session on socket close`, {
|
|
56
|
+
sessionId
|
|
57
|
+
});
|
|
58
|
+
void dispatcher.disposeSession(sessionId);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
return server;
|
|
64
|
+
}
|
|
65
|
+
// Extracts `session_id` from a JSON-RPC `params` array. Always a `number` because session_id
|
|
66
|
+
// comes off `JSON.parse`, which never produces BigInt; values above MAX_SAFE_INTEGER lose
|
|
67
|
+
// precision but still work as a Map key.
|
|
68
|
+
function extractSessionId(params) {
|
|
69
|
+
if (!Array.isArray(params) || params.length === 0) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const first = params[0];
|
|
73
|
+
if (first && typeof first === 'object' && 'session_id' in first) {
|
|
74
|
+
const sid = first.session_id;
|
|
75
|
+
return typeof sid === 'number' ? sid : undefined;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|