Skip to content
This repository was archived by the owner on Jan 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions tests/e2e/devnet-utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { $, fs, path } from 'zx';
import { waitSeconds } from './utils';
import Docker from 'dockerode';

const docker = new Docker({ socketPath: '/var/run/docker.sock' });

export const CONFIG = {
CLEAN_BEFORE: true,
CLEAN_AFTER: false,
CLEAN_AFTER: true,
VERBOSE: false,
};

Expand Down Expand Up @@ -46,14 +49,14 @@ export async function startNetwork() {
await $devnet`docker compose -f ${DOCKER_COMPOSE_FILE} up -d`;
}

interface DevnetChainStatus {
export interface DevnetChainStatus {
chainId: number;
height: number;
hash: string;
type: string;
}

interface DevnetStatus {
export interface DevnetStatus {
chains: DevnetChainStatus[];
cutHeight: number;
}
Expand Down Expand Up @@ -122,3 +125,29 @@ export async function waitForMinCutHeight(
return currentHeight >= cutHeight;
}, options);
}

export const stopContainer = async (containerIdOrName: string) => {
try {
// Get the container by ID or name
const container = docker.getContainer(containerIdOrName);

// Stop the container
await container.stop();
console.log(`Container ${containerIdOrName} stopped successfully.`);
} catch (error: any) {
console.error('Error stopping container:', error.message);
}
};

export const restartContainer = async (containerIdOrName: string) => {
try {
// Get the container by ID or name
const container = docker.getContainer(containerIdOrName);

// Stop the container
await container.restart();
console.log(`Container ${containerIdOrName} restarted successfully.`);
} catch (error: any) {
console.error('Error restarting container:', error.message);
}
};
54 changes: 54 additions & 0 deletions tests/e2e/fast-block-production.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { describe, test, expect, afterAll, beforeAll, it } from 'bun:test';
import {
$devnet,
CONFIG,
createDockerComposeFile,
generateDockerComposeAndStartNetwork,
getDevnetStatus,
stopAndRemoveNetwork,
waitFor,
waitForMinCutHeight,
} from './devnet-utils';
import { DOCKER_COMPOSE_FILE } from './devnet-utils';
import { createLogger } from './utils';
import { fs, $ } from 'zx';

$.verbose = CONFIG.VERBOSE;

const log = createLogger({ context: 'fast-block-production.test.ts' });

describe(`e2e: verify fast block production for reth`, () => {
beforeAll(() => {
// if (CONFIG.CLEAN_BEFORE) {
// return stopAndRemoveNetwork();
// }
});
afterAll(() => {
if (CONFIG.CLEAN_AFTER) {
return stopAndRemoveNetwork();
}
});

test(`e2e: produces 1 block a second or faster`, async () => {
await generateDockerComposeAndStartNetwork();

console.log('waiting for cut-height to reach 98*4...');
await waitForMinCutHeight(98 * 4, { timeoutSeconds: 150 });

const devnetStatus = await getDevnetStatus();
expect(devnetStatus.cutHeight).toBeGreaterThan(98 * 4);
const currentHeight = devnetStatus.cutHeight;
const currentTime = Date.now();

// wait for a single height = 98 blocks
await waitForMinCutHeight(currentHeight + 98 * 1, { timeoutSeconds: 100 });

const newDevnetStatus = await getDevnetStatus();
expect(newDevnetStatus.cutHeight).toBeGreaterThan(currentHeight + 98 * 1);
const newTime = Date.now();

const timePerBlock = (newTime - currentTime) / 98;
console.log(`produced 98 blocks in ${newTime - currentTime} ms`);
expect(timePerBlock).toBeLessThanOrEqual(1000);
});
});
33 changes: 33 additions & 0 deletions tests/e2e/run-multinode-with-miners.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { describe, test, expect, afterAll, beforeAll } from 'bun:test';
import {
CONFIG,
generateDockerComposeAndStartNetwork,
getDevnetStatus,
stopAndRemoveNetwork,
waitForMinCutHeight,
} from './devnet-utils';

