@aztec/end-to-end 0.0.1-commit.b33fc05d0 → 0.0.1-commit.b3d3157a
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/README.md +27 -0
- package/dest/bench/client_flows/benchmark.d.ts +15 -1
- package/dest/bench/client_flows/benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/benchmark.js +17 -0
- package/dest/bench/client_flows/client_flows_benchmark.d.ts +2 -2
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +27 -38
- package/dest/bench/utils.d.ts +1 -1
- package/dest/bench/utils.d.ts.map +1 -1
- package/dest/bench/utils.js +2 -0
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts +5 -4
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.d.ts.map +1 -1
- package/dest/e2e_blacklist_token_contract/blacklist_token_contract_test.js +14 -5
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts +15 -4
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.d.ts.map +1 -1
- package/dest/e2e_cross_chain_messaging/cross_chain_messaging_test.js +39 -7
- package/dest/e2e_deploy_contract/deploy_test.d.ts +3 -3
- package/dest/e2e_deploy_contract/deploy_test.d.ts.map +1 -1
- package/dest/e2e_deploy_contract/deploy_test.js +2 -1
- package/dest/e2e_epochs/epochs_test.d.ts +25 -2
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +86 -13
- package/dest/e2e_fees/fees_test.d.ts +5 -2
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +32 -6
- package/dest/e2e_nested_contract/nested_contract_test.d.ts +3 -3
- package/dest/e2e_nested_contract/nested_contract_test.d.ts.map +1 -1
- package/dest/e2e_nested_contract/nested_contract_test.js +2 -1
- package/dest/e2e_p2p/inactivity_slash_test.d.ts +1 -1
- package/dest/e2e_p2p/inactivity_slash_test.d.ts.map +1 -1
- package/dest/e2e_p2p/inactivity_slash_test.js +4 -3
- package/dest/e2e_p2p/p2p_network.d.ts +10 -9
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +46 -27
- package/dest/e2e_p2p/reqresp/utils.d.ts +1 -1
- package/dest/e2e_p2p/reqresp/utils.d.ts.map +1 -1
- package/dest/e2e_p2p/reqresp/utils.js +29 -13
- package/dest/e2e_p2p/shared.d.ts +23 -14
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +62 -57
- package/dest/e2e_token_contract/token_contract_test.d.ts +3 -3
- package/dest/e2e_token_contract/token_contract_test.d.ts.map +1 -1
- package/dest/e2e_token_contract/token_contract_test.js +4 -2
- package/dest/fixtures/authwit_proxy.d.ts +1 -1
- package/dest/fixtures/authwit_proxy.d.ts.map +1 -1
- package/dest/fixtures/authwit_proxy.js +4 -0
- package/dest/fixtures/e2e_prover_test.d.ts +6 -5
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +9 -13
- package/dest/fixtures/fixtures.d.ts +70 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +65 -0
- package/dest/fixtures/get_bb_config.d.ts +1 -1
- package/dest/fixtures/get_bb_config.d.ts.map +1 -1
- package/dest/fixtures/get_bb_config.js +5 -5
- package/dest/fixtures/ha_setup.d.ts +2 -2
- package/dest/fixtures/ha_setup.d.ts.map +1 -1
- package/dest/fixtures/ha_setup.js +1 -1
- package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts +25 -0
- package/dest/fixtures/schnorr_hardcoded_account_contract.d.ts.map +1 -0
- package/dest/fixtures/schnorr_hardcoded_account_contract.js +37 -0
- package/dest/fixtures/setup.d.ts +44 -11
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +157 -28
- package/dest/fixtures/setup_p2p_test.d.ts +10 -6
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- package/dest/fixtures/setup_p2p_test.js +8 -8
- package/dest/fixtures/token_utils.d.ts +1 -1
- package/dest/fixtures/token_utils.d.ts.map +1 -1
- package/dest/fixtures/token_utils.js +2 -5
- package/dest/fixtures/utils.d.ts +2 -2
- package/dest/fixtures/utils.d.ts.map +1 -1
- package/dest/fixtures/utils.js +1 -1
- package/dest/forward-compatibility/wallet_rpc_client.d.ts +7 -0
- package/dest/forward-compatibility/wallet_rpc_client.d.ts.map +1 -0
- package/dest/forward-compatibility/wallet_rpc_client.js +15 -0
- package/dest/forward-compatibility/wallet_service.d.ts +3 -0
- package/dest/forward-compatibility/wallet_service.d.ts.map +1 -0
- package/dest/forward-compatibility/wallet_service.js +109 -0
- package/dest/install_legacy_contracts.d.cts +10 -0
- package/dest/install_legacy_contracts.d.cts.map +1 -0
- package/dest/legacy-jest-resolver.d.cts +3 -0
- package/dest/legacy-jest-resolver.d.cts.map +1 -0
- package/dest/shared/cross_chain_test_harness.d.ts +4 -2
- package/dest/shared/cross_chain_test_harness.d.ts.map +1 -1
- package/dest/shared/cross_chain_test_harness.js +9 -5
- package/dest/shared/gas_portal_test_harness.d.ts +8 -5
- package/dest/shared/gas_portal_test_harness.d.ts.map +1 -1
- package/dest/shared/gas_portal_test_harness.js +17 -8
- package/dest/shared/uniswap_l1_l2.d.ts +1 -1
- package/dest/shared/uniswap_l1_l2.d.ts.map +1 -1
- package/dest/shared/uniswap_l1_l2.js +50 -32
- package/dest/shared/wait_for_l1_to_l2_message.d.ts +13 -0
- package/dest/shared/wait_for_l1_to_l2_message.d.ts.map +1 -0
- package/dest/shared/wait_for_l1_to_l2_message.js +10 -0
- package/dest/simulators/lending_simulator.d.ts +10 -3
- package/dest/simulators/lending_simulator.d.ts.map +1 -1
- package/dest/simulators/lending_simulator.js +24 -12
- package/dest/simulators/token_simulator.js +1 -1
- package/dest/spartan/setup_test_wallets.d.ts +1 -1
- package/dest/spartan/setup_test_wallets.d.ts.map +1 -1
- package/dest/spartan/setup_test_wallets.js +72 -48
- package/dest/spartan/tx_metrics.d.ts +18 -4
- package/dest/spartan/tx_metrics.d.ts.map +1 -1
- package/dest/spartan/tx_metrics.js +73 -20
- package/dest/spartan/utils/config.d.ts +9 -35
- package/dest/spartan/utils/config.d.ts.map +1 -1
- package/dest/spartan/utils/nodes.js +2 -2
- package/dest/test-wallet/test_wallet.d.ts +25 -23
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +146 -87
- package/dest/test-wallet/utils.d.ts +3 -3
- package/dest/test-wallet/utils.d.ts.map +1 -1
- package/dest/test-wallet/utils.js +2 -7
- package/dest/test-wallet/wallet_worker_script.js +7 -2
- package/dest/test-wallet/worker_wallet.d.ts +5 -4
- package/dest/test-wallet/worker_wallet.d.ts.map +1 -1
- package/dest/test-wallet/worker_wallet.js +6 -2
- package/dest/test-wallet/worker_wallet_schema.d.ts +110 -224
- package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
- package/dest/test-wallet/worker_wallet_schema.js +14 -2
- package/package.json +46 -42
- package/src/bench/client_flows/benchmark.ts +19 -0
- package/src/bench/client_flows/client_flows_benchmark.ts +64 -53
- package/src/bench/utils.ts +2 -1
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +24 -10
- package/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +49 -11
- package/src/e2e_deploy_contract/deploy_test.ts +3 -2
- package/src/e2e_epochs/epochs_test.ts +98 -11
- package/src/e2e_fees/fees_test.ts +37 -4
- package/src/e2e_nested_contract/nested_contract_test.ts +3 -1
- package/src/e2e_p2p/inactivity_slash_test.ts +4 -3
- package/src/e2e_p2p/p2p_network.ts +57 -39
- package/src/e2e_p2p/reqresp/utils.ts +30 -12
- package/src/e2e_p2p/shared.ts +60 -71
- package/src/e2e_token_contract/token_contract_test.ts +12 -2
- package/src/fixtures/authwit_proxy.ts +4 -0
- package/src/fixtures/e2e_prover_test.ts +15 -18
- package/src/fixtures/fixtures.ts +83 -0
- package/src/fixtures/get_bb_config.ts +7 -6
- package/src/fixtures/ha_setup.ts +4 -2
- package/src/fixtures/schnorr_hardcoded_account_contract.ts +49 -0
- package/src/fixtures/setup.ts +186 -33
- package/src/fixtures/setup_p2p_test.ts +13 -9
- package/src/fixtures/token_utils.ts +1 -4
- package/src/fixtures/utils.ts +2 -0
- package/src/forward-compatibility/wallet_rpc_client.ts +14 -0
- package/src/forward-compatibility/wallet_service.ts +104 -0
- package/src/guides/up_quick_start.sh +0 -2
- package/src/install_legacy_contracts.cjs +75 -0
- package/src/legacy-jest-resolver.cjs +112 -0
- package/src/shared/cross_chain_test_harness.ts +14 -4
- package/src/shared/gas_portal_test_harness.ts +20 -10
- package/src/shared/uniswap_l1_l2.ts +84 -40
- package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
- package/src/simulators/lending_simulator.ts +28 -12
- package/src/simulators/token_simulator.ts +1 -1
- package/src/spartan/setup_test_wallets.ts +69 -43
- package/src/spartan/tx_metrics.ts +81 -23
- package/src/spartan/utils/nodes.ts +2 -2
- package/src/test-wallet/test_wallet.ts +174 -104
- package/src/test-wallet/utils.ts +3 -7
- package/src/test-wallet/wallet_worker_script.ts +5 -2
- package/src/test-wallet/worker_wallet.ts +10 -5
- package/src/test-wallet/worker_wallet_schema.ts +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
2
2
|
import type { Logger } from '@aztec/foundation/log';
|
|
3
|
-
import type {
|
|
3
|
+
import type { BlockResponse } from '@aztec/stdlib/interfaces/client';
|
|
4
4
|
import type { TopicType } from '@aztec/stdlib/p2p';
|
|
5
5
|
import { Tx, type TxReceipt } from '@aztec/stdlib/tx';
|
|
6
6
|
|
|
@@ -134,9 +134,12 @@ export class ProvingMetrics {
|
|
|
134
134
|
|
|
135
135
|
export type TxInclusionData = {
|
|
136
136
|
txHash: string;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
/** Wall-clock at client when the tx was submitted, in ms (Date.now()). */
|
|
138
|
+
sentAtMs: number;
|
|
139
|
+
/** Wall-clock at client when the block containing the tx first became visible, in ms (Date.now()). -1 if never observed. */
|
|
140
|
+
minedAtMs: number;
|
|
141
|
+
/** Reserved for future attestation-observed-at signal; -1 today. */
|
|
142
|
+
attestedAtMs: number;
|
|
140
143
|
blocknumber: number;
|
|
141
144
|
priorityFee: number;
|
|
142
145
|
totalFee: number;
|
|
@@ -147,7 +150,7 @@ export type TxInclusionData = {
|
|
|
147
150
|
export class TxInclusionMetrics {
|
|
148
151
|
private data = new Map<string, TxInclusionData>();
|
|
149
152
|
private groups = new Set<string>();
|
|
150
|
-
private blocks = new Map<number, Promise<
|
|
153
|
+
private blocks = new Map<number, Promise<BlockResponse<{ includeTransactions: true }> | undefined>>();
|
|
151
154
|
|
|
152
155
|
private p2pGossipLatencyByTopic: Partial<Record<TopicType, { p50: number; p95: number }>> = {};
|
|
153
156
|
|
|
@@ -174,9 +177,9 @@ export class TxInclusionMetrics {
|
|
|
174
177
|
|
|
175
178
|
this.data.set(txHash, {
|
|
176
179
|
txHash,
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
+
sentAtMs: Date.now(),
|
|
181
|
+
minedAtMs: -1,
|
|
182
|
+
attestedAtMs: -1,
|
|
180
183
|
blocknumber: -1,
|
|
181
184
|
priorityFee: Number(priorityFees.feePerDaGas + priorityFees.feePerL2Gas),
|
|
182
185
|
totalFee: -1,
|
|
@@ -186,6 +189,28 @@ export class TxInclusionMetrics {
|
|
|
186
189
|
this.groups.add(group);
|
|
187
190
|
}
|
|
188
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Stamp mined-at metadata for any tracked tx contained in this block, using
|
|
194
|
+
* `observedAtMs` (caller-supplied wall-clock at the moment they first saw the
|
|
195
|
+
* block). Idempotent: existing minedAtMs is preserved so the first observer
|
|
196
|
+
* wins (typically the block-watcher; recordMinedTx is a fallback).
|
|
197
|
+
*/
|
|
198
|
+
observeBlockForMinedTxs(
|
|
199
|
+
blockNumber: number,
|
|
200
|
+
txHashes: ReadonlyArray<{ toString(): string }>,
|
|
201
|
+
observedAtMs: number,
|
|
202
|
+
): void {
|
|
203
|
+
txHashes.forEach((txHash, position) => {
|
|
204
|
+
const data = this.data.get(txHash.toString());
|
|
205
|
+
if (!data || data.minedAtMs !== -1) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
data.blocknumber = blockNumber;
|
|
209
|
+
data.minedAtMs = observedAtMs;
|
|
210
|
+
data.positionInBlock = position;
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
189
214
|
async recordMinedTx(txReceipt: TxReceipt): Promise<void> {
|
|
190
215
|
const { txHash, blockNumber } = txReceipt;
|
|
191
216
|
if (!txReceipt.isMined() || !txReceipt.hasExecutionSucceeded() || !blockNumber) {
|
|
@@ -197,26 +222,43 @@ export class TxInclusionMetrics {
|
|
|
197
222
|
return;
|
|
198
223
|
}
|
|
199
224
|
|
|
200
|
-
if (!this.blocks.has(blockNumber)) {
|
|
201
|
-
this.blocks.set(blockNumber, this.aztecNode.getBlock(blockNumber));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const block = await this.blocks.get(blockNumber)!;
|
|
205
|
-
if (!block) {
|
|
206
|
-
this.logger?.warn('Failed to load block for mined tx receipt', { txHash: txHash.toString(), blockNumber });
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
225
|
const data = this.data.get(txHash.toString());
|
|
210
226
|
if (!data) {
|
|
211
227
|
const message = `Missing sent tx record for mined tx ${txHash.toString()}`;
|
|
212
228
|
this.logger?.warn(message, { txHash: txHash.toString(), blockNumber });
|
|
213
229
|
throw new Error(message);
|
|
214
230
|
}
|
|
215
|
-
data.blocknumber = blockNumber;
|
|
216
|
-
data.minedAt = Number(block.header.globalVariables.timestamp);
|
|
217
|
-
data.attestedAt = -1;
|
|
218
231
|
data.totalFee = Number(txReceipt.transactionFee ?? 0n);
|
|
219
|
-
|
|
232
|
+
|
|
233
|
+
// Fallback path for txs the block-watcher missed (e.g. observed only after
|
|
234
|
+
// the watcher stopped). Stamp with the block's L2 slot timestamp; this is
|
|
235
|
+
// earlier than the true client-observed time by attestation+propagation
|
|
236
|
+
// lag, but it's the only deterministic timestamp available post-hoc.
|
|
237
|
+
if (data.minedAtMs === -1) {
|
|
238
|
+
if (!this.blocks.has(blockNumber)) {
|
|
239
|
+
this.blocks.set(blockNumber, this.aztecNode.getBlock(blockNumber, { includeTransactions: true }));
|
|
240
|
+
}
|
|
241
|
+
const block = await this.blocks.get(blockNumber)!;
|
|
242
|
+
if (!block) {
|
|
243
|
+
this.logger?.warn('Failed to load block for mined tx receipt', { txHash: txHash.toString(), blockNumber });
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
data.blocknumber = blockNumber;
|
|
247
|
+
data.minedAtMs = Number(block.header.globalVariables.timestamp) * 1000;
|
|
248
|
+
data.positionInBlock = block.body.txEffects.findIndex(txEffect => txEffect.txHash.equals(txHash));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Per-tx inclusion records for a group. Used to serialise out for downstream tooling. */
|
|
253
|
+
getInclusionRecords(group?: string): TxInclusionData[] {
|
|
254
|
+
const out: TxInclusionData[] = [];
|
|
255
|
+
for (const tx of this.data.values()) {
|
|
256
|
+
if (group !== undefined && tx.group !== group) {
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
out.push({ ...tx });
|
|
260
|
+
}
|
|
261
|
+
return out;
|
|
220
262
|
}
|
|
221
263
|
|
|
222
264
|
public inclusionTimeInSeconds(group: string): {
|
|
@@ -229,12 +271,28 @@ export class TxInclusionMetrics {
|
|
|
229
271
|
p99: number;
|
|
230
272
|
} {
|
|
231
273
|
const histogram = createHistogram({});
|
|
274
|
+
let nonPositive = 0;
|
|
232
275
|
for (const tx of this.data.values()) {
|
|
233
|
-
if (!tx.blocknumber || tx.group !== group || tx.
|
|
276
|
+
if (!tx.blocknumber || tx.group !== group || tx.minedAtMs === -1) {
|
|
234
277
|
continue;
|
|
235
278
|
}
|
|
236
279
|
|
|
237
|
-
|
|
280
|
+
// Both timestamps are client wall-clock (ms). A negative delta should be
|
|
281
|
+
// impossible since the watcher stamps minedAtMs strictly after sentAtMs,
|
|
282
|
+
// but the fallback path (recordMinedTx via L2 slot timestamp) can stamp
|
|
283
|
+
// earlier than sentAtMs. perf_hooks.createHistogram rejects <=0; skip
|
|
284
|
+
// those instead of crashing.
|
|
285
|
+
const deltaMs = tx.minedAtMs - tx.sentAtMs;
|
|
286
|
+
if (deltaMs <= 0) {
|
|
287
|
+
nonPositive++;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
// Histogram is recorded in seconds (rounded) to match the existing
|
|
291
|
+
// toGithubActionBenchmarkJSON output unit; per-tx records carry the raw ms.
|
|
292
|
+
histogram.record(Math.max(1, Math.round(deltaMs / 1000)));
|
|
293
|
+
}
|
|
294
|
+
if (nonPositive > 0) {
|
|
295
|
+
this.logger?.debug(`Dropped ${nonPositive} tx inclusion samples with non-positive delta`, { group });
|
|
238
296
|
}
|
|
239
297
|
|
|
240
298
|
if (histogram.count === 0) {
|
|
@@ -71,7 +71,7 @@ export async function waitForProvenToAdvance(
|
|
|
71
71
|
// Get current proven block number
|
|
72
72
|
let initialProvenBlock: number;
|
|
73
73
|
try {
|
|
74
|
-
const tips = await node.
|
|
74
|
+
const tips = await node.getChainTips();
|
|
75
75
|
initialProvenBlock = Number(tips.proven.block.number);
|
|
76
76
|
log.info(`Current proven block: ${initialProvenBlock}. Waiting for it to increase...`);
|
|
77
77
|
} catch (err) {
|
|
@@ -82,7 +82,7 @@ export async function waitForProvenToAdvance(
|
|
|
82
82
|
await retryUntil(
|
|
83
83
|
async () => {
|
|
84
84
|
try {
|
|
85
|
-
const tips = await node.
|
|
85
|
+
const tips = await node.getChainTips();
|
|
86
86
|
const currentProvenBlock = Number(tips.proven.block.number);
|
|
87
87
|
const proposedBlock = Number(tips.proposed.number);
|
|
88
88
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { EcdsaKAccountContract, EcdsaRAccountContract } from '@aztec/accounts/ecdsa';
|
|
2
2
|
import { SchnorrAccountContract } from '@aztec/accounts/schnorr';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { StubEcdsaAccountContractArtifact, createStubEcdsaAccount } from '@aztec/accounts/stub/ecdsa';
|
|
4
|
+
import { StubSchnorrAccountContractArtifact, createStubSchnorrAccount } from '@aztec/accounts/stub/schnorr';
|
|
5
|
+
import { type Account, type AccountContract, NO_FROM } from '@aztec/aztec.js/account';
|
|
6
|
+
import type { CompleteAddress } from '@aztec/aztec.js/addresses';
|
|
5
7
|
import {
|
|
6
8
|
type CallIntent,
|
|
7
9
|
type ContractFunctionInteractionCallIntent,
|
|
@@ -13,21 +15,32 @@ import {
|
|
|
13
15
|
} from '@aztec/aztec.js/authorization';
|
|
14
16
|
import type { AztecNode } from '@aztec/aztec.js/node';
|
|
15
17
|
import { AccountManager, type SendOptions } from '@aztec/aztec.js/wallet';
|
|
18
|
+
import { TxSimulationResultWithAppOffset } from '@aztec/aztec.js/wallet';
|
|
16
19
|
import type { DefaultAccountEntrypointOptions } from '@aztec/entrypoints/account';
|
|
20
|
+
import { DefaultEntrypoint } from '@aztec/entrypoints/default';
|
|
17
21
|
import { Fq, Fr } from '@aztec/foundation/curves/bn254';
|
|
18
22
|
import { GrumpkinScalar } from '@aztec/foundation/curves/grumpkin';
|
|
19
|
-
import type {
|
|
23
|
+
import type { NotesFilter } from '@aztec/pxe/client/lazy';
|
|
20
24
|
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/config';
|
|
21
25
|
import { PXE, type PXECreationOptions, createPXE } from '@aztec/pxe/server';
|
|
22
26
|
import { AuthWitness } from '@aztec/stdlib/auth-witness';
|
|
23
27
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
24
|
-
import {
|
|
28
|
+
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
|
|
25
29
|
import { deriveSigningKey } from '@aztec/stdlib/keys';
|
|
26
30
|
import type { NoteDao } from '@aztec/stdlib/note';
|
|
27
|
-
import
|
|
31
|
+
import {
|
|
32
|
+
type BlockHeader,
|
|
33
|
+
type ContractOverrides,
|
|
34
|
+
SimulationOverrides,
|
|
35
|
+
type TxExecutionRequest,
|
|
36
|
+
type TxHash,
|
|
37
|
+
type TxReceipt,
|
|
38
|
+
} from '@aztec/stdlib/tx';
|
|
28
39
|
import { ExecutionPayload, mergeExecutionPayloads } from '@aztec/stdlib/tx';
|
|
29
|
-
import { BaseWallet, type
|
|
40
|
+
import { BaseWallet, type SimulateViaEntrypointOptions } from '@aztec/wallet-sdk/base-wallet';
|
|
41
|
+
import type { AccountType } from '@aztec/wallets/embedded';
|
|
30
42
|
|
|
43
|
+
import { DEFAULT_MIN_FEE_PADDING } from '../fixtures/fixtures.js';
|
|
31
44
|
import { AztecNodeProxy, ProvenTx } from './utils.js';
|
|
32
45
|
|
|
33
46
|
/**
|
|
@@ -36,6 +49,7 @@ import { AztecNodeProxy, ProvenTx } from './utils.js';
|
|
|
36
49
|
export interface AccountData {
|
|
37
50
|
secret: Fr;
|
|
38
51
|
salt: Fr;
|
|
52
|
+
type?: AccountType;
|
|
39
53
|
contract: AccountContract;
|
|
40
54
|
}
|
|
41
55
|
|
|
@@ -50,6 +64,7 @@ export class TestWallet extends BaseWallet {
|
|
|
50
64
|
private readonly nodeRef: AztecNodeProxy,
|
|
51
65
|
) {
|
|
52
66
|
super(pxe, nodeRef);
|
|
67
|
+
this.minFeePadding = DEFAULT_MIN_FEE_PADDING;
|
|
53
68
|
}
|
|
54
69
|
|
|
55
70
|
static async create(
|
|
@@ -63,7 +78,9 @@ export class TestWallet extends BaseWallet {
|
|
|
63
78
|
...overridePXEConfig,
|
|
64
79
|
});
|
|
65
80
|
const pxe = await createPXE(nodeRef, pxeConfig, options);
|
|
66
|
-
|
|
81
|
+
const wallet = new TestWallet(pxe, nodeRef);
|
|
82
|
+
await wallet.initStubClasses();
|
|
83
|
+
return wallet;
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
/**
|
|
@@ -76,108 +93,143 @@ export class TestWallet extends BaseWallet {
|
|
|
76
93
|
|
|
77
94
|
createSchnorrAccount(secret: Fr, salt: Fr, signingKey?: Fq): Promise<AccountManager> {
|
|
78
95
|
signingKey = signingKey ?? deriveSigningKey(secret);
|
|
79
|
-
|
|
80
|
-
secret,
|
|
81
|
-
salt,
|
|
82
|
-
contract: new SchnorrAccountContract(signingKey),
|
|
83
|
-
};
|
|
84
|
-
return this.createAccount(accountData);
|
|
96
|
+
return this.createAccount({ secret, salt, type: 'schnorr', contract: new SchnorrAccountContract(signingKey) });
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
createECDSARAccount(secret: Fr, salt: Fr, signingKey: Buffer): Promise<AccountManager> {
|
|
88
|
-
|
|
100
|
+
return this.createAccount({
|
|
89
101
|
secret,
|
|
90
102
|
salt,
|
|
103
|
+
type: 'ecdsasecp256r1',
|
|
91
104
|
contract: new EcdsaRAccountContract(signingKey),
|
|
92
|
-
};
|
|
93
|
-
return this.createAccount(accountData);
|
|
105
|
+
});
|
|
94
106
|
}
|
|
95
107
|
|
|
96
108
|
createECDSAKAccount(secret: Fr, salt: Fr, signingKey: Buffer): Promise<AccountManager> {
|
|
97
|
-
|
|
109
|
+
return this.createAccount({
|
|
98
110
|
secret,
|
|
99
111
|
salt,
|
|
112
|
+
type: 'ecdsasecp256k1',
|
|
100
113
|
contract: new EcdsaKAccountContract(signingKey),
|
|
101
|
-
};
|
|
102
|
-
return this.createAccount(accountData);
|
|
114
|
+
});
|
|
103
115
|
}
|
|
104
116
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
// Stub class ids, populated on wallet startup
|
|
118
|
+
// to avoid redundant work per simulation
|
|
119
|
+
private stubClassIds = new Map<AccountType, Fr>();
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Hashes and registers the stub class for every supported account type with PXE, populating
|
|
123
|
+
* stubClassIds. Called on wallet initialization.
|
|
124
|
+
*/
|
|
125
|
+
private async initStubClasses(): Promise<void> {
|
|
126
|
+
const { id: schnorrClassId } = await getContractClassFromArtifact(StubSchnorrAccountContractArtifact);
|
|
127
|
+
await this.pxe.registerContractClass(StubSchnorrAccountContractArtifact);
|
|
128
|
+
|
|
129
|
+
// ecdsa stubs share the same class id
|
|
130
|
+
const { id: ecdsaClassId } = await getContractClassFromArtifact(StubEcdsaAccountContractArtifact);
|
|
131
|
+
await this.pxe.registerContractClass(StubEcdsaAccountContractArtifact);
|
|
132
|
+
|
|
133
|
+
this.stubClassIds.set('schnorr', schnorrClassId);
|
|
134
|
+
this.stubClassIds.set('ecdsasecp256k1', ecdsaClassId);
|
|
135
|
+
this.stubClassIds.set('ecdsasecp256r1', ecdsaClassId);
|
|
124
136
|
}
|
|
125
|
-
protected accounts: Map<string, Account> = new Map();
|
|
126
137
|
|
|
127
138
|
/**
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* When this flag is true, simulateViaEntrypoint constructs a request using a fake account
|
|
131
|
-
* (and accepts contract overrides on the input) and the PXE emulates kernel effects without
|
|
132
|
-
* generating kernel witnesses. When false, simulateViaEntrypoint defers to the standard
|
|
133
|
-
* simulation path via the real account entrypoint.
|
|
139
|
+
* Builds contract overrides for all provided addresses by replacing their account contracts with stub implementations.
|
|
134
140
|
*/
|
|
135
|
-
|
|
141
|
+
protected async buildAccountOverrides(addresses: AztecAddress[]): Promise<ContractOverrides> {
|
|
142
|
+
const accounts = await this.getAccounts();
|
|
143
|
+
const contracts: ContractOverrides = {};
|
|
144
|
+
|
|
145
|
+
const filtered = accounts.filter(acc => addresses.some(addr => addr.equals(acc.item)));
|
|
146
|
+
|
|
147
|
+
for (const account of filtered) {
|
|
148
|
+
const address = account.item;
|
|
149
|
+
const originalAccount = await this.getAccountFromAddress(address);
|
|
150
|
+
const completeAddress = originalAccount.getCompleteAddress();
|
|
151
|
+
const contractInstance = await this.pxe.getContractInstance(completeAddress.address);
|
|
152
|
+
if (!contractInstance) {
|
|
153
|
+
throw new Error(
|
|
154
|
+
`No contract instance found for address: ${completeAddress.address} during account override building. This is a bug!`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const type = this.getTypeFor(address);
|
|
159
|
+
const stubClassId = this.stubClassIds.get(type);
|
|
160
|
+
if (!stubClassId) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`Stub class for account type '${type}' was not registered at wallet init. This is a bug — initStubClasses should cover every supported AccountType.`,
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
contracts[address.toString()] = {
|
|
167
|
+
instance: { ...contractInstance, currentContractClassId: stubClassId },
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return contracts;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
protected accounts: Map<string, { account: Account; type: AccountType }> = new Map();
|
|
136
175
|
|
|
137
|
-
|
|
138
|
-
this.
|
|
176
|
+
private getTypeFor(address: AztecAddress): AccountType {
|
|
177
|
+
return this.accounts.get(address.toString())?.type ?? 'schnorr';
|
|
139
178
|
}
|
|
140
179
|
|
|
141
|
-
|
|
142
|
-
this.
|
|
180
|
+
private getStubAccountFor(address: AztecAddress, completeAddress: CompleteAddress) {
|
|
181
|
+
return this.getTypeFor(address) === 'schnorr'
|
|
182
|
+
? createStubSchnorrAccount(completeAddress)
|
|
183
|
+
: createStubEcdsaAccount(completeAddress);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Controls how the test wallet simulates transactions:
|
|
188
|
+
* - `kernelless`: Skips kernel circuits but uses the real account contract. Default.
|
|
189
|
+
* - `kernelless-override`: Skips kernels and replaces the account with a stub that doesn't do authwit validation.
|
|
190
|
+
* - `full`: Uses real kernel circuits and real account contracts. Slow!
|
|
191
|
+
*/
|
|
192
|
+
private simulationMode: 'kernelless' | 'kernelless-override' | 'full' = 'kernelless';
|
|
193
|
+
|
|
194
|
+
setSimulationMode(mode: 'kernelless' | 'kernelless-override' | 'full') {
|
|
195
|
+
this.simulationMode = mode;
|
|
143
196
|
}
|
|
144
197
|
|
|
145
198
|
setMinFeePadding(value?: number) {
|
|
146
|
-
this.minFeePadding = value ??
|
|
199
|
+
this.minFeePadding = value ?? DEFAULT_MIN_FEE_PADDING;
|
|
147
200
|
}
|
|
148
201
|
|
|
149
202
|
protected getAccountFromAddress(address: AztecAddress): Promise<Account> {
|
|
150
|
-
|
|
151
|
-
if (address.equals(AztecAddress.ZERO)) {
|
|
152
|
-
account = new SignerlessAccount();
|
|
153
|
-
} else {
|
|
154
|
-
account = this.accounts.get(address?.toString() ?? '');
|
|
155
|
-
}
|
|
203
|
+
const entry = this.accounts.get(address?.toString() ?? '');
|
|
156
204
|
|
|
157
|
-
if (!
|
|
205
|
+
if (!entry) {
|
|
158
206
|
throw new Error(`Account not found in wallet for address: ${address}`);
|
|
159
207
|
}
|
|
160
208
|
|
|
161
|
-
return Promise.resolve(account);
|
|
209
|
+
return Promise.resolve(entry.account);
|
|
162
210
|
}
|
|
163
211
|
|
|
164
212
|
getAccounts() {
|
|
165
|
-
return Promise.resolve(
|
|
213
|
+
return Promise.resolve(
|
|
214
|
+
Array.from(this.accounts.values()).map(entry => ({ alias: '', item: entry.account.getAddress() })),
|
|
215
|
+
);
|
|
166
216
|
}
|
|
167
217
|
|
|
168
218
|
async createAccount(accountData?: AccountData): Promise<AccountManager> {
|
|
169
219
|
const secret = accountData?.secret ?? Fr.random();
|
|
170
220
|
const salt = accountData?.salt ?? Fr.random();
|
|
221
|
+
const type = accountData?.type ?? 'schnorr';
|
|
171
222
|
const contract = accountData?.contract ?? new SchnorrAccountContract(GrumpkinScalar.random());
|
|
172
223
|
|
|
173
|
-
const accountManager = await AccountManager.create(this, secret, contract, salt);
|
|
224
|
+
const accountManager = await AccountManager.create(this, secret, contract, { salt });
|
|
174
225
|
|
|
175
226
|
const instance = accountManager.getInstance();
|
|
176
227
|
const artifact = await contract.getContractArtifact();
|
|
177
228
|
|
|
178
229
|
await this.registerContract(instance, artifact, secret);
|
|
179
230
|
|
|
180
|
-
|
|
231
|
+
const address = accountManager.address.toString();
|
|
232
|
+
this.accounts.set(address, { account: await accountManager.getAccount(), type });
|
|
181
233
|
|
|
182
234
|
return accountManager;
|
|
183
235
|
}
|
|
@@ -220,62 +272,80 @@ export class TestWallet extends BaseWallet {
|
|
|
220
272
|
return account.createAuthWit(intentInnerHash, chainInfo);
|
|
221
273
|
}
|
|
222
274
|
|
|
223
|
-
/**
|
|
224
|
-
* Override simulateViaEntrypoint to use fake accounts for kernelless simulation
|
|
225
|
-
* when simulatedSimulations is enabled. Otherwise falls through to the real entrypoint path.
|
|
226
|
-
*/
|
|
227
275
|
protected override async simulateViaEntrypoint(
|
|
228
276
|
executionPayload: ExecutionPayload,
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (!this.simulatedSimulations) {
|
|
236
|
-
return super.simulateViaEntrypoint(
|
|
237
|
-
executionPayload,
|
|
238
|
-
from,
|
|
239
|
-
feeOptions,
|
|
240
|
-
scopes,
|
|
241
|
-
skipTxValidation,
|
|
242
|
-
skipFeeEnforcement,
|
|
243
|
-
);
|
|
244
|
-
}
|
|
277
|
+
opts: SimulateViaEntrypointOptions,
|
|
278
|
+
): Promise<TxSimulationResultWithAppOffset> {
|
|
279
|
+
const { from, feeOptions, additionalScopes, skipTxValidation, skipFeeEnforcement, sendMessagesAs } = opts;
|
|
280
|
+
const scopes = this.scopesFrom(from, additionalScopes);
|
|
281
|
+
const skipKernels = this.simulationMode !== 'full';
|
|
282
|
+
const useOverride = this.simulationMode === 'kernelless-override';
|
|
245
283
|
|
|
246
284
|
const feeExecutionPayload = await feeOptions.walletFeePaymentMethod?.getExecutionPayload();
|
|
247
|
-
const executionOptions: DefaultAccountEntrypointOptions = {
|
|
248
|
-
txNonce: Fr.random(),
|
|
249
|
-
cancellable: this.cancellableTransactions,
|
|
250
|
-
feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions,
|
|
251
|
-
};
|
|
252
285
|
const finalExecutionPayload = feeExecutionPayload
|
|
253
286
|
? mergeExecutionPayloads([feeExecutionPayload, executionPayload])
|
|
254
287
|
: executionPayload;
|
|
255
|
-
const { account: fromAccount, instance, artifact } = await this.getFakeAccountDataFor(from);
|
|
256
288
|
const chainInfo = await this.getChainInfo();
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
289
|
+
|
|
290
|
+
let overrides = opts.overrides;
|
|
291
|
+
let txRequest: TxExecutionRequest;
|
|
292
|
+
if (useOverride) {
|
|
293
|
+
const accountOverrides = await this.buildAccountOverrides(scopes);
|
|
294
|
+
overrides = new SimulationOverrides({
|
|
295
|
+
publicStorage: overrides?.publicStorage,
|
|
296
|
+
contracts: { ...overrides?.contracts, ...accountOverrides },
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (from === NO_FROM) {
|
|
301
|
+
const entrypoint = new DefaultEntrypoint();
|
|
302
|
+
txRequest = await entrypoint.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo);
|
|
303
|
+
} else {
|
|
304
|
+
let fromAccount: Account;
|
|
305
|
+
if (useOverride) {
|
|
306
|
+
const originalAccount = await this.getAccountFromAddress(from);
|
|
307
|
+
fromAccount = this.getStubAccountFor(from, originalAccount.getCompleteAddress());
|
|
308
|
+
} else {
|
|
309
|
+
fromAccount = await this.getAccountFromAddress(from);
|
|
310
|
+
}
|
|
311
|
+
const executionOptions: DefaultAccountEntrypointOptions = {
|
|
312
|
+
txNonce: Fr.random(),
|
|
313
|
+
cancellable: this.cancellableTransactions,
|
|
314
|
+
// If from is an address, feeOptions include the way the account contract should handle the fee payment
|
|
315
|
+
feePaymentMethodOptions: feeOptions.accountFeePaymentMethodOptions!,
|
|
316
|
+
};
|
|
317
|
+
txRequest = await fromAccount.createTxExecutionRequest(
|
|
318
|
+
finalExecutionPayload,
|
|
319
|
+
feeOptions.gasSettings,
|
|
320
|
+
chainInfo,
|
|
321
|
+
executionOptions,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const result = await this.pxe.simulateTx(txRequest, {
|
|
267
326
|
simulatePublic: true,
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
327
|
+
skipKernels,
|
|
328
|
+
skipFeeEnforcement,
|
|
329
|
+
skipTxValidation,
|
|
330
|
+
overrides,
|
|
271
331
|
scopes,
|
|
332
|
+
senderForTags: this.senderForTagsFrom(from, sendMessagesAs),
|
|
272
333
|
});
|
|
334
|
+
const appCallOffset = await this.computeAppCallOffset(from, feeOptions);
|
|
335
|
+
return TxSimulationResultWithAppOffset.fromResultAndOffset(result, appCallOffset);
|
|
273
336
|
}
|
|
274
337
|
|
|
275
338
|
async proveTx(exec: ExecutionPayload, opts: Omit<SendOptions, 'wait'>): Promise<ProvenTx> {
|
|
276
|
-
const fee = await this.completeFeeOptions(
|
|
339
|
+
const fee = await this.completeFeeOptions({
|
|
340
|
+
from: opts.from,
|
|
341
|
+
feePayer: exec.feePayer,
|
|
342
|
+
gasSettings: opts.fee?.gasSettings,
|
|
343
|
+
});
|
|
277
344
|
const txRequest = await this.createTxExecutionRequestFromPayloadAndFee(exec, opts.from, fee);
|
|
278
|
-
const txProvingResult = await this.pxe.proveTx(txRequest,
|
|
345
|
+
const txProvingResult = await this.pxe.proveTx(txRequest, {
|
|
346
|
+
scopes: this.scopesFrom(opts.from, opts.additionalScopes),
|
|
347
|
+
senderForTags: this.senderForTagsFrom(opts.from, opts.sendMessagesAs),
|
|
348
|
+
});
|
|
279
349
|
return new ProvenTx(
|
|
280
350
|
this.aztecNode,
|
|
281
351
|
await txProvingResult.toTx(),
|
|
@@ -297,7 +367,7 @@ export class TestWallet extends BaseWallet {
|
|
|
297
367
|
}
|
|
298
368
|
|
|
299
369
|
sync(): Promise<void> {
|
|
300
|
-
return this.pxe.
|
|
370
|
+
return this.pxe.sync();
|
|
301
371
|
}
|
|
302
372
|
|
|
303
373
|
stop(): Promise<void> {
|
package/src/test-wallet/utils.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BatchCall,
|
|
2
3
|
ContractFunctionInteraction,
|
|
3
4
|
DeployMethod,
|
|
4
5
|
type DeployOptions,
|
|
@@ -62,15 +63,10 @@ export class ProvenTx extends Tx {
|
|
|
62
63
|
|
|
63
64
|
export async function proveInteraction(
|
|
64
65
|
wallet: TestWallet,
|
|
65
|
-
interaction: ContractFunctionInteraction | DeployMethod,
|
|
66
|
+
interaction: ContractFunctionInteraction | DeployMethod | BatchCall,
|
|
66
67
|
options: SendInteractionOptions | DeployOptions,
|
|
67
68
|
) {
|
|
68
|
-
|
|
69
|
-
if (interaction instanceof DeployMethod) {
|
|
70
|
-
execPayload = await interaction.request(interaction.convertDeployOptionsToRequestOptions(options));
|
|
71
|
-
} else {
|
|
72
|
-
execPayload = await interaction.request(options);
|
|
73
|
-
}
|
|
69
|
+
const execPayload = await interaction.request(options);
|
|
74
70
|
return wallet.proveTx(execPayload, toSendOptions(options));
|
|
75
71
|
}
|
|
76
72
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createAztecNodeClient } from '@aztec/aztec.js/node';
|
|
2
2
|
import type { SendOptions } from '@aztec/aztec.js/wallet';
|
|
3
|
+
import { BackendType, BarretenbergSync } from '@aztec/bb.js';
|
|
3
4
|
import { jsonStringify } from '@aztec/foundation/json-rpc';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
5
6
|
import type { ApiSchema, Fr } from '@aztec/foundation/schemas';
|
|
6
|
-
import { parseWithOptionals, schemaHasMethod } from '@aztec/foundation/schemas';
|
|
7
|
+
import { getSchemaParameters, parseWithOptionals, schemaHasMethod } from '@aztec/foundation/schemas';
|
|
7
8
|
import { NodeListener, TransportServer } from '@aztec/foundation/transport';
|
|
8
9
|
import { ExecutionPayload, Tx } from '@aztec/stdlib/tx';
|
|
9
10
|
|
|
@@ -19,6 +20,8 @@ try {
|
|
|
19
20
|
|
|
20
21
|
logger.info('Initializing worker wallet', { nodeUrl });
|
|
21
22
|
const node = createAztecNodeClient(nodeUrl);
|
|
23
|
+
// Worker sync bb use is limited to crypto and proof serialization helpers.
|
|
24
|
+
await BarretenbergSync.initSingleton({ backend: BackendType.Wasm });
|
|
22
25
|
const wallet = await TestWallet.create(node, pxeConfig);
|
|
23
26
|
logger.info('Worker wallet initialized');
|
|
24
27
|
|
|
@@ -46,7 +49,7 @@ try {
|
|
|
46
49
|
throw new Error(`Unknown method: ${msg.fn}`);
|
|
47
50
|
}
|
|
48
51
|
const jsonParams = JSON.parse(msg.args) as unknown[];
|
|
49
|
-
const args: any[] = await parseWithOptionals(jsonParams, schema[msg.fn]
|
|
52
|
+
const args: any[] = await parseWithOptionals(jsonParams, getSchemaParameters(schema[msg.fn]));
|
|
50
53
|
// we have to erase the fn type in order to be able to spread ...args
|
|
51
54
|
const handler: ((...args: any[]) => Promise<any>) | undefined =
|
|
52
55
|
msg.fn in customMethods ? customMethods[msg.fn as keyof typeof customMethods] : undefined;
|