Skip to content
This repository was archived by the owner on Jan 9, 2026. It is now read-only.

Commit b9af03f

Browse files
authored
e2e: writing multiple tests (#83)
1 parent 71ba1c2 commit b9af03f

16 files changed

+7098
-52
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ solidity/artifacts
66
solidity/.env
77
solidity/.env.sepolia
88
solidity/.env.testnet
9+
10+
devnet/docker-compose.yaml

devnet/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.venv
2-
# config
2+
config
33
docker-compose.test.yml
44
docker-compose.yml
55
# docker-compose.yaml

devnet/compose.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import yaml
1515
from secp256k1 import PrivateKey
1616
from typing import TypedDict, Any
17+
import base64
1718

1819
DEFAULT_CHAINWEB_NODE_IMAGE = "ghcr.io/kadena-io/evm-devnet-chainweb-node:latest"
1920
DEFAULT_MINING_CLIENT_IMAGE = "ghcr.io/kadena-io/chainweb-mining-client:latest"
@@ -175,7 +176,8 @@ def payload_provider_config(
175176
mining_node: bool,
176177
node_name: str,
177178
evm_chains: list[int],
178-
pact_chains: list[int]
179+
pact_chains: list[int],
180+
minerAddress: str | None = evmMinerAddress
179181
) -> None:
180182
config = {
181183
"chainweb": {
@@ -188,7 +190,7 @@ def payload_provider_config(
188190
}
189191
|
190192
({
191-
"minerAddress": f"{evmMinerAddress}",
193+
"minerAddress": f"{minerAddress}",
192194
}
193195
if mining_node else {})
194196
for cid in evm_chains
@@ -207,7 +209,7 @@ def payload_provider_config(
207209
}
208210
| {
209211
"default": {
210-
"redeemAccount": "0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA",
212+
"redeemAccount": account_to_base64(minerAddress),
211213
"redeemChain": 0,
212214
},
213215
}
@@ -1043,9 +1045,10 @@ def chainweb_node(
10431045
has_frontend: bool = False,
10441046
exposed: bool = False,
10451047
evm_impl: str = "reth",
1048+
minerAddress: str | None = None,
10461049
) -> Spec:
10471050
jwtsecret_config(project_name, node_name)
1048-
payload_provider_config(project_name, mining_mode is not None, node_name, evm_cids, pact_cids)
1051+
payload_provider_config(project_name, mining_mode is not None, node_name, evm_cids, pact_cids, minerAddress)
10491052
cdir = config_dir(project_name, node_name)
10501053

10511054

@@ -1278,6 +1281,11 @@ def minimal_project(update_secrets: bool = False) -> Spec:
12781281
)
12791282

12801283

1284+
def account_to_base64(account:str) -> str:
1285+
account_bytes = account.encode('utf-8')
1286+
# Encode to Base64
1287+
return base64.b64encode(account_bytes).decode('utf-8')
1288+
12811289
# A project for testing and debugging chainweb-node itself. It runs several
12821290
# nodes in different configurations.
12831291
#
@@ -1320,6 +1328,7 @@ def kadena_dev_project(update_secrets: bool = False) -> Spec:
13201328
exposed=False,
13211329
has_frontend=False,
13221330
evm_impl=evm_impl,
1331+
minerAddress= "0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA"
13231332
),
13241333
chainweb_node(
13251334
"kadena-dev",
@@ -1331,6 +1340,7 @@ def kadena_dev_project(update_secrets: bool = False) -> Spec:
13311340
exposed=False,
13321341
has_frontend=False,
13331342
evm_impl=evm_impl,
1343+
minerAddress="0x38a6BD13CC381c68751BE2cef97BD79EBcb2Bb31"
13341344
),
13351345
chainweb_node(
13361346
"kadena-dev",

devnet/config/default/bootnode/payload-providers.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,5 @@ chainweb:
8989
miner: *id001
9090
type: pact
9191
default:
92-
redeemAccount: '0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA'
92+
redeemAccount: MHhkNDJkNzFjZGMyQTBhNzhmRTdmQkU3MjM2YzE5OTI1ZjYyQzQ0MmJB
9393
redeemChain: 0

network

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,19 +103,19 @@ function blockscout-help () {
103103

104104
function devnet-help () {
105105
echo -e "${YELLOW}Devnet commands:${R}"
106-
echo -e " ${B}devnet pull${R} pull container images for all devnet services"
107-
echo -e " ${B}devnet start|up${R} start the network with default components"
108-
echo -e " ${B}devnet stop|down${R} shutdown the network and reset all database"
109-
echo -e " ${B}devnet allocations${R} print information about pre-allocated wallets"
110-
echo -e " ${B}devnet state|status${R} print lastest consensus state for all chains in the network"
111-
echo -e " ${B}devnet summary${R} print summary of the consensus state for all nodes in the network"
112-
echo -e " ${B}devnet restart${R} restart the chainweb-node service"
113-
echo -e " ${B}devnet ports${R} show ports of available services"
114-
echo -e " ${B}devnet height-details${R} return detailed information for a given block height or 'latest' in JSON"
115-
echo -e " ${B}devnet services${R} show status of services in the network (docker compose ps)"
116-
echo -e " ${B}devnet chain-config${R} show chainweb chain configuration"
117-
echo -e " ${B}devnet curl${R} run a curl command from within the docker network"
118-
echo -e " ${B}devnet reth-db${R} run a reth CLI database debugging command (first argument is the chain, i.e. 0 or 1)"
106+
echo -e " ${B}devnet pull${R} pull container images for all devnet services"
107+
echo -e " ${B}devnet start|up${R} start the network with default components"
108+
echo -e " ${B}devnet stop|down${R} shutdown the network and reset all database"
109+
echo -e " ${B}devnet allocations${R} print information about pre-allocated wallets"
110+
echo -e " ${B}devnet state|status${R} --node print lastest consensus state for all chains in the network"
111+
echo -e " ${B}devnet summary${R} print summary of the consensus state for all nodes in the network"
112+
echo -e " ${B}devnet restart${R} restart the chainweb-node service"
113+
echo -e " ${B}devnet ports${R} show ports of available services"
114+
echo -e " ${B}devnet height-details${R} return detailed information for a given block height or 'latest' in JSON"
115+
echo -e " ${B}devnet services${R} show status of services in the network (docker compose ps)"
116+
echo -e " ${B}devnet chain-config${R} show chainweb chain configuration"
117+
echo -e " ${B}devnet curl${R} run a curl command from within the docker network"
118+
echo -e " ${B}devnet reth-db${R} run a reth CLI database debugging command (first argument is the chain, i.e. 0 or 1)"
119119
}
120120

121121
function usage() {
@@ -181,6 +181,7 @@ function show-ports () {
181181

182182
function devnet () {
183183
local CMD=$1
184+
local VAR1=$2
184185
case "$CMD" in
185186
help|h)
186187
shift
@@ -219,7 +220,7 @@ function devnet () {
219220
shift
220221
(
221222
cd "$NETWORK_DIR" &&
222-
bash state.sh
223+
bash state.sh $VAR1
223224
)
224225
;;
225226
summary)

tests/docker-compose.yaml

Whitespace-only changes.

tests/e2e/chainUtils.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { createPublicClient, defineChain, http } from 'viem';
2+
3+
export type EVMChainId = '20' | '21' | '22' | '23' | '24';
4+
export const EVMCHAINS: EVMChainId[] = ['20', '21', '22', '23', '24'] as const;
5+
const STARTBLOCKCHAINWEB = '5920';
6+
const STARTCHAIN_ID = '20';
7+
8+
const createBlockChainId = (chainId: EVMChainId): number => {
9+
return parseInt(STARTBLOCKCHAINWEB, 10) + parseInt(chainId, 10) - parseInt(STARTCHAIN_ID, 10);
10+
};
11+
12+
export const createServerUrl = (chainId: EVMChainId) => {
13+
return `http://localhost:1848/chainweb/0.0/evm-development/chain/${chainId}/evm/rpc`;
14+
};
15+
16+
export const getChainwebEVMChain = (chainId: EVMChainId) => {
17+
return defineChain({
18+
id: createBlockChainId(chainId),
19+
20+
name: 'Kadena Chainweb EVM',
21+
network: `kadena_${createBlockChainId(chainId)}`,
22+
nativeCurrency: {
23+
decimals: 18,
24+
name: 'KDA',
25+
symbol: 'KDA',
26+
},
27+
rpcUrls: {
28+
default: {
29+
http: [createServerUrl(chainId)],
30+
},
31+
public: {
32+
http: [createServerUrl(chainId)],
33+
},
34+
},
35+
});
36+
};
37+
38+
export const getPublicClient = (chainId: EVMChainId) => {
39+
return createPublicClient({
40+
chain: getChainwebEVMChain(chainId),
41+
transport: http(createServerUrl(chainId)),
42+
});
43+
};
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import { describe, test, expect, afterAll, beforeAll } from 'bun:test';
2+
import {
3+
CONFIG,
4+
docker,
5+
generateDockerComposeAndStartNetwork,
6+
getDevnetStatus,
7+
stopAndRemoveNetwork,
8+
waitForMinCutHeight,
9+
} from './devnet-utils';
10+
import type { ContainerLogsOptions } from 'dockerode';
11+
12+
describe('e2e: check container logs during for errors, warnings, crashes etc', () => {
13+
beforeAll(async () => {
14+
await stopAndRemoveNetwork('kadena-dev');
15+
await generateDockerComposeAndStartNetwork('kadena-dev');
16+
});
17+
afterAll(() => {
18+
if (CONFIG.CLEAN_AFTER) {
19+
// return stopAndRemoveNetwork('kadena-dev');
20+
}
21+
});
22+
23+
const containerArray = [
24+
'miner-1-mining-client',
25+
'miner-1-consensus',
26+
'miner-1-evm-init-20',
27+
'miner-1-evm-init-21',
28+
'miner-1-evm-init-22',
29+
'miner-1-evm-init-23',
30+
'miner-1-evm-init-24',
31+
'miner-1-evm-20',
32+
'miner-1-evm-21',
33+
'miner-1-evm-22',
34+
'miner-1-evm-23',
35+
'miner-1-evm-24',
36+
'miner-2-mining-client',
37+
'miner-2-consensus',
38+
'miner-2-evm-init-20',
39+
'miner-2-evm-init-21',
40+
'miner-2-evm-init-22',
41+
'miner-2-evm-init-23',
42+
'miner-2-evm-init-24',
43+
'miner-2-evm-20',
44+
'miner-2-evm-21',
45+
'miner-2-evm-22',
46+
'miner-2-evm-23',
47+
'miner-2-evm-24',
48+
'bootnode-allocations',
49+
'bootnode-consensus',
50+
'bootnode-evm-init-20',
51+
'bootnode-evm-init-21',
52+
'bootnode-evm-init-22',
53+
'bootnode-evm-init-23',
54+
'bootnode-evm-init-24',
55+
'bootnode-evm-20',
56+
'bootnode-evm-21',
57+
'bootnode-evm-22',
58+
'bootnode-evm-23',
59+
'bootnode-evm-24',
60+
'appdev-frontend',
61+
'appdev-evm-init-20',
62+
'appdev-evm-init-24',
63+
'appdev-evm-20',
64+
'appdev-evm-24',
65+
'appdev-consensus',
66+
];
67+
68+
const filterErrorLines =
69+
(cleanFunction?: (container: string, lines: string[]) => string[]) =>
70+
async (container: string): Promise<string[]> => {
71+
console.log('starting log check for', container);
72+
const c = await docker.getContainer(container.trim());
73+
74+
// Fetch logs
75+
const logBuffer = await c.logs({
76+
follow: false,
77+
stdout: true,
78+
stderr: true,
79+
timestamps: true,
80+
});
81+
82+
// Convert buffer to string and split into lines
83+
const logText = logBuffer.toString('utf8');
84+
const logLines = logText.split('\n');
85+
const affectedLines: string[] = [];
86+
87+
// Filter and display lines containing errors, warnings, or crashes
88+
logLines.forEach((line) => {
89+
if (/error|warning|crash|exception|failed/i.test(line)) {
90+
affectedLines.push(line);
91+
console.log(container, 'Issue detected:', line);
92+
}
93+
});
94+
95+
if (cleanFunction) {
96+
return cleanFunction(container, affectedLines);
97+
}
98+
99+
return affectedLines;
100+
};
101+
102+
// the appdev-consensus container and the bootnode-consensus container have a some expected warnings
103+
// because no miners were started in those containers. so we can ignore those lines
104+
const cleanLines = (container: string, lines: string[]): string[] => {
105+
return lines.filter(
106+
(line) =>
107+
!/EVM miner address is not set for ChainId/.test(line) &&
108+
container !== 'appdev-consensus' &&
109+
container !== 'bootnode-consensus'
110+
);
111+
};
112+
113+
test('should show no errors on startup', async () => {
114+
const promises = containerArray.map(filterErrorLines(cleanLines));
115+
const results = await Promise.all(promises);
116+
117+
results.forEach((logsArray) => {
118+
expect(logsArray.length).toBe(0);
119+
});
120+
});
121+
test('should show no errors during block production', async () => {
122+
const devnetStatus = await getDevnetStatus();
123+
await waitForMinCutHeight(devnetStatus.cutHeight + 98 * 1, { timeoutSeconds: 150 });
124+
125+
const promises = containerArray.map(filterErrorLines(cleanLines));
126+
const results = await Promise.all(promises);
127+
128+
results.forEach((logsArray) => {
129+
expect(logsArray.length).toBe(0);
130+
});
131+
});
132+
});

0 commit comments

Comments
 (0)