describe(`e2e: multinode config with miners`, () => {
beforeAll(() => {});
afterAll(() => {
if (CONFIG.CLEAN_AFTER) {
return stopAndRemoveNetwork();
}
});

test('should see an update in blockheight on every chain', async () => {
await generateDockerComposeAndStartNetwork();
const devnetStatus = await getDevnetStatus();

const evmChains = devnetStatus.chains.filter((c) => c.type === 'evm');
expect(evmChains.length).toBeGreaterThan(1);
const currentHeight = devnetStatus.cutHeight;

// wait for a 2 height (just to be sure that all are upadted)
await waitForMinCutHeight(currentHeight + 98 * 2, { timeoutSeconds: 100 });
const newDevnetStatus = await getDevnetStatus();
const newEvmChains = newDevnetStatus.chains.filter((c) => c.type === 'evm');

expect(!!evmChains.find((chain, idx) => chain.height >= newEvmChains[idx]!.height)).toBe(false);
});
});
59 changes: 59 additions & 0 deletions tests/e2e/sync-nodes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, test, expect, afterAll, beforeAll } from 'bun:test';
import {
CONFIG,
generateDockerComposeAndStartNetwork,
getDevnetStatus,
restartContainer,
stopAndRemoveNetwork,
stopContainer,
waitForMinCutHeight,
type DevnetChainStatus,
type DevnetStatus,
} from './devnet-utils';

const getChainStatus = (chainId: number, status: DevnetStatus): DevnetChainStatus => {
return status.chains.find((c) => c.chainId === chainId)!;
};

describe.only(`e2e: sync nodes`, () => {
beforeAll(() => {
if (CONFIG.CLEAN_BEFORE) {
return stopAndRemoveNetwork();
}
});
afterAll(() => {
if (CONFIG.CLEAN_AFTER) {
return stopAndRemoveNetwork();
}
});

test('should have node2 catchup with node1 after it went down', async () => {
await generateDockerComposeAndStartNetwork();

const devnetStatus = await getDevnetStatus();
const currentHeight = devnetStatus.cutHeight;
const chain21 = getChainStatus(21, devnetStatus);
console.log(`evm-21 height: ${chain21.height}`);

await stopContainer('bootnode-evm-21');
console.log('stopped bootnode-evm-21');

// wait for a 2 height (just to be sure that all are upadted)
await waitForMinCutHeight(currentHeight + 98 * 2, { timeoutSeconds: 100 });
const newDevnetStatus = await getDevnetStatus();
const newChain21 = getChainStatus(21, newDevnetStatus);
const newCurrentHeight = newDevnetStatus.cutHeight;

expect(newChain21.height).toBe(chain21.height);

// wait for a 2 height (just to be sure that all are upadted)
await restartContainer('bootnode-evm-21');
console.log('restarted bootnode-evm-21');
await waitForMinCutHeight(newCurrentHeight + 98 * 3, { timeoutSeconds: 100 });
const newDevnetStatus2 = await getDevnetStatus();
const newChain21_2 = getChainStatus(21, newDevnetStatus2);

console.log(`evm-21 height: ${newChain21_2.height}`);
expect(newChain21_2.height).toBeGreaterThan(newChain21.height);
});
});
4 changes: 2 additions & 2 deletions tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"private": true,
"scripts": {
"test": "bun test ./src",
"e2e": "bun test ./e2e --timeout 300000",
"e2e": "bun test ./e2e/sync-nodes.test.ts --timeout 3000000",
"test-tx": "hardhat run ./scripts/send-basic-tx.mjs"
},
"devDependencies": {
Expand All @@ -21,4 +21,4 @@
"hardhat": "2.24.1",
"zx": "^8.5.4"
}
}
}
Loading