@aztec/txe 0.0.1-commit.7b86788 → 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 +39 -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 +36 -20
- package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
- package/dest/oracle/txe_oracle_top_level_context.js +125 -66
- 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 +567 -243
- 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 +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 +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 +64 -6
- package/dest/txe_session.d.ts.map +1 -1
- package/dest/txe_session.js +159 -31
- 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 +43 -34
- package/src/oracle/txe_oracle_public_context.ts +42 -12
- package/src/oracle/txe_oracle_top_level_context.ts +146 -77
- package/src/oracle/txe_private_execution_oracle.ts +30 -0
- package/src/rpc_server.ts +87 -0
- package/src/rpc_translator.ts +646 -326
- package/src/state_machine/archiver.ts +33 -18
- 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 +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 +253 -33
- 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,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,17 +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,
|
|
17
|
+
type ExecutionHooks,
|
|
20
18
|
NoteStore,
|
|
21
|
-
|
|
19
|
+
ORACLE_VERSION_MAJOR,
|
|
22
20
|
PrivateEventStore,
|
|
23
21
|
RecipientTaggingStore,
|
|
24
22
|
SenderAddressBookStore,
|
|
25
23
|
SenderTaggingStore,
|
|
24
|
+
composeHooks,
|
|
26
25
|
enrichPublicSimulationError,
|
|
27
26
|
} from '@aztec/pxe/server';
|
|
28
27
|
import {
|
|
@@ -64,6 +63,7 @@ import {
|
|
|
64
63
|
PrivateToPublicAccumulatedData,
|
|
65
64
|
PublicCallRequest,
|
|
66
65
|
} from '@aztec/stdlib/kernel';
|
|
66
|
+
import { hashPublicKey } from '@aztec/stdlib/keys';
|
|
67
67
|
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
68
68
|
import { makeGlobalVariables } from '@aztec/stdlib/testing';
|
|
69
69
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
@@ -80,13 +80,13 @@ import {
|
|
|
80
80
|
collectNested,
|
|
81
81
|
} from '@aztec/stdlib/tx';
|
|
82
82
|
import type { UInt64 } from '@aztec/stdlib/types';
|
|
83
|
-
import { ForkCheckpoint } from '@aztec/world-state';
|
|
83
|
+
import { ForkCheckpoint } from '@aztec/world-state/native';
|
|
84
84
|
|
|
85
85
|
import { DEFAULT_ADDRESS } from '../constants.js';
|
|
86
86
|
import type { TXEStateMachine } from '../state_machine/index.js';
|
|
87
|
-
import type { TXEAccountStore } from '../util/txe_account_store.js';
|
|
88
|
-
import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
|
|
89
87
|
import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
|
|
88
|
+
import type { TXEAccountStore } from '../utils/txe_account_store.js';
|
|
89
|
+
import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
|
|
90
90
|
import type { ITxeExecutionOracle } from './interfaces.js';
|
|
91
91
|
|
|
92
92
|
export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
|
|
@@ -116,22 +116,34 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
116
116
|
this.logger.debug('Entering Top Level Context');
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
private contractOracleVersion: { major: number; minor: number } | undefined;
|
|
120
|
+
|
|
121
|
+
assertCompatibleOracleVersion(major: number, minor: number): void {
|
|
122
|
+
if (major !== ORACLE_VERSION_MAJOR) {
|
|
123
|
+
const hint =
|
|
124
|
+
major > ORACLE_VERSION_MAJOR
|
|
125
|
+
? '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.'
|
|
126
|
+
: '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.';
|
|
121
127
|
throw new Error(
|
|
122
|
-
`Incompatible
|
|
128
|
+
`Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
|
|
123
129
|
);
|
|
124
130
|
}
|
|
131
|
+
this.contractOracleVersion = { major, minor };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
|
|
135
|
+
nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
|
|
136
|
+
return this.contractOracleVersion;
|
|
125
137
|
}
|
|
126
138
|
|
|
127
139
|
// This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
|
|
128
140
|
// setup.
|
|
129
|
-
|
|
141
|
+
getRandomField(): Fr {
|
|
130
142
|
return Fr.random();
|
|
131
143
|
}
|
|
132
144
|
|
|
133
145
|
// We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
|
|
134
|
-
|
|
146
|
+
log(level: number, message: string, fields: Fr[]): Promise<void> {
|
|
135
147
|
if (!LogLevels[level]) {
|
|
136
148
|
throw new Error(`Invalid log level: ${level}`);
|
|
137
149
|
}
|
|
@@ -141,25 +153,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
141
153
|
return Promise.resolve();
|
|
142
154
|
}
|
|
143
155
|
|
|
144
|
-
|
|
156
|
+
getDefaultAddress(): AztecAddress {
|
|
145
157
|
return DEFAULT_ADDRESS;
|
|
146
158
|
}
|
|
147
159
|
|
|
148
|
-
async
|
|
160
|
+
async getNextBlockNumber(): Promise<BlockNumber> {
|
|
149
161
|
return BlockNumber((await this.getLastBlockNumber()) + 1);
|
|
150
162
|
}
|
|
151
163
|
|
|
152
|
-
|
|
164
|
+
getNextBlockTimestamp(): Promise<bigint> {
|
|
153
165
|
return Promise.resolve(this.nextBlockTimestamp);
|
|
154
166
|
}
|
|
155
167
|
|
|
156
|
-
async
|
|
157
|
-
return (await this.stateMachine.node.
|
|
168
|
+
async getLastBlockTimestamp() {
|
|
169
|
+
return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
|
|
158
170
|
}
|
|
159
171
|
|
|
160
|
-
async
|
|
172
|
+
async getLastTxEffects() {
|
|
161
173
|
const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
|
|
162
|
-
const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
|
|
174
|
+
const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
|
|
163
175
|
|
|
164
176
|
if (block!.body.txEffects.length != 1) {
|
|
165
177
|
// Note that calls like env.mine() will result in blocks with no transactions, hitting this
|
|
@@ -168,12 +180,22 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
168
180
|
|
|
169
181
|
const txEffects = block!.body.txEffects[0];
|
|
170
182
|
|
|
171
|
-
|
|
183
|
+
const privateLogs = txEffects.privateLogs;
|
|
184
|
+
if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
|
|
185
|
+
throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
txHash: txEffects.txHash,
|
|
190
|
+
noteHashes: txEffects.noteHashes,
|
|
191
|
+
nullifiers: txEffects.nullifiers,
|
|
192
|
+
privateLogs,
|
|
193
|
+
};
|
|
172
194
|
}
|
|
173
195
|
|
|
174
196
|
async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
|
|
175
197
|
if (contractAddress.equals(DEFAULT_ADDRESS)) {
|
|
176
|
-
this.logger.debug(`Skipping sync in
|
|
198
|
+
this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
|
|
177
199
|
return;
|
|
178
200
|
}
|
|
179
201
|
|
|
@@ -190,7 +212,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
190
212
|
);
|
|
191
213
|
}
|
|
192
214
|
|
|
193
|
-
async
|
|
215
|
+
async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
|
|
194
216
|
return (
|
|
195
217
|
await this.privateEventStore.getPrivateEvents(selector, {
|
|
196
218
|
contractAddress,
|
|
@@ -201,7 +223,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
201
223
|
).map(e => e.packedEvent);
|
|
202
224
|
}
|
|
203
225
|
|
|
204
|
-
async
|
|
226
|
+
async advanceBlocksBy(blocks: number) {
|
|
205
227
|
this.logger.debug(`time traveling ${blocks} blocks`);
|
|
206
228
|
|
|
207
229
|
for (let i = 0; i < blocks; i++) {
|
|
@@ -209,24 +231,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
209
231
|
}
|
|
210
232
|
}
|
|
211
233
|
|
|
212
|
-
|
|
234
|
+
advanceTimestampBy(duration: UInt64) {
|
|
213
235
|
this.logger.debug(`time traveling ${duration} seconds`);
|
|
214
236
|
this.nextBlockTimestamp += duration;
|
|
215
237
|
}
|
|
216
238
|
|
|
217
|
-
|
|
239
|
+
private deploymentNullifier(address: AztecAddress): Promise<Fr> {
|
|
240
|
+
return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async deploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
|
|
218
244
|
// Emit deployment nullifier
|
|
219
245
|
await this.mineBlock({
|
|
220
|
-
nullifiers: [
|
|
221
|
-
await siloNullifier(
|
|
222
|
-
AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
|
|
223
|
-
instance.address.toField(),
|
|
224
|
-
),
|
|
225
|
-
],
|
|
246
|
+
nullifiers: [await this.deploymentNullifier(instance.address)],
|
|
226
247
|
});
|
|
227
248
|
|
|
228
249
|
if (!secret.equals(Fr.ZERO)) {
|
|
229
|
-
await this.
|
|
250
|
+
await this.addAccount(artifact, instance, secret);
|
|
230
251
|
} else {
|
|
231
252
|
await this.contractStore.addContractInstance(instance);
|
|
232
253
|
await this.contractStore.addContractArtifact(artifact);
|
|
@@ -234,7 +255,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
234
255
|
}
|
|
235
256
|
}
|
|
236
257
|
|
|
237
|
-
|
|
258
|
+
/**
|
|
259
|
+
* Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
|
|
260
|
+
*/
|
|
261
|
+
async mineDeploymentNullifiers(addresses: AztecAddress[]) {
|
|
262
|
+
await this.mineBlock({
|
|
263
|
+
nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async addAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
|
|
238
268
|
const partialAddress = await computePartialAddress(instance);
|
|
239
269
|
|
|
240
270
|
this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
|
|
@@ -249,7 +279,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
249
279
|
return completeAddress;
|
|
250
280
|
}
|
|
251
281
|
|
|
252
|
-
async
|
|
282
|
+
async createAccount(secret: Fr) {
|
|
253
283
|
// This is a foot gun !
|
|
254
284
|
const completeAddress = await this.keyStore.addAccount(secret, secret);
|
|
255
285
|
await this.accountStore.setAccount(completeAddress.address, completeAddress);
|
|
@@ -259,20 +289,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
259
289
|
return completeAddress;
|
|
260
290
|
}
|
|
261
291
|
|
|
262
|
-
async
|
|
292
|
+
async addAuthWitness(address: AztecAddress, messageHash: Fr) {
|
|
263
293
|
const account = await this.accountStore.getAccount(address);
|
|
264
|
-
const
|
|
294
|
+
const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
|
|
295
|
+
const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
|
|
265
296
|
|
|
266
297
|
const schnorr = new Schnorr();
|
|
267
|
-
const signature = await schnorr.constructSignature(messageHash
|
|
298
|
+
const signature = await schnorr.constructSignature(messageHash, privateKey);
|
|
268
299
|
|
|
269
|
-
const authWitness = new AuthWitness(messageHash,
|
|
300
|
+
const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
|
|
270
301
|
|
|
271
302
|
this.authwits.set(authWitness.requestHash.toString(), authWitness);
|
|
272
303
|
}
|
|
273
304
|
|
|
274
305
|
async mineBlock(options: { nullifiers?: Fr[] } = {}) {
|
|
275
|
-
const blockNumber = await this.
|
|
306
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
276
307
|
|
|
277
308
|
const txEffect = TxEffect.empty();
|
|
278
309
|
txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
|
|
@@ -296,14 +327,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
296
327
|
await this.stateMachine.handleL2Block(block);
|
|
297
328
|
}
|
|
298
329
|
|
|
299
|
-
async
|
|
300
|
-
from: AztecAddress,
|
|
330
|
+
async privateCallNewFlow(
|
|
331
|
+
from: AztecAddress | undefined,
|
|
301
332
|
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
302
333
|
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
303
334
|
args: Fr[],
|
|
304
335
|
argsHash: Fr = Fr.zero(),
|
|
305
336
|
isStaticCall: boolean = false,
|
|
337
|
+
additionalScopes: AztecAddress[] = [],
|
|
306
338
|
jobId: string,
|
|
339
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
340
|
+
gasSettings: GasSettings,
|
|
307
341
|
) {
|
|
308
342
|
this.logger.verbose(
|
|
309
343
|
`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
@@ -317,12 +351,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
317
351
|
throw new Error(message);
|
|
318
352
|
}
|
|
319
353
|
|
|
320
|
-
|
|
321
|
-
// empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
|
|
322
|
-
const effectiveScopes = from.isZero() ? [] : [from];
|
|
354
|
+
const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
|
|
323
355
|
|
|
324
356
|
// Sync notes before executing private function to discover notes from previous transactions
|
|
325
|
-
const utilityExecutor = async (call: FunctionCall, execScopes:
|
|
357
|
+
const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
|
|
326
358
|
await this.executeUtilityCall(call, execScopes, jobId);
|
|
327
359
|
};
|
|
328
360
|
|
|
@@ -333,16 +365,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
333
365
|
utilityExecutor,
|
|
334
366
|
blockHeader,
|
|
335
367
|
jobId,
|
|
336
|
-
|
|
368
|
+
scopes,
|
|
337
369
|
);
|
|
338
370
|
|
|
339
|
-
const blockNumber = await this.
|
|
371
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
340
372
|
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
344
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
345
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
373
|
+
const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
|
|
374
|
+
const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
|
|
346
375
|
|
|
347
376
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
348
377
|
|
|
@@ -376,17 +405,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
376
405
|
senderTaggingStore: this.senderTaggingStore,
|
|
377
406
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
378
407
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
379
|
-
|
|
408
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
380
409
|
privateEventStore: this.privateEventStore,
|
|
381
410
|
contractSyncService: this.stateMachine.contractSyncService,
|
|
382
411
|
jobId,
|
|
383
412
|
totalPublicCalldataCount: 0,
|
|
384
413
|
sideEffectCounter: minRevertibleSideEffectCounter,
|
|
385
|
-
scopes
|
|
414
|
+
scopes,
|
|
386
415
|
// In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
|
|
387
416
|
// contract would perform, including setting senderForTags.
|
|
388
417
|
senderForTags: from,
|
|
389
418
|
simulator,
|
|
419
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
420
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
421
|
+
hooks: composeHooks({
|
|
422
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
|
|
423
|
+
isStaticCall ? 'private view' : 'private',
|
|
424
|
+
authorizedUtilityCallTargets,
|
|
425
|
+
),
|
|
426
|
+
}),
|
|
390
427
|
});
|
|
391
428
|
|
|
392
429
|
// 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.
|
|
@@ -409,7 +446,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
409
446
|
);
|
|
410
447
|
const publicFunctionsCalldata = await Promise.all(
|
|
411
448
|
publicCallRequests.map(async r => {
|
|
412
|
-
const calldata = await privateExecutionOracle.
|
|
449
|
+
const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
|
|
413
450
|
return new HashedValues(calldata, r.calldataHash);
|
|
414
451
|
}),
|
|
415
452
|
);
|
|
@@ -494,11 +531,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
494
531
|
}
|
|
495
532
|
}
|
|
496
533
|
|
|
534
|
+
// Walk the nested private-call tree and collect every offchain effect the transaction emitted.
|
|
535
|
+
// PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
|
|
536
|
+
// `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
|
|
537
|
+
// we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
|
|
538
|
+
const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
|
|
539
|
+
|
|
497
540
|
if (isStaticCall) {
|
|
498
541
|
await checkpoint!.revert();
|
|
499
542
|
|
|
500
543
|
await forkedWorldTrees.close();
|
|
501
|
-
return executionResult.returnValues ?? [];
|
|
544
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
502
545
|
}
|
|
503
546
|
|
|
504
547
|
const txEffect = TxEffect.empty();
|
|
@@ -520,26 +563,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
520
563
|
|
|
521
564
|
await forkedWorldTrees.close();
|
|
522
565
|
|
|
523
|
-
return executionResult.returnValues ?? [];
|
|
566
|
+
return { returnValues: executionResult.returnValues ?? [], offchainEffects };
|
|
524
567
|
}
|
|
525
568
|
|
|
526
|
-
async
|
|
527
|
-
from: AztecAddress,
|
|
569
|
+
async publicCallNewFlow(
|
|
570
|
+
from: AztecAddress | undefined,
|
|
528
571
|
targetContractAddress: AztecAddress,
|
|
529
572
|
calldata: Fr[],
|
|
530
573
|
isStaticCall: boolean,
|
|
574
|
+
gasSettings: GasSettings,
|
|
531
575
|
) {
|
|
532
576
|
this.logger.verbose(
|
|
533
577
|
`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
534
578
|
);
|
|
535
579
|
|
|
536
|
-
const blockNumber = await this.
|
|
537
|
-
|
|
538
|
-
const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
539
|
-
|
|
540
|
-
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
|
|
541
|
-
|
|
542
|
-
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
580
|
+
const blockNumber = await this.getNextBlockNumber();
|
|
543
581
|
|
|
544
582
|
const txContext = new TxContext(this.chainId, this.version, gasSettings);
|
|
545
583
|
|
|
@@ -592,7 +630,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
592
630
|
// may require producing reverts.
|
|
593
631
|
const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
|
|
594
632
|
revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
|
|
595
|
-
from,
|
|
633
|
+
from ?? AztecAddress.NULL_MSG_SENDER,
|
|
596
634
|
targetContractAddress,
|
|
597
635
|
isStaticCall,
|
|
598
636
|
calldataHash,
|
|
@@ -678,11 +716,12 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
678
716
|
return returnValues ?? [];
|
|
679
717
|
}
|
|
680
718
|
|
|
681
|
-
async
|
|
719
|
+
async executeUtilityFunction(
|
|
682
720
|
targetContractAddress: AztecAddress,
|
|
683
721
|
functionSelector: FunctionSelector,
|
|
684
722
|
args: Fr[],
|
|
685
723
|
jobId: string,
|
|
724
|
+
authorizedUtilityCallTargets: AztecAddress[],
|
|
686
725
|
) {
|
|
687
726
|
const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
688
727
|
if (!artifact) {
|
|
@@ -699,7 +738,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
699
738
|
},
|
|
700
739
|
blockHeader,
|
|
701
740
|
jobId,
|
|
702
|
-
|
|
741
|
+
await this.keyStore.getAccounts(),
|
|
703
742
|
);
|
|
704
743
|
|
|
705
744
|
const call = FunctionCall.from({
|
|
@@ -713,10 +752,15 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
713
752
|
returnTypes: [],
|
|
714
753
|
});
|
|
715
754
|
|
|
716
|
-
return this.executeUtilityCall(call,
|
|
755
|
+
return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
|
|
717
756
|
}
|
|
718
757
|
|
|
719
|
-
private async executeUtilityCall(
|
|
758
|
+
private async executeUtilityCall(
|
|
759
|
+
call: FunctionCall,
|
|
760
|
+
scopes: AztecAddress[],
|
|
761
|
+
jobId: string,
|
|
762
|
+
authorizedUtilityCallTargets: AztecAddress[] = [],
|
|
763
|
+
): Promise<Fr[]> {
|
|
720
764
|
const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
|
|
721
765
|
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
722
766
|
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
@@ -729,6 +773,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
729
773
|
|
|
730
774
|
try {
|
|
731
775
|
const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
|
|
776
|
+
const simulator = new WASMSimulator();
|
|
777
|
+
const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
|
|
778
|
+
await this.executeUtilityCall(syncCall, execScopes, jobId);
|
|
779
|
+
};
|
|
732
780
|
const oracle = new UtilityExecutionOracle({
|
|
733
781
|
contractAddress: call.to,
|
|
734
782
|
authWitnesses: [],
|
|
@@ -741,12 +789,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
741
789
|
aztecNode: this.stateMachine.node,
|
|
742
790
|
recipientTaggingStore: this.recipientTaggingStore,
|
|
743
791
|
senderAddressBookStore: this.senderAddressBookStore,
|
|
744
|
-
|
|
792
|
+
capsuleService: new CapsuleService(this.capsuleStore, scopes),
|
|
745
793
|
privateEventStore: this.privateEventStore,
|
|
794
|
+
messageContextService: this.stateMachine.messageContextService,
|
|
795
|
+
contractSyncService: this.stateMachine.contractSyncService,
|
|
796
|
+
l2TipsStore: this.stateMachine.l2TipsProvider,
|
|
746
797
|
jobId,
|
|
747
798
|
scopes,
|
|
799
|
+
simulator,
|
|
800
|
+
hooks: composeHooks({
|
|
801
|
+
authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
|
|
802
|
+
}),
|
|
803
|
+
utilityExecutor,
|
|
748
804
|
});
|
|
749
|
-
const acirExecutionResult = await
|
|
805
|
+
const acirExecutionResult = await simulator
|
|
750
806
|
.executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
|
|
751
807
|
.catch((err: Error) => {
|
|
752
808
|
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
@@ -774,7 +830,20 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
|
|
|
774
830
|
}
|
|
775
831
|
|
|
776
832
|
private async getLastBlockNumber(): Promise<BlockNumber> {
|
|
777
|
-
const
|
|
778
|
-
return
|
|
833
|
+
const block = await this.stateMachine.node.getBlock('latest');
|
|
834
|
+
return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
private buildAuthorizeUtilityCallHook(
|
|
838
|
+
callerContext: 'private' | 'private view' | 'utility',
|
|
839
|
+
authorizedTargets: AztecAddress[],
|
|
840
|
+
): ExecutionHooks['authorizeUtilityCall'] | undefined {
|
|
841
|
+
if (authorizedTargets.length === 0) {
|
|
842
|
+
return undefined;
|
|
843
|
+
}
|
|
844
|
+
return req =>
|
|
845
|
+
Promise.resolve({
|
|
846
|
+
authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
|
|
847
|
+
});
|
|
779
848
|
}
|
|
780
849
|
}
|
|
@@ -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
|
+
}
|