@aztec/end-to-end 0.0.1-commit.5914bae → 0.0.1-commit.59a0419c6
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/client_flows_benchmark.d.ts +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.d.ts.map +1 -1
- package/dest/bench/client_flows/client_flows_benchmark.js +13 -27
- package/dest/e2e_epochs/epochs_test.d.ts +16 -1
- package/dest/e2e_epochs/epochs_test.d.ts.map +1 -1
- package/dest/e2e_epochs/epochs_test.js +56 -8
- package/dest/e2e_fees/fees_test.d.ts +1 -1
- package/dest/e2e_fees/fees_test.d.ts.map +1 -1
- package/dest/e2e_fees/fees_test.js +2 -2
- 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 +2 -3
- package/dest/e2e_p2p/p2p_network.d.ts +11 -10
- package/dest/e2e_p2p/p2p_network.d.ts.map +1 -1
- package/dest/e2e_p2p/p2p_network.js +47 -28
- 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 +16 -3
- package/dest/e2e_p2p/shared.d.ts +5 -19
- package/dest/e2e_p2p/shared.d.ts.map +1 -1
- package/dest/e2e_p2p/shared.js +36 -70
- package/dest/fixtures/e2e_prover_test.d.ts +4 -3
- package/dest/fixtures/e2e_prover_test.d.ts.map +1 -1
- package/dest/fixtures/e2e_prover_test.js +7 -12
- package/dest/fixtures/elu_monitor.d.ts +21 -0
- package/dest/fixtures/elu_monitor.d.ts.map +1 -0
- package/dest/fixtures/elu_monitor.js +102 -0
- package/dest/fixtures/fixtures.d.ts +12 -1
- package/dest/fixtures/fixtures.d.ts.map +1 -1
- package/dest/fixtures/fixtures.js +10 -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 +39 -0
- package/dest/fixtures/setup.d.ts +17 -9
- package/dest/fixtures/setup.d.ts.map +1 -1
- package/dest/fixtures/setup.js +28 -12
- package/dest/fixtures/setup_p2p_test.d.ts +6 -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/shared/gas_portal_test_harness.js +1 -1
- package/dest/shared/jest_setup.js +41 -1
- package/dest/shared/submit-transactions.d.ts +1 -1
- package/dest/shared/submit-transactions.d.ts.map +1 -1
- 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 +0 -4
- 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 +58 -40
- package/dest/spartan/tx_metrics.d.ts +1 -1
- package/dest/spartan/tx_metrics.d.ts.map +1 -1
- package/dest/spartan/tx_metrics.js +16 -2
- package/dest/spartan/utils/config.d.ts +7 -1
- package/dest/spartan/utils/config.d.ts.map +1 -1
- package/dest/spartan/utils/config.js +3 -1
- package/dest/spartan/utils/index.d.ts +2 -1
- package/dest/spartan/utils/index.d.ts.map +1 -1
- package/dest/spartan/utils/index.js +2 -0
- package/dest/spartan/utils/nodes.d.ts +4 -5
- package/dest/spartan/utils/nodes.d.ts.map +1 -1
- package/dest/spartan/utils/nodes.js +9 -9
- package/dest/spartan/utils/pod_logs.d.ts +25 -0
- package/dest/spartan/utils/pod_logs.d.ts.map +1 -0
- package/dest/spartan/utils/pod_logs.js +74 -0
- package/dest/test-wallet/test_wallet.d.ts +1 -1
- package/dest/test-wallet/test_wallet.d.ts.map +1 -1
- package/dest/test-wallet/test_wallet.js +10 -4
- package/dest/test-wallet/worker_wallet_schema.d.ts +6 -1
- package/dest/test-wallet/worker_wallet_schema.d.ts.map +1 -1
- package/package.json +42 -44
- package/src/bench/client_flows/client_flows_benchmark.ts +31 -22
- package/src/e2e_epochs/epochs_test.ts +56 -7
- package/src/e2e_fees/fees_test.ts +4 -2
- package/src/e2e_p2p/inactivity_slash_test.ts +2 -3
- package/src/e2e_p2p/p2p_network.ts +58 -40
- package/src/e2e_p2p/reqresp/utils.ts +24 -3
- package/src/e2e_p2p/shared.ts +33 -103
- package/src/fixtures/dumps/epoch_proof_result.json +1 -1
- package/src/fixtures/e2e_prover_test.ts +12 -17
- package/src/fixtures/elu_monitor.ts +126 -0
- package/src/fixtures/fixtures.ts +22 -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 +43 -16
- package/src/fixtures/setup_p2p_test.ts +9 -9
- package/src/fixtures/token_utils.ts +1 -4
- package/src/guides/up_quick_start.sh +0 -2
- package/src/shared/gas_portal_test_harness.ts +0 -1
- package/src/shared/jest_setup.ts +51 -1
- package/src/shared/submit-transactions.ts +1 -4
- package/src/shared/uniswap_l1_l2.ts +0 -4
- package/src/simulators/token_simulator.ts +1 -1
- package/src/spartan/setup_test_wallets.ts +59 -36
- package/src/spartan/tx_metrics.ts +14 -2
- package/src/spartan/utils/config.ts +2 -0
- package/src/spartan/utils/index.ts +3 -0
- package/src/spartan/utils/nodes.ts +15 -10
- package/src/spartan/utils/pod_logs.ts +99 -0
- package/src/test-wallet/test_wallet.ts +9 -3
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import type { InitialAccountData } from '@aztec/accounts/testing';
|
|
1
2
|
import type { Archiver } from '@aztec/archiver';
|
|
2
3
|
import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
|
|
4
|
+
import { getAccountContractAddress } from '@aztec/aztec.js/account';
|
|
3
5
|
import { getTimestampRangeForEpoch } from '@aztec/aztec.js/block';
|
|
4
6
|
import { getContractInstanceFromInstantiationParams } from '@aztec/aztec.js/contracts';
|
|
5
7
|
import { Fr } from '@aztec/aztec.js/fields';
|
|
@@ -34,6 +36,10 @@ import { join } from 'path';
|
|
|
34
36
|
import type { Hex } from 'viem';
|
|
35
37
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
36
38
|
|
|
39
|
+
import {
|
|
40
|
+
SCHNORR_HARDCODED_PRIVATE_KEY,
|
|
41
|
+
SchnorrHardcodedKeyAccountContract,
|
|
42
|
+
} from '../fixtures/schnorr_hardcoded_account_contract.js';
|
|
37
43
|
import {
|
|
38
44
|
type EndToEndContext,
|
|
39
45
|
type SetupOptions,
|
|
@@ -41,6 +47,7 @@ import {
|
|
|
41
47
|
getPrivateKeyFromIndex,
|
|
42
48
|
setup,
|
|
43
49
|
} from '../fixtures/utils.js';
|
|
50
|
+
import type { TestWallet } from '../test-wallet/test_wallet.js';
|
|
44
51
|
|
|
45
52
|
export const WORLD_STATE_CHECKPOINT_HISTORY = 2;
|
|
46
53
|
export const WORLD_STATE_BLOCK_CHECK_INTERVAL = 50;
|
|
@@ -51,6 +58,8 @@ export type EpochsTestOpts = Partial<SetupOptions> & {
|
|
|
51
58
|
numberOfAccounts?: number;
|
|
52
59
|
pxeOpts?: Partial<PXEConfig>;
|
|
53
60
|
aztecSlotDurationInL1Slots?: number;
|
|
61
|
+
/** Skip creating/registering the hardcoded account during setup (for tests that handle accounts themselves). */
|
|
62
|
+
skipHardcodedAccount?: boolean;
|
|
54
63
|
};
|
|
55
64
|
|
|
56
65
|
export type TrackedSequencerEvent = {
|
|
@@ -121,10 +130,18 @@ export class EpochsTestContext {
|
|
|
121
130
|
this.L1_BLOCK_TIME_IN_S = ethereumSlotDuration;
|
|
122
131
|
this.L2_SLOT_DURATION_IN_S = aztecSlotDuration;
|
|
123
132
|
|
|
133
|
+
// When skipInitialSequencer is set, auto-create a hardcoded account funded via genesis.
|
|
134
|
+
// This avoids needing to deploy accounts on-chain (which would require a running sequencer).
|
|
135
|
+
const useHardcodedAccount = opts.skipInitialSequencer && !opts.skipHardcodedAccount;
|
|
136
|
+
let hardcodedAccountData: InitialAccountData | undefined;
|
|
137
|
+
if (useHardcodedAccount) {
|
|
138
|
+
hardcodedAccountData = await EpochsTestContext.getHardcodedAccountData(Fr.random(), Fr.random());
|
|
139
|
+
}
|
|
140
|
+
|
|
124
141
|
// Set up system without any account nor protocol contracts
|
|
125
142
|
// and with faster block times and shorter epochs.
|
|
126
143
|
const context = await setup(
|
|
127
|
-
opts.numberOfAccounts ?? 0,
|
|
144
|
+
useHardcodedAccount ? 0 : (opts.numberOfAccounts ?? 0),
|
|
128
145
|
{
|
|
129
146
|
automineL1Setup: true,
|
|
130
147
|
checkIntervalMs: 50,
|
|
@@ -139,15 +156,13 @@ export class EpochsTestContext {
|
|
|
139
156
|
realProofs: false,
|
|
140
157
|
startProverNode: true,
|
|
141
158
|
proverTestDelayMs: opts.proverTestDelayMs ?? 0,
|
|
142
|
-
// We use numeric incremental prover ids for simplicity, but we can switch to
|
|
143
|
-
// using the prover's eth address if the proverId is used for something in the rollup contract
|
|
144
|
-
// Use numeric EthAddress for deterministic prover id
|
|
145
159
|
proverId: EthAddress.fromNumber(1),
|
|
146
160
|
worldStateCheckpointHistory: WORLD_STATE_CHECKPOINT_HISTORY,
|
|
147
161
|
exitDelaySeconds: DefaultL1ContractsConfig.exitDelaySeconds,
|
|
148
|
-
|
|
162
|
+
slasherEnabled: false,
|
|
149
163
|
l1PublishingTime,
|
|
150
164
|
...opts,
|
|
165
|
+
...(hardcodedAccountData ? { initialFundedAccounts: [hardcodedAccountData], numberOfAccounts: 0 } : {}),
|
|
151
166
|
},
|
|
152
167
|
// Use checkpointed chain tip for PXE by default to avoid issues with blocks being dropped due to pruned anchor blocks.
|
|
153
168
|
// Can be overridden via opts.pxeOpts.
|
|
@@ -155,6 +170,11 @@ export class EpochsTestContext {
|
|
|
155
170
|
);
|
|
156
171
|
|
|
157
172
|
this.context = context;
|
|
173
|
+
|
|
174
|
+
// Register the hardcoded account in PXE (local only, no on-chain deployment needed).
|
|
175
|
+
if (hardcodedAccountData) {
|
|
176
|
+
await this.registerHardcodedAccount(hardcodedAccountData);
|
|
177
|
+
}
|
|
158
178
|
this.proverNodes = context.proverNode ? [context.proverNode] : [];
|
|
159
179
|
this.nodes = context.aztecNode ? [context.aztecNode as AztecNodeService] : [];
|
|
160
180
|
this.logger = context.logger;
|
|
@@ -197,6 +217,35 @@ export class EpochsTestContext {
|
|
|
197
217
|
await this.context.teardown();
|
|
198
218
|
}
|
|
199
219
|
|
|
220
|
+
/**
|
|
221
|
+
* Computes InitialAccountData for a SchnorrHardcodedKeyAccountContract.
|
|
222
|
+
* This contract has a hardcoded signing key and no initializer, so it can be used without
|
|
223
|
+
* on-chain deployment. Pass the returned data in `initialFundedAccounts` so the address
|
|
224
|
+
* gets funded with fee juice in genesis.
|
|
225
|
+
*/
|
|
226
|
+
public static async getHardcodedAccountData(secret: Fr, salt: Fr): Promise<InitialAccountData> {
|
|
227
|
+
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
228
|
+
const address = await getAccountContractAddress(contract, secret, salt);
|
|
229
|
+
const signingKey = SCHNORR_HARDCODED_PRIVATE_KEY;
|
|
230
|
+
return { secret, salt, signingKey, address };
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Registers a SchnorrHardcodedKeyAccountContract in PXE. The account must have been funded
|
|
235
|
+
* at genesis (via getHardcodedAccountData). No on-chain deployment or block mining needed.
|
|
236
|
+
*/
|
|
237
|
+
public async registerHardcodedAccount(accountData: InitialAccountData) {
|
|
238
|
+
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
239
|
+
const wallet = this.context.wallet;
|
|
240
|
+
const accountManager = await (wallet as TestWallet).createAccount({
|
|
241
|
+
secret: accountData.secret,
|
|
242
|
+
salt: accountData.salt,
|
|
243
|
+
contract,
|
|
244
|
+
});
|
|
245
|
+
this.context.accounts = [accountManager.address];
|
|
246
|
+
return accountManager.address;
|
|
247
|
+
}
|
|
248
|
+
|
|
200
249
|
public async createProverNode(opts: { dontStart?: boolean } & Partial<ProverNodeConfig> = {}) {
|
|
201
250
|
this.logger.warn('Creating and syncing a simulated prover node...');
|
|
202
251
|
const proverNodePrivateKey = this.getNextPrivateKey();
|
|
@@ -223,7 +272,7 @@ export class EpochsTestContext {
|
|
|
223
272
|
},
|
|
224
273
|
},
|
|
225
274
|
{
|
|
226
|
-
|
|
275
|
+
genesis: this.context.genesis,
|
|
227
276
|
dontStart: opts.dontStart,
|
|
228
277
|
},
|
|
229
278
|
),
|
|
@@ -278,7 +327,7 @@ export class EpochsTestContext {
|
|
|
278
327
|
slashingProtectionDb: opts.slashingProtectionDb,
|
|
279
328
|
},
|
|
280
329
|
{
|
|
281
|
-
|
|
330
|
+
genesis: this.context.genesis,
|
|
282
331
|
...opts,
|
|
283
332
|
},
|
|
284
333
|
),
|
|
@@ -23,7 +23,7 @@ import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
|
23
23
|
|
|
24
24
|
import { getContract } from 'viem';
|
|
25
25
|
|
|
26
|
-
import { MNEMONIC } from '../fixtures/fixtures.js';
|
|
26
|
+
import { MNEMONIC, getPaddedMaxFeesPerGas } from '../fixtures/fixtures.js';
|
|
27
27
|
import {
|
|
28
28
|
type EndToEndContext,
|
|
29
29
|
type SetupOptions,
|
|
@@ -193,7 +193,9 @@ export class FeesTest {
|
|
|
193
193
|
this.wallet = this.context.wallet;
|
|
194
194
|
this.aztecNode = this.context.aztecNodeService;
|
|
195
195
|
this.aztecNodeAdmin = this.context.aztecNodeService;
|
|
196
|
-
this.gasSettings = GasSettings.fallback({
|
|
196
|
+
this.gasSettings = GasSettings.fallback({
|
|
197
|
+
maxFeesPerGas: await getPaddedMaxFeesPerGas(this.aztecNode),
|
|
198
|
+
});
|
|
197
199
|
this.cheatCodes = this.context.cheatCodes;
|
|
198
200
|
this.accounts = deployedAccounts.map(a => a.address);
|
|
199
201
|
this.accounts.forEach((a, i) => this.logger.verbose(`Account ${i} address: ${a}`));
|
|
@@ -67,7 +67,6 @@ export class P2PInactivityTest {
|
|
|
67
67
|
listenAddress: '127.0.0.1',
|
|
68
68
|
minTxsPerBlock: 0,
|
|
69
69
|
aztecEpochDuration: EPOCH_DURATION,
|
|
70
|
-
validatorReexecute: false,
|
|
71
70
|
sentinelEnabled: true,
|
|
72
71
|
slashingQuorum: SLASHING_QUORUM,
|
|
73
72
|
slashingRoundSizeInEpochs: SLASHING_ROUND_SIZE_IN_EPOCHS,
|
|
@@ -109,7 +108,7 @@ export class P2PInactivityTest {
|
|
|
109
108
|
this.test.bootstrapNodeEnr,
|
|
110
109
|
NUM_NODES - this.inactiveNodeCount - Number(this.keepInitialNode),
|
|
111
110
|
BOOT_NODE_UDP_PORT,
|
|
112
|
-
this.test.
|
|
111
|
+
this.test.genesis,
|
|
113
112
|
this.dataDir,
|
|
114
113
|
undefined,
|
|
115
114
|
Number(this.keepInitialNode),
|
|
@@ -123,7 +122,7 @@ export class P2PInactivityTest {
|
|
|
123
122
|
this.test.bootstrapNodeEnr,
|
|
124
123
|
this.inactiveNodeCount,
|
|
125
124
|
BOOT_NODE_UDP_PORT,
|
|
126
|
-
this.test.
|
|
125
|
+
this.test.genesis,
|
|
127
126
|
this.dataDir,
|
|
128
127
|
undefined,
|
|
129
128
|
NUM_NODES - this.inactiveNodeCount,
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InitialAccountData, generateSchnorrAccounts } from '@aztec/accounts/testing';
|
|
2
2
|
import type { AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
|
|
3
|
+
import { getAccountContractAddress } from '@aztec/aztec.js/account';
|
|
3
4
|
import { AztecAddress, EthAddress } from '@aztec/aztec.js/addresses';
|
|
4
5
|
import { Fr } from '@aztec/aztec.js/fields';
|
|
5
6
|
import { getL1ContractsConfigEnvVars } from '@aztec/ethereum/config';
|
|
6
|
-
import {
|
|
7
|
-
type EmpireSlashingProposerContract,
|
|
8
|
-
GSEContract,
|
|
9
|
-
RollupContract,
|
|
10
|
-
type TallySlashingProposerContract,
|
|
11
|
-
} from '@aztec/ethereum/contracts';
|
|
7
|
+
import { GSEContract, RollupContract, type SlashingProposerContract } from '@aztec/ethereum/contracts';
|
|
12
8
|
import type { Operator } from '@aztec/ethereum/deploy-aztec-l1-contracts';
|
|
13
9
|
import { deployL1Contract } from '@aztec/ethereum/deploy-l1-contract';
|
|
14
10
|
import { MultiAdderArtifact } from '@aztec/ethereum/l1-artifacts';
|
|
@@ -24,9 +20,8 @@ import { SpamContract } from '@aztec/noir-test-contracts.js/Spam';
|
|
|
24
20
|
import type { BootstrapNode } from '@aztec/p2p/bootstrap';
|
|
25
21
|
import { createBootstrapNodeFromPrivateKey, getBootstrapNodeEnr } from '@aztec/p2p/test-helpers';
|
|
26
22
|
import { tryStop } from '@aztec/stdlib/interfaces/server';
|
|
27
|
-
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
28
23
|
import { TopicType } from '@aztec/stdlib/p2p';
|
|
29
|
-
import type {
|
|
24
|
+
import type { GenesisData } from '@aztec/stdlib/world-state';
|
|
30
25
|
import { ZkPassportProofParams } from '@aztec/stdlib/zkpassport';
|
|
31
26
|
import { getGenesisValues } from '@aztec/world-state/testing';
|
|
32
27
|
|
|
@@ -34,10 +29,13 @@ import getPort from 'get-port';
|
|
|
34
29
|
import { type GetContractReturnType, getAddress, getContract } from 'viem';
|
|
35
30
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
36
31
|
|
|
32
|
+
import {
|
|
33
|
+
SCHNORR_HARDCODED_PRIVATE_KEY,
|
|
34
|
+
SchnorrHardcodedKeyAccountContract,
|
|
35
|
+
} from '../fixtures/schnorr_hardcoded_account_contract.js';
|
|
37
36
|
import {
|
|
38
37
|
type EndToEndContext,
|
|
39
38
|
type SetupOptions,
|
|
40
|
-
deployAccounts,
|
|
41
39
|
getPrivateKeyFromIndex,
|
|
42
40
|
getSponsoredFPCAddress,
|
|
43
41
|
setup,
|
|
@@ -59,7 +57,7 @@ export const WAIT_FOR_TX_TIMEOUT = l1ContractsConfig.aztecSlotDuration * 3;
|
|
|
59
57
|
export const SHORTENED_BLOCK_TIME_CONFIG_NO_PRUNES = {
|
|
60
58
|
aztecSlotDuration: 12,
|
|
61
59
|
ethereumSlotDuration: 4,
|
|
62
|
-
|
|
60
|
+
aztecProofSubmissionEpochs: 640,
|
|
63
61
|
};
|
|
64
62
|
|
|
65
63
|
export class P2PNetworkTest {
|
|
@@ -76,8 +74,8 @@ export class P2PNetworkTest {
|
|
|
76
74
|
public peerIdPrivateKeys: string[] = [];
|
|
77
75
|
public validators: Operator[] = [];
|
|
78
76
|
|
|
79
|
-
public
|
|
80
|
-
public
|
|
77
|
+
public hardcodedAccountData!: InitialAccountData;
|
|
78
|
+
public genesis: GenesisData | undefined;
|
|
81
79
|
|
|
82
80
|
// The re-execution test needs a wallet and a spam contract
|
|
83
81
|
public wallet?: TestWallet;
|
|
@@ -124,12 +122,11 @@ export class P2PNetworkTest {
|
|
|
124
122
|
initialValidatorConfig.aztecProofSubmissionEpochs ?? l1ContractsConfig.aztecProofSubmissionEpochs,
|
|
125
123
|
slashingRoundSizeInEpochs:
|
|
126
124
|
initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
|
|
127
|
-
|
|
125
|
+
slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
|
|
128
126
|
aztecTargetCommitteeSize: numberOfValidators,
|
|
129
127
|
metricsPort: metricsPort,
|
|
130
128
|
numberOfInitialFundedAccounts: 2,
|
|
131
129
|
startProverNode,
|
|
132
|
-
walletMinFeePadding: 2.0,
|
|
133
130
|
};
|
|
134
131
|
|
|
135
132
|
this.deployL1ContractsArgs = {
|
|
@@ -137,7 +134,7 @@ export class P2PNetworkTest {
|
|
|
137
134
|
aztecEpochDuration: initialValidatorConfig.aztecEpochDuration ?? l1ContractsConfig.aztecEpochDuration,
|
|
138
135
|
slashingRoundSizeInEpochs:
|
|
139
136
|
initialValidatorConfig.slashingRoundSizeInEpochs ?? l1ContractsConfig.slashingRoundSizeInEpochs,
|
|
140
|
-
|
|
137
|
+
slasherEnabled: initialValidatorConfig.slasherEnabled ?? true,
|
|
141
138
|
|
|
142
139
|
ethereumSlotDuration: initialValidatorConfig.ethereumSlotDuration ?? l1ContractsConfig.ethereumSlotDuration,
|
|
143
140
|
aztecSlotDuration: initialValidatorConfig.aztecSlotDuration ?? l1ContractsConfig.aztecSlotDuration,
|
|
@@ -192,10 +189,10 @@ export class P2PNetworkTest {
|
|
|
192
189
|
}
|
|
193
190
|
|
|
194
191
|
get fundedAccount() {
|
|
195
|
-
if (!this.
|
|
196
|
-
throw new Error('Call
|
|
192
|
+
if (!this.hardcodedAccountData) {
|
|
193
|
+
throw new Error('Call setup to initialize the hardcoded account.');
|
|
197
194
|
}
|
|
198
|
-
return this.
|
|
195
|
+
return this.hardcodedAccountData;
|
|
199
196
|
}
|
|
200
197
|
|
|
201
198
|
async addBootstrapNode() {
|
|
@@ -303,17 +300,22 @@ export class P2PNetworkTest {
|
|
|
303
300
|
await this._sendDummyTx(this.context.deployL1ContractsValues.l1Client);
|
|
304
301
|
}
|
|
305
302
|
|
|
303
|
+
/** Points the wallet to a P2P-enabled node so transactions can propagate through the network. */
|
|
304
|
+
setupWalletOnNode(node: AztecNodeService) {
|
|
305
|
+
this.logger.info('Pointing wallet to a P2P-enabled node');
|
|
306
|
+
this.context.wallet.updateNode(node);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Registers the hardcoded account in PXE without on-chain deployment. No sequencer needed. */
|
|
306
310
|
async setupAccount() {
|
|
307
|
-
this.logger.info('
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
this.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
initialFundedAccounts: this.context.initialFundedAccounts,
|
|
311
|
+
this.logger.info('Registering hardcoded account (no deployment)');
|
|
312
|
+
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
313
|
+
const accountManager = await (this.context.wallet as TestWallet).createAccount({
|
|
314
|
+
secret: this.hardcodedAccountData.secret,
|
|
315
|
+
salt: this.hardcodedAccountData.salt,
|
|
316
|
+
contract,
|
|
314
317
|
});
|
|
315
|
-
this.
|
|
316
|
-
[{ address: this.defaultAccountAddress }] = deployedAccounts;
|
|
318
|
+
this.defaultAccountAddress = accountManager.address;
|
|
317
319
|
this.wallet = this.context.wallet;
|
|
318
320
|
}
|
|
319
321
|
|
|
@@ -354,13 +356,30 @@ export class P2PNetworkTest {
|
|
|
354
356
|
|
|
355
357
|
async setup() {
|
|
356
358
|
this.logger.info('Setting up subsystems from fresh');
|
|
359
|
+
|
|
360
|
+
// Pre-compute hardcoded account data so it gets funded in genesis.
|
|
361
|
+
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
362
|
+
const secret = Fr.random();
|
|
363
|
+
const salt = Fr.random();
|
|
364
|
+
this.hardcodedAccountData = {
|
|
365
|
+
secret,
|
|
366
|
+
salt,
|
|
367
|
+
signingKey: SCHNORR_HARDCODED_PRIVATE_KEY,
|
|
368
|
+
address: await getAccountContractAddress(contract, secret, salt),
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// Generate regular Schnorr accounts for tests that need deployable accounts (e.g. add_rollup).
|
|
372
|
+
const regularAccounts = await generateSchnorrAccounts(this.setupOptions.numberOfInitialFundedAccounts ?? 2);
|
|
373
|
+
|
|
357
374
|
this.context = await setup(
|
|
358
375
|
0,
|
|
359
376
|
{
|
|
360
377
|
...this.setupOptions,
|
|
361
378
|
fundSponsoredFPC: true,
|
|
362
379
|
skipAccountDeployment: true,
|
|
363
|
-
|
|
380
|
+
skipInitialSequencer: true,
|
|
381
|
+
initialFundedAccounts: [...regularAccounts, this.hardcodedAccountData],
|
|
382
|
+
slasherEnabled: this.setupOptions.slasherEnabled ?? this.deployL1ContractsArgs.slasherEnabled ?? false,
|
|
364
383
|
aztecTargetCommitteeSize: 0,
|
|
365
384
|
l1ContractsArgs: this.deployL1ContractsArgs,
|
|
366
385
|
},
|
|
@@ -372,8 +391,13 @@ export class P2PNetworkTest {
|
|
|
372
391
|
const sponsoredFPCAddress = await getSponsoredFPCAddress();
|
|
373
392
|
const initialFundedAccounts = [...this.context.initialFundedAccounts.map(a => a.address), sponsoredFPCAddress];
|
|
374
393
|
|
|
375
|
-
const {
|
|
376
|
-
|
|
394
|
+
const { genesis } = await getGenesisValues(
|
|
395
|
+
initialFundedAccounts,
|
|
396
|
+
undefined,
|
|
397
|
+
undefined,
|
|
398
|
+
this.context.genesis!.genesisTimestamp,
|
|
399
|
+
);
|
|
400
|
+
this.genesis = genesis;
|
|
377
401
|
|
|
378
402
|
const rollupContract = RollupContract.getFromL1ContractsValues(this.context.deployL1ContractsValues);
|
|
379
403
|
this.monitor = new ChainMonitor(rollupContract, this.context.dateProvider).start();
|
|
@@ -468,8 +492,7 @@ export class P2PNetworkTest {
|
|
|
468
492
|
async getContracts(): Promise<{
|
|
469
493
|
rollup: RollupContract;
|
|
470
494
|
slasherContract: GetContractReturnType<typeof SlasherAbi, ViemClient>;
|
|
471
|
-
slashingProposer:
|
|
472
|
-
slashFactory: SlashFactoryContract;
|
|
495
|
+
slashingProposer: SlashingProposerContract | undefined;
|
|
473
496
|
}> {
|
|
474
497
|
if (!this.ctx.deployL1ContractsValues) {
|
|
475
498
|
throw new Error('DeployAztecL1ContractsValues not set');
|
|
@@ -486,14 +509,9 @@ export class P2PNetworkTest {
|
|
|
486
509
|
client: this.ctx.deployL1ContractsValues.l1Client,
|
|
487
510
|
});
|
|
488
511
|
|
|
489
|
-
// Get the actual slashing proposer from rollup
|
|
512
|
+
// Get the actual slashing proposer from rollup
|
|
490
513
|
const slashingProposer = await rollup.getSlashingProposer();
|
|
491
514
|
|
|
492
|
-
|
|
493
|
-
this.ctx.deployL1ContractsValues.l1Client,
|
|
494
|
-
getAddress(this.ctx.deployL1ContractsValues.l1ContractAddresses.slashFactoryAddress!.toString()),
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
return { rollup, slasherContract, slashingProposer, slashFactory };
|
|
515
|
+
return { rollup, slasherContract, slashingProposer };
|
|
498
516
|
}
|
|
499
517
|
}
|
|
@@ -91,7 +91,7 @@ export async function runReqrespTxTest(params: {
|
|
|
91
91
|
t.bootstrapNodeEnr,
|
|
92
92
|
NUM_VALIDATORS,
|
|
93
93
|
BOOT_NODE_UDP_PORT,
|
|
94
|
-
t.
|
|
94
|
+
t.genesis,
|
|
95
95
|
dataDir,
|
|
96
96
|
shouldCollectMetrics(),
|
|
97
97
|
);
|
|
@@ -149,6 +149,13 @@ export async function runReqrespTxTest(params: {
|
|
|
149
149
|
const submittedTxs = await Promise.all(
|
|
150
150
|
txBatches.map(async (batch, batchIndex) => {
|
|
151
151
|
const proposerNode = nodes[proposerIndexes[batchIndex]];
|
|
152
|
+
for (const tx of batch) {
|
|
153
|
+
t.logger.info(`Tx ${tx.getTxHash().toString()} base64: ${tx.toBuffer().toString('base64')}`);
|
|
154
|
+
}
|
|
155
|
+
const txHashes = batch.map(tx => tx.getTxHash().toString());
|
|
156
|
+
t.logger.info(
|
|
157
|
+
`Sending batch ${batchIndex} to proposer ${getNodePort(proposerIndexes[batchIndex])}: ${txHashes.join(', ')}`,
|
|
158
|
+
);
|
|
152
159
|
await Promise.all(
|
|
153
160
|
batch.map(async tx => {
|
|
154
161
|
try {
|
|
@@ -163,6 +170,12 @@ export async function runReqrespTxTest(params: {
|
|
|
163
170
|
}),
|
|
164
171
|
);
|
|
165
172
|
|
|
173
|
+
// Log pool state per node after sending
|
|
174
|
+
for (let i = 0; i < NUM_VALIDATORS; i++) {
|
|
175
|
+
const count = await nodes[i].getPendingTxCount();
|
|
176
|
+
t.logger.info(`Node ${getNodePort(i)} pool has ${count} pending txs`);
|
|
177
|
+
}
|
|
178
|
+
|
|
166
179
|
t.logger.info('Waiting for all transactions to be mined');
|
|
167
180
|
await Promise.all(
|
|
168
181
|
submittedTxs.flatMap((batch, batchIndex) =>
|
|
@@ -178,8 +191,16 @@ export async function runReqrespTxTest(params: {
|
|
|
178
191
|
|
|
179
192
|
// Assert that multiple blocks were built for at least one slot
|
|
180
193
|
t.logger.info('Verifying multiple blocks for at least one checkpoint');
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
// Wait for L1 checkpoint sync, which may lag behind P2P block propagation.
|
|
195
|
+
const checkpoints = await retryUntil(
|
|
196
|
+
async () => {
|
|
197
|
+
const cps = await nodes[0].getCheckpoints(CheckpointNumber(1), 50);
|
|
198
|
+
return cps.length > 0 && cps.some(cp => cp.checkpoint.blocks.length >= 2) ? cps : undefined;
|
|
199
|
+
},
|
|
200
|
+
'waiting for multi-block checkpoint to sync from L1',
|
|
201
|
+
30,
|
|
202
|
+
1,
|
|
203
|
+
);
|
|
183
204
|
|
|
184
205
|
let mbpsFound = false;
|
|
185
206
|
let expectedBlockNumber = checkpoints[0].checkpoint.blocks[0].number;
|
package/src/e2e_p2p/shared.ts
CHANGED
|
@@ -7,11 +7,7 @@ import type { Logger } from '@aztec/aztec.js/log';
|
|
|
7
7
|
import { TxHash } from '@aztec/aztec.js/tx';
|
|
8
8
|
import type { RollupCheatCodes } from '@aztec/aztec/testing';
|
|
9
9
|
import type { EpochCacheInterface } from '@aztec/epoch-cache';
|
|
10
|
-
import type {
|
|
11
|
-
EmpireSlashingProposerContract,
|
|
12
|
-
RollupContract,
|
|
13
|
-
TallySlashingProposerContract,
|
|
14
|
-
} from '@aztec/ethereum/contracts';
|
|
10
|
+
import type { RollupContract, SlashingProposerContract } from '@aztec/ethereum/contracts';
|
|
15
11
|
import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
16
12
|
import { timesAsync, unique } from '@aztec/foundation/collection';
|
|
17
13
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
@@ -22,8 +18,8 @@ import { TestContract, TestContractArtifact } from '@aztec/noir-test-contracts.j
|
|
|
22
18
|
import { getPXEConfig, getPXEConfig as getRpcConfig } from '@aztec/pxe/server';
|
|
23
19
|
import { getRoundForOffense } from '@aztec/slasher';
|
|
24
20
|
import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client';
|
|
25
|
-
import type { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
26
21
|
|
|
22
|
+
import { SchnorrHardcodedKeyAccountContract } from '../fixtures/schnorr_hardcoded_account_contract.js';
|
|
27
23
|
import { submitTxsTo } from '../shared/submit-transactions.js';
|
|
28
24
|
import { TestWallet } from '../test-wallet/test_wallet.js';
|
|
29
25
|
import { type ProvenTx, proveInteraction } from '../test-wallet/utils.js';
|
|
@@ -60,10 +56,17 @@ export const submitTransactions = async (
|
|
|
60
56
|
rpcConfig.proverEnabled = false;
|
|
61
57
|
const wallet = await TestWallet.create(
|
|
62
58
|
node,
|
|
63
|
-
|
|
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' },
|
|
64
62
|
{ loggerActorLabel: 'pxe-tx' },
|
|
65
63
|
);
|
|
66
|
-
const
|
|
64
|
+
const contract = new SchnorrHardcodedKeyAccountContract();
|
|
65
|
+
const fundedAccountManager = await wallet.createAccount({
|
|
66
|
+
secret: fundedAccount.secret,
|
|
67
|
+
salt: fundedAccount.salt,
|
|
68
|
+
contract,
|
|
69
|
+
});
|
|
67
70
|
return submitTxsTo(wallet, fundedAccountManager.address, numTxs, logger);
|
|
68
71
|
};
|
|
69
72
|
|
|
@@ -78,10 +81,15 @@ export async function prepareTransactions(
|
|
|
78
81
|
|
|
79
82
|
const wallet = await TestWallet.create(
|
|
80
83
|
node,
|
|
81
|
-
{ ...getPXEConfig(), proverEnabled: false },
|
|
84
|
+
{ ...getPXEConfig(), proverEnabled: false, syncChainTip: 'checkpointed' },
|
|
82
85
|
{ loggerActorLabel: 'pxe-tx' },
|
|
83
86
|
);
|
|
84
|
-
const
|
|
87
|
+
const accountContract = new SchnorrHardcodedKeyAccountContract();
|
|
88
|
+
const fundedAccountManager = await wallet.createAccount({
|
|
89
|
+
secret: fundedAccount.secret,
|
|
90
|
+
salt: fundedAccount.salt,
|
|
91
|
+
contract: accountContract,
|
|
92
|
+
});
|
|
85
93
|
|
|
86
94
|
const testContractInstance = await getContractInstanceFromInstantiationParams(TestContractArtifact, {
|
|
87
95
|
salt: Fr.random(),
|
|
@@ -99,7 +107,7 @@ export async function prepareTransactions(
|
|
|
99
107
|
}
|
|
100
108
|
|
|
101
109
|
export function awaitProposalExecution(
|
|
102
|
-
slashingProposer:
|
|
110
|
+
slashingProposer: SlashingProposerContract,
|
|
103
111
|
timeoutSeconds: number,
|
|
104
112
|
logger: Logger,
|
|
105
113
|
): Promise<bigint> {
|
|
@@ -109,24 +117,12 @@ export function awaitProposalExecution(
|
|
|
109
117
|
reject(new Error(`Timeout waiting for proposal execution after ${timeoutSeconds}s`));
|
|
110
118
|
}, timeoutSeconds * 1000);
|
|
111
119
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
logger.warn(`Proposal ${args.payload} from round ${args.round} executed`);
|
|
115
|
-
clearTimeout(timeout);
|
|
116
|
-
unwatch();
|
|
117
|
-
resolve(args.round);
|
|
118
|
-
});
|
|
119
|
-
} else if (slashingProposer.type === 'tally') {
|
|
120
|
-
const unwatch = slashingProposer.listenToRoundExecuted(args => {
|
|
121
|
-
logger.warn(`Slash from round ${args.round} executed`);
|
|
122
|
-
clearTimeout(timeout);
|
|
123
|
-
unwatch();
|
|
124
|
-
resolve(args.round);
|
|
125
|
-
});
|
|
126
|
-
} else {
|
|
120
|
+
const unwatch = slashingProposer.listenToRoundExecuted(args => {
|
|
121
|
+
logger.warn(`Slash from round ${args.round} executed`);
|
|
127
122
|
clearTimeout(timeout);
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
unwatch();
|
|
124
|
+
resolve(args.round);
|
|
125
|
+
});
|
|
130
126
|
});
|
|
131
127
|
}
|
|
132
128
|
|
|
@@ -203,48 +199,6 @@ export async function advanceToEpochBeforeProposer({
|
|
|
203
199
|
throw new Error(`Target proposer ${targetProposer} not found in any slot after ${maxAttempts} epoch attempts`);
|
|
204
200
|
}
|
|
205
201
|
|
|
206
|
-
/**
|
|
207
|
-
* Advance epochs until we find one where the target proposer is selected for at least one slot.
|
|
208
|
-
* With N validators and M slots per epoch, a specific proposer may not be selected in any given epoch.
|
|
209
|
-
* For example, with 4 validators and 2 slots/epoch, there is about a 44% chance per epoch.
|
|
210
|
-
*/
|
|
211
|
-
export async function awaitEpochWithProposer({
|
|
212
|
-
epochCache,
|
|
213
|
-
cheatCodes,
|
|
214
|
-
targetProposer,
|
|
215
|
-
logger,
|
|
216
|
-
maxAttempts = 20,
|
|
217
|
-
}: {
|
|
218
|
-
epochCache: EpochCacheInterface;
|
|
219
|
-
cheatCodes: RollupCheatCodes;
|
|
220
|
-
targetProposer: EthAddress;
|
|
221
|
-
logger: Logger;
|
|
222
|
-
maxAttempts?: number;
|
|
223
|
-
}): Promise<void> {
|
|
224
|
-
const { epochDuration } = await cheatCodes.getConfig();
|
|
225
|
-
|
|
226
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
227
|
-
const currentEpoch = await cheatCodes.getEpoch();
|
|
228
|
-
const startSlot = Number(currentEpoch) * Number(epochDuration);
|
|
229
|
-
const endSlot = startSlot + Number(epochDuration);
|
|
230
|
-
|
|
231
|
-
logger.info(`Checking epoch ${currentEpoch} (slots ${startSlot}-${endSlot - 1}) for proposer ${targetProposer}`);
|
|
232
|
-
|
|
233
|
-
for (let s = startSlot; s < endSlot; s++) {
|
|
234
|
-
const proposer = await epochCache.getProposerAttesterAddressInSlot(SlotNumber(s));
|
|
235
|
-
if (proposer && proposer.equals(targetProposer)) {
|
|
236
|
-
logger.warn(`Found target proposer ${targetProposer} in slot ${s} of epoch ${currentEpoch}`);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
logger.info(`Target proposer not found in epoch ${currentEpoch}, advancing to next epoch`);
|
|
242
|
-
await cheatCodes.advanceToNextEpoch();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
throw new Error(`Target proposer ${targetProposer} not found in any slot after ${maxAttempts} epoch attempts`);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
202
|
export async function awaitOffenseDetected({
|
|
249
203
|
logger,
|
|
250
204
|
nodeAdmin,
|
|
@@ -287,7 +241,6 @@ export async function awaitCommitteeKicked({
|
|
|
287
241
|
rollup,
|
|
288
242
|
cheatCodes,
|
|
289
243
|
committee,
|
|
290
|
-
slashFactory,
|
|
291
244
|
slashingProposer,
|
|
292
245
|
slashingRoundSize,
|
|
293
246
|
aztecSlotDuration,
|
|
@@ -298,8 +251,7 @@ export async function awaitCommitteeKicked({
|
|
|
298
251
|
rollup: RollupContract;
|
|
299
252
|
cheatCodes: RollupCheatCodes;
|
|
300
253
|
committee: readonly `0x${string}`[];
|
|
301
|
-
|
|
302
|
-
slashingProposer: EmpireSlashingProposerContract | TallySlashingProposerContract | undefined;
|
|
254
|
+
slashingProposer: SlashingProposerContract | undefined;
|
|
303
255
|
slashingRoundSize: number;
|
|
304
256
|
aztecSlotDuration: number;
|
|
305
257
|
aztecEpochDuration: number;
|
|
@@ -312,36 +264,14 @@ export async function awaitCommitteeKicked({
|
|
|
312
264
|
|
|
313
265
|
await cheatCodes.debugRollup();
|
|
314
266
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
const events = await slashFactory.getSlashPayloadCreatedEvents();
|
|
324
|
-
return events.length > 0 ? events : undefined;
|
|
325
|
-
},
|
|
326
|
-
'slash payload created',
|
|
327
|
-
120,
|
|
328
|
-
1,
|
|
329
|
-
);
|
|
330
|
-
expect(slashPayloadEvents.length).toBe(1);
|
|
331
|
-
// The uniqueness check is needed since a validator may be slashed more than once on the same round (eg because they let two epochs be pruned)
|
|
332
|
-
expect(unique(slashPayloadEvents[0].slashes.map(slash => slash.validator.toString()))).toHaveLength(
|
|
333
|
-
committee.length,
|
|
334
|
-
);
|
|
335
|
-
} else {
|
|
336
|
-
// Use the slash offset to ensure we are in the right epoch for tally
|
|
337
|
-
const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
|
|
338
|
-
const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
|
|
339
|
-
const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
|
|
340
|
-
const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
|
|
341
|
-
const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
|
|
342
|
-
logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
|
|
343
|
-
await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
|
|
344
|
-
}
|
|
267
|
+
// Use the slash offset to ensure we are in the right epoch for tally
|
|
268
|
+
const slashOffsetInRounds = await slashingProposer.getSlashOffsetInRounds();
|
|
269
|
+
const slashingRoundSizeInEpochs = slashingRoundSize / aztecEpochDuration;
|
|
270
|
+
const slashingOffsetInEpochs = Number(slashOffsetInRounds) * slashingRoundSizeInEpochs;
|
|
271
|
+
const firstEpochInOffenseRound = offenseEpoch - (offenseEpoch % slashingRoundSizeInEpochs);
|
|
272
|
+
const targetEpoch = firstEpochInOffenseRound + slashingOffsetInEpochs;
|
|
273
|
+
logger.info(`Advancing to epoch ${targetEpoch} so we start slashing`);
|
|
274
|
+
await cheatCodes.advanceToEpoch(EpochNumber(targetEpoch), { offset: -aztecSlotDuration / 2 });
|
|
345
275
|
|
|
346
276
|
const attestersPre = await rollup.getAttesters();
|
|
347
277
|
expect(attestersPre.length).toBe(committee.length);
|