@aztec/end-to-end 0.0.1-commit.b2a5d0dd1 → 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/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 +13 -9
- 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 +3 -3
- 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 +13 -4
- 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 +8 -2
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +30 -7
- 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 +29 -3
- 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 +1 -0
- 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 +28 -12
- package/dest/e2e_p2p/shared.d.ts +19 -8
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +33 -13
- 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/e2e_prover_test.d.ts +3 -3
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +2 -1
- package/dest/fixtures/fixtures.d.ts +59 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +55 -0
- package/dest/fixtures/schnorr_hardcoded_account_contract.js +2 -4
- package/dest/fixtures/setup.d.ts +30 -4
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +117 -7
- package/dest/fixtures/setup_p2p_test.d.ts +5 -1
- package/dest/fixtures/setup_p2p_test.d.ts.map +1 -1
- 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/install_legacy_contracts.d.cts +10 -0
- package/dest/install_legacy_contracts.d.cts.map +1 -0
- package/dest/legacy-jest-resolver.d.cts +1 -1
- package/dest/legacy-jest-resolver.d.cts.map +1 -1
- 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 +16 -7
- 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 -28
- 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 +23 -11
- 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 +9 -3
- 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 +3 -2
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +49 -27
- 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 +2 -1
- 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 -229
- 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 +45 -41
- package/src/bench/client_flows/benchmark.ts +19 -0
- package/src/bench/client_flows/client_flows_benchmark.ts +32 -30
- package/src/bench/utils.ts +2 -1
- package/src/e2e_blacklist_token_contract/blacklist_token_contract_test.ts +21 -4
- 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 +32 -5
- package/src/e2e_fees/fees_test.ts +33 -2
- package/src/e2e_nested_contract/nested_contract_test.ts +3 -1
- package/src/e2e_p2p/inactivity_slash_test.ts +1 -0
- package/src/e2e_p2p/reqresp/utils.ts +29 -11
- package/src/e2e_p2p/shared.ts +31 -12
- package/src/e2e_token_contract/token_contract_test.ts +12 -2
- package/src/fixtures/e2e_prover_test.ts +3 -1
- package/src/fixtures/fixtures.ts +61 -0
- package/src/fixtures/schnorr_hardcoded_account_contract.ts +2 -2
- package/src/fixtures/setup.ts +134 -10
- package/src/fixtures/setup_p2p_test.ts +4 -0
- package/src/fixtures/utils.ts +2 -0
- package/src/install_legacy_contracts.cjs +75 -0
- package/src/legacy-jest-resolver.cjs +25 -48
- package/src/shared/cross_chain_test_harness.ts +14 -4
- package/src/shared/gas_portal_test_harness.ts +20 -9
- package/src/shared/uniswap_l1_l2.ts +84 -36
- package/src/shared/wait_for_l1_to_l2_message.ts +23 -0
- package/src/simulators/lending_simulator.ts +27 -13
- package/src/spartan/setup_test_wallets.ts +6 -4
- package/src/spartan/tx_metrics.ts +81 -23
- package/src/spartan/utils/nodes.ts +2 -2
- package/src/test-wallet/test_wallet.ts +46 -23
- 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 +7 -3
- package/src/test-wallet/worker_wallet_schema.ts +2 -2
package/src/e2e_p2p/shared.ts
CHANGED
|
@@ -56,7 +56,9 @@ export const submitTransactions = async (
|
|
|
56
56
|
rpcConfig.proverEnabled = false;
|
|
57
57
|
const wallet = await TestWallet.create(
|
|
58
58
|
node,
|
|
59
|
-
|
|
59
|
+
// Use checkpointed chain tip to avoid anchoring on provisional blocks that the archiver can prune
|
|
60
|
+
// when their slot ends without a checkpoint landing on L1.
|
|
61
|
+
{ ...getPXEConfig(), proverEnabled: false, syncChainTip: 'checkpointed' },
|
|
60
62
|
{ loggerActorLabel: 'pxe-tx' },
|
|
61
63
|
);
|
|
62
64
|
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
@@ -79,7 +81,7 @@ export async function prepareTransactions(
|
|
|
79
81
|
|
|
80
82
|
const wallet = await TestWallet.create(
|
|
81
83
|
node,
|
|
82
|
-
{ ...getPXEConfig(), proverEnabled: false },
|
|
84
|
+
{ ...getPXEConfig(), proverEnabled: false, syncChainTip: 'checkpointed' },
|
|
83
85
|
{ loggerActorLabel: 'pxe-tx' },
|
|
84
86
|
);
|
|
85
87
|
const accountContract = new SchnorrHardcodedKeyAccountContract();
|
|
@@ -146,12 +148,21 @@ export async function awaitCommitteeExists({
|
|
|
146
148
|
}
|
|
147
149
|
|
|
148
150
|
/**
|
|
149
|
-
* Advance epochs until we find one where the target proposer is selected for at least
|
|
150
|
-
* then stop one epoch before it. This leaves time for the caller to
|
|
151
|
-
* warping to the target epoch, avoiding the race where the target epoch
|
|
152
|
-
* are ready.
|
|
151
|
+
* Advance epochs until we find one where the target proposer is selected for a slot at least
|
|
152
|
+
* `warmupSlots` into the epoch, then stop one epoch before it. This leaves time for the caller to
|
|
153
|
+
* start sequencers before warping to the target epoch, avoiding the race where the target epoch
|
|
154
|
+
* passes before sequencers are ready.
|
|
153
155
|
*
|
|
154
|
-
*
|
|
156
|
+
* The first `warmupSlots` slots of the epoch are skipped on purpose. Callers warp to one slot
|
|
157
|
+
* before the target epoch and, under proposer pipelining, the proposer begins building one slot
|
|
158
|
+
* before its proposal slot. If the proposer were in the first slot of the epoch, that build would
|
|
159
|
+
* begin at the exact instant of the warp, leaving the freshly-started sequencer no warm-up margin;
|
|
160
|
+
* it then serializes its (often AVM-heavy) proposal past the slot boundary and honest receivers
|
|
161
|
+
* reject it as late. Picking a slot at least `warmupSlots` into the epoch guarantees that many full
|
|
162
|
+
* slots of wall-clock between the warp and the start of the proposer's build.
|
|
163
|
+
*
|
|
164
|
+
* Returns the target epoch and the concrete target slot so the caller can warp to it after starting
|
|
165
|
+
* sequencers.
|
|
155
166
|
*/
|
|
156
167
|
export async function advanceToEpochBeforeProposer({
|
|
157
168
|
epochCache,
|
|
@@ -159,13 +170,15 @@ export async function advanceToEpochBeforeProposer({
|
|
|
159
170
|
targetProposer,
|
|
160
171
|
logger,
|
|
161
172
|
maxAttempts = 20,
|
|
173
|
+
warmupSlots = 1,
|
|
162
174
|
}: {
|
|
163
175
|
epochCache: EpochCacheInterface;
|
|
164
176
|
cheatCodes: RollupCheatCodes;
|
|
165
177
|
targetProposer: EthAddress;
|
|
166
178
|
logger: Logger;
|
|
167
179
|
maxAttempts?: number;
|
|
168
|
-
|
|
180
|
+
warmupSlots?: number;
|
|
181
|
+
}): Promise<{ targetEpoch: EpochNumber; targetSlot: SlotNumber }> {
|
|
169
182
|
const { epochDuration } = await cheatCodes.getConfig();
|
|
170
183
|
|
|
171
184
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
@@ -173,8 +186,11 @@ export async function advanceToEpochBeforeProposer({
|
|
|
173
186
|
// Check the NEXT epoch's slots so we stay one epoch before the target,
|
|
174
187
|
// giving the caller time to start sequencers before the target epoch arrives.
|
|
175
188
|
const nextEpoch = Number(currentEpoch) + 1;
|
|
176
|
-
const
|
|
177
|
-
|
|
189
|
+
const epochStartSlot = nextEpoch * Number(epochDuration);
|
|
190
|
+
// Skip the first `warmupSlots` slots so the caller keeps a warm-up margin after warping to one
|
|
191
|
+
// slot before the epoch (see the doc comment above).
|
|
192
|
+
const startSlot = epochStartSlot + warmupSlots;
|
|
193
|
+
const endSlot = epochStartSlot + Number(epochDuration);
|
|
178
194
|
|
|
179
195
|
logger.info(
|
|
180
196
|
`Checking next epoch ${nextEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer} (current epoch: ${currentEpoch})`,
|
|
@@ -186,7 +202,7 @@ export async function advanceToEpochBeforeProposer({
|
|
|
186
202
|
logger.warn(
|
|
187
203
|
`Found target proposer ${targetProposer} in slot ${s} of epoch ${nextEpoch}. Staying at epoch ${currentEpoch} to allow sequencer startup.`,
|
|
188
204
|
);
|
|
189
|
-
return { targetEpoch: EpochNumber(nextEpoch) };
|
|
205
|
+
return { targetEpoch: EpochNumber(nextEpoch), targetSlot: SlotNumber(s) };
|
|
190
206
|
}
|
|
191
207
|
}
|
|
192
208
|
|
|
@@ -279,7 +295,10 @@ export async function awaitCommitteeKicked({
|
|
|
279
295
|
expect(attesterInfo.status).toEqual(1); // Validating
|
|
280
296
|
}
|
|
281
297
|
|
|
282
|
-
|
|
298
|
+
// Allow up to four round-lengths so that under proposer pipelining, where individual rounds
|
|
299
|
+
// sometimes fail to gather quorum because parts of the committee miss votes due to chain-state
|
|
300
|
+
// races, we still see a later round execute the slash.
|
|
301
|
+
const timeout = slashingRoundSize * 4 * aztecSlotDuration + 30;
|
|
283
302
|
logger.info(`Waiting for slash to be executed (timeout ${timeout}s)`);
|
|
284
303
|
await awaitProposalExecution(slashingProposer, timeout, logger);
|
|
285
304
|
|
|
@@ -7,7 +7,15 @@ import { InvalidAccountContract } from '@aztec/noir-test-contracts.js/InvalidAcc
|
|
|
7
7
|
|
|
8
8
|
import { jest } from '@jest/globals';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
type EndToEndContext,
|
|
12
|
+
type SetupOptions,
|
|
13
|
+
deployAccounts,
|
|
14
|
+
ensureAuthRegistryPublished,
|
|
15
|
+
publicDeployAccounts,
|
|
16
|
+
setup,
|
|
17
|
+
teardown,
|
|
18
|
+
} from '../fixtures/setup.js';
|
|
11
19
|
import { mintTokensToPrivate } from '../fixtures/token_utils.js';
|
|
12
20
|
import { TokenSimulator } from '../simulators/token_simulator.js';
|
|
13
21
|
import type { TestWallet } from '../test-wallet/test_wallet.js';
|
|
@@ -77,6 +85,7 @@ export class TokenContractTest {
|
|
|
77
85
|
[this.adminAddress, this.account1Address, this.account2Address] = deployedAccounts.map(acc => acc.address);
|
|
78
86
|
|
|
79
87
|
this.logger.info('Applying base setup - deploying token contract');
|
|
88
|
+
await ensureAuthRegistryPublished(this.wallet, this.adminAddress);
|
|
80
89
|
this.logger.verbose(`Public deploy accounts...`);
|
|
81
90
|
await publicDeployAccounts(this.wallet, [this.adminAddress, this.account1Address]);
|
|
82
91
|
|
|
@@ -115,8 +124,9 @@ export class TokenContractTest {
|
|
|
115
124
|
);
|
|
116
125
|
}
|
|
117
126
|
|
|
118
|
-
async setup() {
|
|
127
|
+
async setup(opts: Partial<SetupOptions> = {}) {
|
|
119
128
|
this.context = await setup(0, {
|
|
129
|
+
...opts,
|
|
120
130
|
metricsPort: this.metricsPort,
|
|
121
131
|
fundSponsoredFPC: true,
|
|
122
132
|
skipAccountDeployment: true,
|
|
@@ -24,6 +24,7 @@ import { getACVMConfig } from './get_acvm_config.js';
|
|
|
24
24
|
import { getBBConfig } from './get_bb_config.js';
|
|
25
25
|
import {
|
|
26
26
|
type EndToEndContext,
|
|
27
|
+
type SetupOptions,
|
|
27
28
|
deployAccounts,
|
|
28
29
|
getPrivateKeyFromIndex,
|
|
29
30
|
getSponsoredFPCAddress,
|
|
@@ -124,9 +125,10 @@ export class FullProverTest {
|
|
|
124
125
|
);
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
async setup() {
|
|
128
|
+
async setup(opts: Partial<SetupOptions> = {}) {
|
|
128
129
|
this.logger.info('Setting up subsystems from fresh');
|
|
129
130
|
this.context = await setup(0, {
|
|
131
|
+
...opts,
|
|
130
132
|
startProverNode: true,
|
|
131
133
|
coinbase: this.coinbase,
|
|
132
134
|
fundSponsoredFPC: true,
|
package/src/fixtures/fixtures.ts
CHANGED
|
@@ -12,6 +12,67 @@ export const DEFAULT_MIN_FEE_PADDING = 5;
|
|
|
12
12
|
*/
|
|
13
13
|
export const LARGE_MIN_FEE_PADDING = 15;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Fee padding used by tests running under proposer pipelining. Under pipelining the fee-asset
|
|
17
|
+
* price modifier evolves faster across the build/publish gap, so client-set maxFeesPerGas (sized
|
|
18
|
+
* for the default 5x padding) was getting bumped past by the time the tx mined a few slots later.
|
|
19
|
+
* Observed worst case in CI: fee evolved ~20x between PXE snapshot and inclusion, exceeding even
|
|
20
|
+
* LARGE_MIN_FEE_PADDING (15x).
|
|
21
|
+
*/
|
|
22
|
+
export const PIPELINED_FEE_PADDING = 30;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Setup option preset that opts a test into proposer pipelining. Use with `setup()`:
|
|
26
|
+
*
|
|
27
|
+
* await setup(N, { ...PIPELINING_SETUP_OPTS, ...otherOpts });
|
|
28
|
+
*
|
|
29
|
+
* The preset sets:
|
|
30
|
+
* - `inboxLag: 2` so the sequencer sources L1->L2 messages from checkpoint N-1 (already sealed),
|
|
31
|
+
* avoiding `L1ToL2MessagesNotReadyError` when building for slot N during slot N-1.
|
|
32
|
+
* - `minTxsPerBlock: 0` so empty checkpoints land even when a tx arrives late in the build window
|
|
33
|
+
* (otherwise the chain stalls on alternating slots).
|
|
34
|
+
* - `aztecSlotDuration: 12` / `ethereumSlotDuration: 4` so the pipelined cycle fits inside the
|
|
35
|
+
* default 300s Jest hook budget. Tests that depend on the env-default 72s/12s should override.
|
|
36
|
+
* - `walletMinFeePadding: PIPELINED_FEE_PADDING` (30x) to absorb the wider fee evolution window.
|
|
37
|
+
*/
|
|
38
|
+
export const PIPELINING_SETUP_OPTS = {
|
|
39
|
+
inboxLag: 2,
|
|
40
|
+
minTxsPerBlock: 0,
|
|
41
|
+
aztecSlotDuration: 12,
|
|
42
|
+
ethereumSlotDuration: 4,
|
|
43
|
+
walletMinFeePadding: PIPELINED_FEE_PADDING,
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Setup option preset that opts a test into the deterministic AutomineSequencer path.
|
|
48
|
+
* Use only for single-sequencer tests that don't exercise block-building or consensus
|
|
49
|
+
* (e.g. e2e_token, e2e_amm, e2e_authwit). Not compatible with `e2e_p2p/*`,
|
|
50
|
+
* `e2e_epochs/*`, `e2e_slashing/*`, `e2e_block_building`, or any multi-validator suite.
|
|
51
|
+
*
|
|
52
|
+
* await setup(N, { ...AUTOMINE_E2E_OPTS, ...otherOpts });
|
|
53
|
+
*
|
|
54
|
+
* The preset:
|
|
55
|
+
* - Swaps the production Sequencer for an AutomineSequencer that builds one block per
|
|
56
|
+
* submitted tx, publishes synchronously to L1, and owns all time control through a
|
|
57
|
+
* serial queue (see `sequencer-client/src/sequencer/automine/automine_sequencer.ts`).
|
|
58
|
+
* - Disables the validator client and AnvilTestWatcher (the AutomineSequencer needs
|
|
59
|
+
* neither).
|
|
60
|
+
* - Uses `inboxLag: 1` (synchronous) since the AutomineSequencer publishes one block per tx.
|
|
61
|
+
* - Switches anvil into automine mode at setup time (no interval mining); each L1 tx
|
|
62
|
+
* mines an L1 block immediately.
|
|
63
|
+
*
|
|
64
|
+
* Requires `aztecTargetCommitteeSize: 0`, which is the e2e default at `setup.ts:317`.
|
|
65
|
+
*/
|
|
66
|
+
export const AUTOMINE_E2E_OPTS = {
|
|
67
|
+
useAutomineSequencer: true,
|
|
68
|
+
disableAnvilTestWatcher: true,
|
|
69
|
+
inboxLag: 1,
|
|
70
|
+
minTxsPerBlock: 0,
|
|
71
|
+
aztecSlotDuration: 12,
|
|
72
|
+
ethereumSlotDuration: 4,
|
|
73
|
+
walletMinFeePadding: PIPELINED_FEE_PADDING,
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
15
76
|
/** Returns worst-case predicted min fees with padding applied, mirroring the BaseWallet pattern. */
|
|
16
77
|
export async function getPaddedMaxFeesPerGas(node: AztecNode, padding = DEFAULT_MIN_FEE_PADDING): Promise<GasFees> {
|
|
17
78
|
const predicted = await node.getPredictedMinFees();
|
|
@@ -41,8 +41,8 @@ export class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract {
|
|
|
41
41
|
return {
|
|
42
42
|
async createAuthWit(messageHash: Fr): Promise<AuthWitness> {
|
|
43
43
|
const signer = new Schnorr();
|
|
44
|
-
const signature = await signer.constructSignature(messageHash
|
|
45
|
-
return new AuthWitness(messageHash,
|
|
44
|
+
const signature = await signer.constructSignature(messageHash, privateKey);
|
|
45
|
+
return new AuthWitness(messageHash, signature.toLimbFields());
|
|
46
46
|
},
|
|
47
47
|
};
|
|
48
48
|
}
|
package/src/fixtures/setup.ts
CHANGED
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
BatchCall,
|
|
8
8
|
type ContractFunctionInteraction,
|
|
9
9
|
type ContractMethod,
|
|
10
|
-
type DeployInteractionWaitOptions,
|
|
11
10
|
type DeployOptions,
|
|
11
|
+
type InteractionWaitOptions,
|
|
12
12
|
getContractClassFromArtifact,
|
|
13
13
|
waitForProven,
|
|
14
14
|
} from '@aztec/aztec.js/contracts';
|
|
@@ -48,8 +48,12 @@ import type { P2PClientDeps } from '@aztec/p2p';
|
|
|
48
48
|
import { MockGossipSubNetwork, getMockPubSubP2PServiceFactory } from '@aztec/p2p/test-helpers';
|
|
49
49
|
import { protocolContractsHash } from '@aztec/protocol-contracts';
|
|
50
50
|
import type { ProverNodeConfig } from '@aztec/prover-node';
|
|
51
|
-
import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server';
|
|
51
|
+
import { type PXEConfig, type PXECreationOptions, getPXEConfig } from '@aztec/pxe/server';
|
|
52
52
|
import type { SequencerClient } from '@aztec/sequencer-client';
|
|
53
|
+
import { AuthRegistryArtifact, getStandardAuthRegistry } from '@aztec/standard-contracts/auth-registry';
|
|
54
|
+
import { HandshakeRegistryArtifact, getStandardHandshakeRegistry } from '@aztec/standard-contracts/handshake-registry';
|
|
55
|
+
import { PublicChecksArtifact, getStandardPublicChecks } from '@aztec/standard-contracts/public-checks';
|
|
56
|
+
import { ARTIFACT_VERSION_BEFORE_INJECTION } from '@aztec/stdlib/abi';
|
|
53
57
|
import { type ContractInstanceWithAddress, getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
|
|
54
58
|
import type { AztecNodeAdmin, AztecNodeDebug } from '@aztec/stdlib/interfaces/client';
|
|
55
59
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
@@ -212,6 +216,11 @@ export type SetupOptions = {
|
|
|
212
216
|
/** Whether the initial node should be a lightweight RPC-only node (no sequencer, no validator).
|
|
213
217
|
* Use for tests that create their own validator nodes and don't need the initial sequencer. */
|
|
214
218
|
skipInitialSequencer?: boolean;
|
|
219
|
+
/** Whether to swap the production Sequencer for the minimal AutomineSequencer.
|
|
220
|
+
* Use only for single-sequencer non-block-building tests. See AUTOMINE_E2E_OPTS in `fixtures.ts`. */
|
|
221
|
+
useAutomineSequencer?: boolean;
|
|
222
|
+
/** Options forwarded to PXE creation (e.g. execution hooks). */
|
|
223
|
+
pxeCreationOptions?: PXECreationOptions;
|
|
215
224
|
} & Partial<AztecNodeConfig>;
|
|
216
225
|
|
|
217
226
|
/** Context for an end-to-end test as returned by the `setup` function */
|
|
@@ -270,6 +279,32 @@ export type EndToEndContext = {
|
|
|
270
279
|
teardown: () => Promise<void>;
|
|
271
280
|
};
|
|
272
281
|
|
|
282
|
+
/**
|
|
283
|
+
* When CONTRACT_ARTIFACTS_VERSION is set (backwards compatibility testing), asserts that the loaded artifact's
|
|
284
|
+
* aztecVersion matches the expected version. This is a sanity check verifying that the legacy artifact resolver
|
|
285
|
+
* actually swapped in the correct version.
|
|
286
|
+
*/
|
|
287
|
+
function assertContractArtifactsVersion() {
|
|
288
|
+
const expected = process.env.CONTRACT_ARTIFACTS_VERSION;
|
|
289
|
+
if (!expected) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const { aztecVersion } = SponsoredFPCContract.artifact;
|
|
293
|
+
// TODO(F-557): Remove this bypass once pre-version artifacts are no longer tested.
|
|
294
|
+
if (aztecVersion === ARTIFACT_VERSION_BEFORE_INJECTION) {
|
|
295
|
+
createLogger('e2e:setup').info(
|
|
296
|
+
`Skipping artifact version check: artifact predates version injection (CONTRACT_ARTIFACTS_VERSION=${expected})`,
|
|
297
|
+
);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
if (aztecVersion !== expected) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`Artifact version mismatch: expected ${expected} but got ${aztecVersion}. ` +
|
|
303
|
+
`The legacy artifact resolver may not have swapped in the correct version.`,
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
273
308
|
/**
|
|
274
309
|
* Sets up the environment for the end-to-end tests.
|
|
275
310
|
* @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated.
|
|
@@ -282,6 +317,7 @@ export async function setup(
|
|
|
282
317
|
pxeOpts: Partial<PXEConfig> = {},
|
|
283
318
|
chain: Chain = foundry,
|
|
284
319
|
): Promise<EndToEndContext> {
|
|
320
|
+
assertContractArtifactsVersion();
|
|
285
321
|
let anvil: Anvil | undefined;
|
|
286
322
|
try {
|
|
287
323
|
opts.aztecTargetCommitteeSize ??= 0;
|
|
@@ -424,9 +460,27 @@ export async function setup(
|
|
|
424
460
|
},
|
|
425
461
|
);
|
|
426
462
|
|
|
427
|
-
config
|
|
463
|
+
Object.assign(config, deployL1ContractsValues.l1ContractAddresses);
|
|
428
464
|
config.rollupVersion = deployL1ContractsValues.rollupVersion;
|
|
429
465
|
|
|
466
|
+
// Propagate L1-contracts-config overrides back to the node config so the archiver's
|
|
467
|
+
// `l1Constants` (and any other node-side consumer) agrees with what was actually deployed.
|
|
468
|
+
// Without this, a per-test override like `aztecEpochDuration: 4` lands on the rollup contract
|
|
469
|
+
// but the node config keeps the default (32), so `archiver.isEpochComplete(0)` computes
|
|
470
|
+
// `endSlot=31` and `EpochTestSettler`/`EpochMonitor` never fires — letting the
|
|
471
|
+
// `aztecProofSubmissionEpochs` window expire mid-test and prune the pending chain.
|
|
472
|
+
// Skip undefined values: callers (e.g. `P2PNetworkTest`) sometimes build `l1ContractsArgs`
|
|
473
|
+
// by spreading a partial `AztecNodeConfig`, which leaves unset fields (notably `dataDirectory`)
|
|
474
|
+
// as `undefined`. A blind Object.assign would then clobber the temp `dataDirectory` set earlier
|
|
475
|
+
// in this function and crash `setupSharedBlobStorage`.
|
|
476
|
+
if (opts.l1ContractsArgs) {
|
|
477
|
+
for (const [key, value] of Object.entries(opts.l1ContractsArgs)) {
|
|
478
|
+
if (value !== undefined) {
|
|
479
|
+
(config as unknown as Record<string, unknown>)[key] = value;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
430
484
|
if (enableAutomine) {
|
|
431
485
|
await ethCheatCodes.setAutomine(false);
|
|
432
486
|
await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration);
|
|
@@ -492,11 +546,17 @@ export async function setup(
|
|
|
492
546
|
throw new Error('minTxsPerBlock is undefined in e2e test setup');
|
|
493
547
|
}
|
|
494
548
|
|
|
495
|
-
//
|
|
549
|
+
// Whether we're deploying accounts (and therefore need reliable block inclusion past genesis)
|
|
496
550
|
const shouldDeployAccounts = numberOfAccounts > 0 && !opts.skipAccountDeployment;
|
|
497
551
|
// Only set minTxsPerBlock=0 if we need an empty block (no accounts at all, not skipped deployment)
|
|
498
552
|
const needsEmptyBlock = numberOfAccounts === 0 && !opts.skipAccountDeployment;
|
|
499
|
-
|
|
553
|
+
// Pipelining is always on: the proposer builds during slot N-1 for slot N. A tx submitted at
|
|
554
|
+
// slot N start arrives after that build, so forcing minTxsPerBlock=1 would stall the chain on
|
|
555
|
+
// alternating slots -- hence empty checkpoints are allowed (minTxsPerBlock=0) for account
|
|
556
|
+
// deployment. Automine is unaffected: its runBuild clamps mempool builds to
|
|
557
|
+
// Math.max(minTxsPerBlock ?? 1, 1) and still requires minValidTxs: 1.
|
|
558
|
+
const accountsDeployMinTxs = 0;
|
|
559
|
+
config.minTxsPerBlock = shouldDeployAccounts ? accountsDeployMinTxs : needsEmptyBlock ? 0 : originalMinTxsPerBlock;
|
|
500
560
|
|
|
501
561
|
config.p2pEnabled = opts.mockGossipSubNetwork || config.p2pEnabled;
|
|
502
562
|
config.p2pIp = opts.p2pIp ?? config.p2pIp ?? '127.0.0.1';
|
|
@@ -559,13 +619,21 @@ export async function setup(
|
|
|
559
619
|
pxeConfig.dataDirectory = path.join(directoryToCleanup, randomBytes(8).toString('hex'));
|
|
560
620
|
// For tests we only want proving enabled if specifically requested
|
|
561
621
|
pxeConfig.proverEnabled = !!pxeOpts.proverEnabled;
|
|
562
|
-
const wallet = await TestWallet.create(aztecNodeService, pxeConfig, {
|
|
622
|
+
const wallet = await TestWallet.create(aztecNodeService, pxeConfig, {
|
|
623
|
+
loggerActorLabel: 'pxe-0',
|
|
624
|
+
...opts.pxeCreationOptions,
|
|
625
|
+
});
|
|
563
626
|
|
|
564
627
|
if (opts.walletMinFeePadding !== undefined) {
|
|
565
628
|
wallet.setMinFeePadding(opts.walletMinFeePadding);
|
|
566
629
|
}
|
|
567
630
|
|
|
568
|
-
const cheatCodes = await CheatCodes.create(
|
|
631
|
+
const cheatCodes = await CheatCodes.create(
|
|
632
|
+
config.l1RpcUrls,
|
|
633
|
+
aztecNodeService,
|
|
634
|
+
dateProvider,
|
|
635
|
+
aztecNodeService.getAutomineSequencer(),
|
|
636
|
+
);
|
|
569
637
|
|
|
570
638
|
if (
|
|
571
639
|
(opts.aztecTargetCommitteeSize && opts.aztecTargetCommitteeSize > 0) ||
|
|
@@ -587,13 +655,18 @@ export async function setup(
|
|
|
587
655
|
logger.info('Sequencer not started on initial node, skipping block progression');
|
|
588
656
|
} else if (shouldDeployAccounts) {
|
|
589
657
|
logger.info(
|
|
590
|
-
`${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by
|
|
658
|
+
`${numberOfAccounts} accounts are being deployed. Reliably progressing past genesis by waiting for the accounts to be deployed`,
|
|
591
659
|
);
|
|
592
660
|
const accountsData = initialFundedAccounts.slice(0, numberOfAccounts);
|
|
593
661
|
const accountManagers = await deployFundedSchnorrAccounts(wallet, accountsData);
|
|
594
662
|
accounts = accountManagers.map(accountManager => accountManager.address);
|
|
595
663
|
} else if (needsEmptyBlock) {
|
|
596
664
|
logger.info('No accounts are being deployed, waiting for an empty block 1 to be mined');
|
|
665
|
+
// AutomineSequencer only builds on tx arrival; explicitly request an empty block.
|
|
666
|
+
const automine = aztecNodeService.getAutomineSequencer();
|
|
667
|
+
if (automine) {
|
|
668
|
+
await automine.buildEmptyBlock();
|
|
669
|
+
}
|
|
597
670
|
while ((await aztecNodeService.getBlockNumber()) === 0) {
|
|
598
671
|
await sleep(2000);
|
|
599
672
|
}
|
|
@@ -734,7 +807,7 @@ export async function waitForProvenChain(node: AztecNode, targetBlock?: BlockNum
|
|
|
734
807
|
targetBlock ??= await node.getBlockNumber();
|
|
735
808
|
|
|
736
809
|
await retryUntil(
|
|
737
|
-
async () => (await node.
|
|
810
|
+
async () => (await node.getBlockNumber('proven')) >= targetBlock,
|
|
738
811
|
'proven chain status',
|
|
739
812
|
timeoutSec,
|
|
740
813
|
intervalSec,
|
|
@@ -824,6 +897,57 @@ export async function expectMappingDelta<K, V extends number | bigint>(
|
|
|
824
897
|
expect(diffs).toEqual(expectedDiffs);
|
|
825
898
|
}
|
|
826
899
|
|
|
900
|
+
/**
|
|
901
|
+
* Registers the auth_registry contract class and publishes its standard instance if not already
|
|
902
|
+
* present, and registers the artifact with PXE. Publishing is required before exercising the public
|
|
903
|
+
* authwit path (which relies on the AVM's deployment-nullifier check); the PXE-side registration is
|
|
904
|
+
* required so revert messages from AuthRegistry calls can be enriched (otherwise assertion strings
|
|
905
|
+
* surface as generic "Assertion failed:" and tests that match on the real message fail).
|
|
906
|
+
*/
|
|
907
|
+
export async function ensureAuthRegistryPublished(wallet: Wallet, from: AztecAddress) {
|
|
908
|
+
const { instance, contractClass } = await getStandardAuthRegistry();
|
|
909
|
+
if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
|
|
910
|
+
await (await publishContractClass(wallet, AuthRegistryArtifact)).send({ from });
|
|
911
|
+
}
|
|
912
|
+
if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
|
|
913
|
+
await publishInstance(wallet, instance).send({ from });
|
|
914
|
+
}
|
|
915
|
+
await wallet.registerContract(instance, AuthRegistryArtifact);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Registers the public_checks contract class and publishes its standard instance if not already
|
|
920
|
+
* present, and registers the artifact with PXE. Required for any contract that calls
|
|
921
|
+
* `privately_check_timestamp` / `privately_check_block_number` (which dispatch into the
|
|
922
|
+
* deployed PublicChecks contract via an enqueued public call).
|
|
923
|
+
*/
|
|
924
|
+
export async function ensurePublicChecksPublished(wallet: Wallet, from: AztecAddress) {
|
|
925
|
+
const { instance, contractClass } = await getStandardPublicChecks();
|
|
926
|
+
if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
|
|
927
|
+
await (await publishContractClass(wallet, PublicChecksArtifact)).send({ from });
|
|
928
|
+
}
|
|
929
|
+
if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
|
|
930
|
+
await publishInstance(wallet, instance).send({ from });
|
|
931
|
+
}
|
|
932
|
+
await wallet.registerContract(instance, PublicChecksArtifact);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Registers the handshake_registry contract class and publishes its standard instance if not
|
|
937
|
+
* already present, and registers the artifact with PXE. Required for constrained-delivery flows
|
|
938
|
+
* that call into the HandshakeRegistry at its well-known address.
|
|
939
|
+
*/
|
|
940
|
+
export async function ensureHandshakeRegistryPublished(wallet: Wallet, from: AztecAddress) {
|
|
941
|
+
const { instance, contractClass } = await getStandardHandshakeRegistry();
|
|
942
|
+
if (!(await wallet.getContractClassMetadata(contractClass.id)).isContractClassPubliclyRegistered) {
|
|
943
|
+
await (await publishContractClass(wallet, HandshakeRegistryArtifact)).send({ from });
|
|
944
|
+
}
|
|
945
|
+
if (!(await wallet.getContractMetadata(instance.address)).isContractPublished) {
|
|
946
|
+
await publishInstance(wallet, instance).send({ from });
|
|
947
|
+
}
|
|
948
|
+
await wallet.registerContract(instance, HandshakeRegistryArtifact);
|
|
949
|
+
}
|
|
950
|
+
|
|
827
951
|
/**
|
|
828
952
|
* Registers the contract class used for test accounts and publicly deploys the instances requested.
|
|
829
953
|
* Use this when you need to make a public call to an account contract, such as for requesting a public authwit.
|
|
@@ -858,7 +982,7 @@ export async function ensureAccountContractsPublished(wallet: Wallet, accountsTo
|
|
|
858
982
|
* Returns deployed account data that can be used by tests.
|
|
859
983
|
*/
|
|
860
984
|
export const deployAccounts =
|
|
861
|
-
(numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<
|
|
985
|
+
(numberOfAccounts: number, logger: Logger, deployOptions?: Partial<DeployOptions<InteractionWaitOptions>>) =>
|
|
862
986
|
async ({ wallet, initialFundedAccounts }: { wallet: TestWallet; initialFundedAccounts: InitialAccountData[] }) => {
|
|
863
987
|
if (initialFundedAccounts.length < numberOfAccounts) {
|
|
864
988
|
throw new Error(`Cannot deploy more than ${initialFundedAccounts.length} initial accounts.`);
|
|
@@ -88,6 +88,10 @@ export type CreateNodeConfig = AztecNodeConfig & {
|
|
|
88
88
|
dontStartSequencer?: boolean;
|
|
89
89
|
/** Override the private key (instead of deriving from addressIndex). */
|
|
90
90
|
validatorPrivateKey?: `0x${string}`;
|
|
91
|
+
/** Corrupt only the block proposal at this indexWithinCheckpoint (testing only). */
|
|
92
|
+
invalidBlockProposalIndexWithinCheckpoint?: number;
|
|
93
|
+
/** Accept proposal gossip regardless of slot timing (testing only). */
|
|
94
|
+
skipProposalSlotValidation?: boolean;
|
|
91
95
|
};
|
|
92
96
|
|
|
93
97
|
/** Creates a P2P enabled instance of Aztec Node Service with a validator. */
|
package/src/fixtures/utils.ts
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Installs pinned legacy @aztec/* contract-artifact packages into .legacy-contracts/<version>/.
|
|
3
|
+
//
|
|
4
|
+
// Called from two places:
|
|
5
|
+
// - bootstrap.sh ci-compat-e2e: pre-populates the cache on the host before hermetic test
|
|
6
|
+
// containers launch. The containers run with --net=none (see ci3/docker_isolate), so on-demand
|
|
7
|
+
// installs from inside them fail with EAI_AGAIN.
|
|
8
|
+
// - legacy-jest-resolver.cjs: on-demand install for local dev, where jest runs with network.
|
|
9
|
+
//
|
|
10
|
+
// Idempotent: no-op when all packages are already present.
|
|
11
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
const { execFileSync } = require('child_process');
|
|
16
|
+
|
|
17
|
+
const REDIRECTED = ['@aztec/noir-contracts.js', '@aztec/noir-test-contracts.js', '@aztec/accounts'];
|
|
18
|
+
|
|
19
|
+
const e2eRoot = path.resolve(__dirname, '..');
|
|
20
|
+
|
|
21
|
+
function cacheRoot(version) {
|
|
22
|
+
return path.join(e2eRoot, '.legacy-contracts', version);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function pkgJsonPath(version, pkg) {
|
|
26
|
+
return path.join(cacheRoot(version), 'node_modules', pkg, 'package.json');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function installLegacyContracts(version) {
|
|
30
|
+
if (!version) {
|
|
31
|
+
throw new Error('installLegacyContracts: version is required');
|
|
32
|
+
}
|
|
33
|
+
if (REDIRECTED.every(pkg => fs.existsSync(pkgJsonPath(version, pkg)))) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const cacheDir = cacheRoot(version);
|
|
38
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
39
|
+
|
|
40
|
+
// Seed a standalone package.json so `npm install --prefix` treats cacheRoot as its own project. Without this, npm
|
|
41
|
+
// walks up and finds the yarn-project workspace root, which breaks on `workspace:` protocol deps and risks
|
|
42
|
+
// clobbering the monorepo's node_modules.
|
|
43
|
+
const seed = path.join(cacheDir, 'package.json');
|
|
44
|
+
if (!fs.existsSync(seed)) {
|
|
45
|
+
fs.writeFileSync(seed, JSON.stringify({ name: 'legacy-contracts-cache', private: true }));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const specs = REDIRECTED.map(pkg => `${pkg}@${version}`);
|
|
49
|
+
process.stderr.write(`[legacy-contracts] installing ${specs.join(' ')} into ${cacheDir}\n`);
|
|
50
|
+
// --prefix: install into cacheRoot instead of cwd, so the cache is isolated from the monorepo.
|
|
51
|
+
// --no-save: don't write the installed packages back to the seeded package.json.
|
|
52
|
+
// --ignore-scripts: skip lifecycle scripts (preinstall/postinstall) of the legacy packages and their transitive
|
|
53
|
+
// deps; we only want the files on disk, not to run any build steps.
|
|
54
|
+
// --legacy-peer-deps: tolerate peer-dependency mismatches between the pinned legacy @aztec/* graph and whatever
|
|
55
|
+
// current versions npm would otherwise try to reconcile.
|
|
56
|
+
execFileSync(
|
|
57
|
+
'npm',
|
|
58
|
+
['install', '--prefix', cacheDir, '--no-save', '--ignore-scripts', '--legacy-peer-deps', ...specs],
|
|
59
|
+
{ stdio: 'inherit' },
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
// Verify versions on disk match the requested version.
|
|
63
|
+
for (const pkg of REDIRECTED) {
|
|
64
|
+
const onDisk = JSON.parse(fs.readFileSync(pkgJsonPath(version, pkg), 'utf8')).version;
|
|
65
|
+
if (onDisk !== version) {
|
|
66
|
+
throw new Error(`[legacy-contracts] ${pkg} on disk is ${onDisk}, expected ${version}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = { installLegacyContracts, REDIRECTED, cacheRoot };
|
|
72
|
+
|
|
73
|
+
if (require.main === module) {
|
|
74
|
+
installLegacyContracts(process.argv[2]);
|
|
75
|
+
}
|