Skip to content

Commit a093ab7

Browse files
committed
test: update arb aggregator test to anvil
1 parent a7b1c85 commit a093ab7

File tree

6 files changed

+134
-39
lines changed

6 files changed

+134
-39
lines changed

src/createRollup.integration.test.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ import {
99
type PrivateKeyAccountWithPrivateKey,
1010
} from './testHelpers';
1111
import { createRollupFetchTransactionHash } from './createRollupFetchTransactionHash';
12-
import { getInitializedAnvilTestStackEnv } from './integrationTestHelpers/anvilHarness';
13-
import { isAnvilIntegrationTestMode } from './integrationTestHelpers/injectedMode';
12+
import { getAnvilTestStack, isAnvilTestMode } from './integrationTestHelpers/injectedMode';
1413

15-
const env = isAnvilIntegrationTestMode() ? getInitializedAnvilTestStackEnv() : undefined;
14+
const env = isAnvilTestMode() ? getAnvilTestStack() : undefined;
1615

1716
const parentChainPublicClient = createPublicClient({
1817
chain: env ? env.l2.chain : nitroTestnodeL2,

src/decorators/arbAggregatorActions.integration.test.ts

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,30 @@ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
55
import { nitroTestnodeL2 } from '../chains';
66
import { arbAggregatorActions } from './arbAggregatorActions';
77
import { getNitroTestnodePrivateKeyAccounts } from '../testHelpers';
8+
import { getAnvilTestStack, isAnvilTestMode } from '../integrationTestHelpers/injectedMode';
89

9-
const testnodeAccounts = getNitroTestnodePrivateKeyAccounts();
10-
const l2RollupOwner = testnodeAccounts.l2RollupOwner;
11-
const randomAccount = privateKeyToAccount(generatePrivateKey());
10+
const env = isAnvilTestMode() ? getAnvilTestStack() : undefined;
1211

13-
const nitroTestnodeL2Client = createPublicClient({
14-
chain: nitroTestnodeL2,
12+
const l2Client = createPublicClient({
13+
chain: env ? env.l2.chain : nitroTestnodeL2,
1514
transport: http(),
1615
}).extend(arbAggregatorActions);
1716

17+
const l2RollupOwner = env
18+
? env.l2.accounts.deployer
19+
: getNitroTestnodePrivateKeyAccounts().l2RollupOwner;
20+
const randomAccount = privateKeyToAccount(generatePrivateKey());
21+
1822
describe('ArgAggregator decorator tests', () => {
1923
it('successfully fetches the batch posters and the fee collectors', async () => {
20-
const batchPosters = await nitroTestnodeL2Client.arbAggregatorReadContract({
24+
const batchPosters = await l2Client.arbAggregatorReadContract({
2125
functionName: 'getBatchPosters',
2226
});
2327

2428
expect(batchPosters).toHaveLength(2);
2529
expect(batchPosters[0]).toEqual('0xA4b000000000000000000073657175656e636572');
2630

27-
const batchPosterFeeCollector = await nitroTestnodeL2Client.arbAggregatorReadContract({
31+
const batchPosterFeeCollector = await l2Client.arbAggregatorReadContract({
2832
functionName: 'getFeeCollector',
2933
args: [batchPosters[0]],
3034
});
@@ -34,25 +38,26 @@ describe('ArgAggregator decorator tests', () => {
3438

3539
it('succesfully updates the fee collector of a batch poster', async () => {
3640
// Get the batch posters
37-
const batchPosters = await nitroTestnodeL2Client.arbAggregatorReadContract({
41+
const batchPosters = await l2Client.arbAggregatorReadContract({
3842
functionName: 'getBatchPosters',
3943
});
4044

4145
// Set the fee collector of the batch poster to the random address
42-
const setFeeCollectorTransactionRequest =
43-
await nitroTestnodeL2Client.arbAggregatorPrepareTransactionRequest({
46+
const setFeeCollectorTransactionRequest = await l2Client.arbAggregatorPrepareTransactionRequest(
47+
{
4448
functionName: 'setFeeCollector',
4549
args: [batchPosters[1], randomAccount.address],
4650
upgradeExecutor: false,
4751
account: l2RollupOwner.address,
48-
});
49-
const txHash = await nitroTestnodeL2Client.sendRawTransaction({
52+
},
53+
);
54+
const txHash = await l2Client.sendRawTransaction({
5055
serializedTransaction: await l2RollupOwner.signTransaction(setFeeCollectorTransactionRequest),
5156
});
52-
await nitroTestnodeL2Client.waitForTransactionReceipt({ hash: txHash });
57+
await l2Client.waitForTransactionReceipt({ hash: txHash });
5358

5459
// Check the fee collector has changed
55-
const batchPosterFeeCollector = await nitroTestnodeL2Client.arbAggregatorReadContract({
60+
const batchPosterFeeCollector = await l2Client.arbAggregatorReadContract({
5661
functionName: 'getFeeCollector',
5762
args: [batchPosters[1]],
5863
});

src/integrationTestHelpers/anvilHarness.ts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
createPublicClient,
99
createWalletClient,
1010
defineChain,
11+
Hex,
1112
http,
1213
parseEther,
1314
parseGwei,
@@ -49,24 +50,40 @@ import {
4950
import { type RpcCachingProxy, startRpcCachingProxy } from './rpcCachingProxy';
5051
import type { CustomTimingParams, PrivateKeyAccountWithPrivateKey } from '../testHelpers';
5152

52-
export type AnvilTestStack = {
53+
type RegisteredParentChain = Parameters<typeof registerCustomParentChain>[0];
54+
55+
type BaseStack<L2Accounts, L3Accounts> = {
5356
l2: {
5457
rpcUrl: string;
5558
chain: Chain;
56-
accounts: {
57-
deployer: PrivateKeyAccountWithPrivateKey;
58-
};
59+
accounts: L2Accounts;
5960
timingParams: CustomTimingParams;
6061
rollupCreatorVersion: RollupCreatorSupportedVersion;
6162
};
6263
l3: {
63-
accounts: {
64-
tokenBridgeDeployer: PrivateKeyAccountWithPrivateKey;
65-
};
64+
accounts: L3Accounts;
6665
nativeToken: Address;
6766
};
6867
};
6968

69+
export type AnvilTestStack = BaseStack<
70+
{
71+
deployer: PrivateKeyAccountWithPrivateKey;
72+
},
73+
{
74+
tokenBridgeDeployer: PrivateKeyAccountWithPrivateKey;
75+
}
76+
>;
77+
78+
export type InjectedAnvilTestStack = BaseStack<
79+
{
80+
deployerPrivateKey: Hex;
81+
},
82+
{
83+
tokenBridgeDeployerPrivateKey: Hex;
84+
}
85+
>;
86+
7087
let envPromise: Promise<AnvilTestStack> | undefined;
7188
let initializedEnv: AnvilTestStack | undefined;
7289
let runtimeDir: string | undefined;
@@ -83,6 +100,46 @@ function prepareNitroRuntimeDir(runtimeDir: string) {
83100
chmodSync(join(runtimeDir, 'nitro-data'), 0o777);
84101
}
85102

103+
export function dehydrateAnvilTestStack(env: AnvilTestStack): InjectedAnvilTestStack {
104+
return {
105+
...env,
106+
l2: {
107+
...env.l2,
108+
accounts: {
109+
deployerPrivateKey: env.l2.accounts.deployer.privateKey,
110+
},
111+
},
112+
l3: {
113+
...env.l3,
114+
accounts: {
115+
tokenBridgeDeployerPrivateKey: env.l3.accounts.tokenBridgeDeployer.privateKey,
116+
},
117+
},
118+
};
119+
}
120+
121+
export function hydrateAnvilTestStack(env: InjectedAnvilTestStack): AnvilTestStack {
122+
const l2Chain = defineChain(env.l2.chain) as RegisteredParentChain;
123+
registerCustomParentChain(l2Chain);
124+
125+
return {
126+
...env,
127+
l2: {
128+
...env.l2,
129+
chain: l2Chain,
130+
accounts: {
131+
deployer: createAccount(env.l2.accounts.deployerPrivateKey),
132+
},
133+
},
134+
l3: {
135+
...env.l3,
136+
accounts: {
137+
tokenBridgeDeployer: createAccount(env.l3.accounts.tokenBridgeDeployerPrivateKey),
138+
},
139+
},
140+
};
141+
}
142+
86143
export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
87144
if (envPromise) {
88145
return envPromise;
@@ -222,11 +279,19 @@ export async function setupAnvilTestStack(): Promise<AnvilTestStack> {
222279
parentChainBeaconRpcUrl: sepoliaBeaconRpc,
223280
});
224281

225-
if (l2ChainConfig.arbitrum.DataAvailabilityCommittee) {
226-
delete l2NodeConfig.node?.['data-availability']?.['rpc-aggregator'];
282+
if (l2NodeConfig.node === undefined || l2NodeConfig.node['batch-poster'] === undefined) {
283+
throw new Error('L2 node config batch poster is undefined');
227284
}
228285

229-
l2NodeConfig.node!['batch-poster']!.enable = false;
286+
l2NodeConfig.node['batch-poster'].enable = true;
287+
l2NodeConfig.node['batch-poster']['max-delay'] = '1s';
288+
l2NodeConfig.node['batch-poster']['poll-interval'] = '1s';
289+
l2NodeConfig.node['batch-poster']['error-delay'] = '1s';
290+
l2NodeConfig.node['batch-poster']['l1-block-bound'] = 'ignore';
291+
l2NodeConfig.node['batch-poster']['data-poster'] = {
292+
'wait-for-l1-finality': false,
293+
};
294+
230295
l2NodeConfig.node!.staker!.enable = false;
231296
const nodeConfigPath = join(runtimeDir, 'l2-node-config.json');
232297
writeFileSync(nodeConfigPath, JSON.stringify(l2NodeConfig, null, 2), { mode: 0o644 });
Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
import { afterAll } from 'vitest';
1+
import {
2+
dehydrateAnvilTestStack,
3+
setupAnvilTestStack,
4+
teardownAnvilTestStack,
5+
} from './anvilHarness.ts';
26

3-
import { setupAnvilTestStack, teardownAnvilTestStack } from './anvilHarness.ts';
7+
export async function setup(project) {
8+
const env = await setupAnvilTestStack();
9+
project.provide('anvilTestStack', structuredClone(dehydrateAnvilTestStack(env)));
410

5-
await setupAnvilTestStack();
6-
7-
afterAll(() => {
8-
teardownAnvilTestStack();
9-
});
11+
return async () => {
12+
teardownAnvilTestStack();
13+
};
14+
}
Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
11
import { inject } from 'vitest';
22

3-
export const INTEGRATION_TEST_MODE = 'integrationTestMode' as const;
3+
import {
4+
type AnvilTestStack,
5+
type InjectedAnvilTestStack,
6+
hydrateAnvilTestStack,
7+
} from './anvilHarness';
8+
49
export type IntegrationTestMode = 'testnode' | 'anvil';
510

611
declare module 'vitest' {
712
export interface ProvidedContext {
813
integrationTestMode: IntegrationTestMode;
14+
anvilTestStack?: InjectedAnvilTestStack;
915
}
1016
}
1117

12-
export function isAnvilIntegrationTestMode(): boolean {
13-
const value = inject(INTEGRATION_TEST_MODE);
18+
export function isAnvilTestMode(): boolean {
19+
const value = inject('integrationTestMode');
1420

1521
if (value === 'anvil') {
1622
return true;
1723
}
1824

1925
return false;
2026
}
27+
28+
export function getAnvilTestStack(): AnvilTestStack {
29+
const value = inject('anvilTestStack');
30+
31+
if (value === undefined) {
32+
throw new Error('Injected Anvil test stack is unavailable.');
33+
}
34+
35+
return hydrateAnvilTestStack(value);
36+
}

vitest.integration.anvil.config.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@ export default mergeConfig(
99
integrationTestMode: 'anvil',
1010
},
1111
// The Anvil stack boots a forked L1 and dockerized Nitro L2 in-process.
12+
// Use worker threads so the provided Anvil env can cross the worker boundary with structured clone.
13+
pool: 'threads',
1214
testTimeout: 45 * 60 * 1000,
13-
setupFiles: ['./src/integrationTestHelpers/globalSetup.mjs'],
15+
globalSetup: ['./src/integrationTestHelpers/globalSetup.mjs'],
1416
exclude: [...configDefaults.exclude],
15-
include: ['./src/createRollup.integration.test.ts'],
17+
include: [
18+
'./src/createRollup.integration.test.ts',
19+
'./src/decorators/arbAggregatorActions.integration.test.ts',
20+
],
1621
fileParallelism: false,
1722
},
1823
}),

0 commit comments

Comments
 (0)