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 all 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ solidity/artifacts
solidity/.env
solidity/.env.sepolia
solidity/.env.testnet

devnet/docker-compose.yaml
2 changes: 1 addition & 1 deletion devnet/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.venv
# config
config
docker-compose.test.yml
docker-compose.yml
# docker-compose.yaml
Expand Down
18 changes: 14 additions & 4 deletions devnet/compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import yaml
from secp256k1 import PrivateKey
from typing import TypedDict, Any
import base64

DEFAULT_CHAINWEB_NODE_IMAGE = "ghcr.io/kadena-io/evm-devnet-chainweb-node:latest"
DEFAULT_MINING_CLIENT_IMAGE = "ghcr.io/kadena-io/chainweb-mining-client:latest"
Expand Down Expand Up @@ -175,7 +176,8 @@ def payload_provider_config(
mining_node: bool,
node_name: str,
evm_chains: list[int],
pact_chains: list[int]
pact_chains: list[int],
minerAddress: str | None = evmMinerAddress
) -> None:
config = {
"chainweb": {
Expand All @@ -188,7 +190,7 @@ def payload_provider_config(
}
|
({
"minerAddress": f"{evmMinerAddress}",
"minerAddress": f"{minerAddress}",
}
if mining_node else {})
for cid in evm_chains
Expand All @@ -207,7 +209,7 @@ def payload_provider_config(
}
| {
"default": {
"redeemAccount": "0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA",
"redeemAccount": account_to_base64(minerAddress),
"redeemChain": 0,
},
}
Expand Down Expand Up @@ -1043,9 +1045,10 @@ def chainweb_node(
has_frontend: bool = False,
exposed: bool = False,
evm_impl: str = "reth",
minerAddress: str | None = None,
) -> Spec:
jwtsecret_config(project_name, node_name)
payload_provider_config(project_name, mining_mode is not None, node_name, evm_cids, pact_cids)
payload_provider_config(project_name, mining_mode is not None, node_name, evm_cids, pact_cids, minerAddress)
cdir = config_dir(project_name, node_name)


Expand Down Expand Up @@ -1278,6 +1281,11 @@ def minimal_project(update_secrets: bool = False) -> Spec:
)


def account_to_base64(account:str) -> str:
account_bytes = account.encode('utf-8')
# Encode to Base64
return base64.b64encode(account_bytes).decode('utf-8')

# A project for testing and debugging chainweb-node itself. It runs several
# nodes in different configurations.
#
Expand Down Expand Up @@ -1320,6 +1328,7 @@ def kadena_dev_project(update_secrets: bool = False) -> Spec:
exposed=False,
has_frontend=False,
evm_impl=evm_impl,
minerAddress= "0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA"
),
chainweb_node(
"kadena-dev",
Expand All @@ -1331,6 +1340,7 @@ def kadena_dev_project(update_secrets: bool = False) -> Spec:
exposed=False,
has_frontend=False,
evm_impl=evm_impl,
minerAddress="0x38a6BD13CC381c68751BE2cef97BD79EBcb2Bb31"
),
chainweb_node(
"kadena-dev",
Expand Down
2 changes: 1 addition & 1 deletion devnet/config/default/bootnode/payload-providers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,5 @@ chainweb:
miner: *id001
type: pact
default:
redeemAccount: '0xd42d71cdc2A0a78fE7fBE7236c19925f62C442bA'
redeemAccount: MHhkNDJkNzFjZGMyQTBhNzhmRTdmQkU3MjM2YzE5OTI1ZjYyQzQ0MmJB
redeemChain: 0
29 changes: 15 additions & 14 deletions network
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,19 @@ function blockscout-help () {

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

function usage() {
Expand Down Expand Up @@ -181,6 +181,7 @@ function show-ports () {

function devnet () {
local CMD=$1
local VAR1=$2
case "$CMD" in
help|h)
shift
Expand Down Expand Up @@ -219,7 +220,7 @@ function devnet () {
shift
(
cd "$NETWORK_DIR" &&
bash state.sh
bash state.sh $VAR1
)
;;
summary)
Expand Down
Empty file added tests/docker-compose.yaml
Empty file.
43 changes: 43 additions & 0 deletions tests/e2e/chainUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { createPublicClient, defineChain, http } from 'viem';

export type EVMChainId = '20' | '21' | '22' | '23' | '24';
export const EVMCHAINS: EVMChainId[] = ['20', '21', '22', '23', '24'] as const;
const STARTBLOCKCHAINWEB = '5920';
const STARTCHAIN_ID = '20';

const createBlockChainId = (chainId: EVMChainId): number => {
return parseInt(STARTBLOCKCHAINWEB, 10) + parseInt(chainId, 10) - parseInt(STARTCHAIN_ID, 10);
};

export const createServerUrl = (chainId: EVMChainId) => {
return `http://localhost:1848/chainweb/0.0/evm-development/chain/${chainId}/evm/rpc`;
};

export const getChainwebEVMChain = (chainId: EVMChainId) => {
return defineChain({
id: createBlockChainId(chainId),

name: 'Kadena Chainweb EVM',
network: `kadena_${createBlockChainId(chainId)}`,
nativeCurrency: {
decimals: 18,
name: 'KDA',
symbol: 'KDA',
},
rpcUrls: {
default: {
http: [createServerUrl(chainId)],
},
public: {
http: [createServerUrl(chainId)],
},
},
});
};

export const getPublicClient = (chainId: EVMChainId) => {
return createPublicClient({
chain: getChainwebEVMChain(chainId),
transport: http(createServerUrl(chainId)),
});
};
132 changes: 132 additions & 0 deletions tests/e2e/check-container-logs.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { describe, test, expect, afterAll, beforeAll } from 'bun:test';
import {
CONFIG,
docker,
generateDockerComposeAndStartNetwork,
getDevnetStatus,
stopAndRemoveNetwork,
waitForMinCutHeight,
} from './devnet-utils';
import type { ContainerLogsOptions } from 'dockerode';

describe('e2e: check container logs during for errors, warnings, crashes etc', () => {
beforeAll(async () => {
await stopAndRemoveNetwork('kadena-dev');
await generateDockerComposeAndStartNetwork('kadena-dev');
});
afterAll(() => {
if (CONFIG.CLEAN_AFTER) {
// return stopAndRemoveNetwork('kadena-dev');
}
});

const containerArray = [
'miner-1-mining-client',
'miner-1-consensus',
'miner-1-evm-init-20',
'miner-1-evm-init-21',
'miner-1-evm-init-22',
'miner-1-evm-init-23',
'miner-1-evm-init-24',
'miner-1-evm-20',
'miner-1-evm-21',
'miner-1-evm-22',
'miner-1-evm-23',
'miner-1-evm-24',
'miner-2-mining-client',
'miner-2-consensus',
'miner-2-evm-init-20',
'miner-2-evm-init-21',
'miner-2-evm-init-22',
'miner-2-evm-init-23',
'miner-2-evm-init-24',
'miner-2-evm-20',
'miner-2-evm-21',
'miner-2-evm-22',
'miner-2-evm-23',
'miner-2-evm-24',
'bootnode-allocations',
'bootnode-consensus',
'bootnode-evm-init-20',
'bootnode-evm-init-21',
'bootnode-evm-init-22',
'bootnode-evm-init-23',
'bootnode-evm-init-24',
'bootnode-evm-20',
'bootnode-evm-21',
'bootnode-evm-22',
'bootnode-evm-23',
'bootnode-evm-24',
'appdev-frontend',
'appdev-evm-init-20',
'appdev-evm-init-24',
'appdev-evm-20',
'appdev-evm-24',
'appdev-consensus',
];

const filterErrorLines =
(cleanFunction?: (container: string, lines: string[]) => string[]) =>
async (container: string): Promise<string[]> => {
console.log('starting log check for', container);
const c = await docker.getContainer(container.trim());

// Fetch logs
const logBuffer = await c.logs({
follow: false,
stdout: true,
stderr: true,
timestamps: true,
});

// Convert buffer to string and split into lines
const logText = logBuffer.toString('utf8');
const logLines = logText.split('\n');
const affectedLines: string[] = [];

// Filter and display lines containing errors, warnings, or crashes
logLines.forEach((line) => {
if (/error|warning|crash|exception|failed/i.test(line)) {
affectedLines.push(line);
console.log(container, 'Issue detected:', line);
}
});

if (cleanFunction) {
return cleanFunction(container, affectedLines);
}

return affectedLines;
};

// the appdev-consensus container and the bootnode-consensus container have a some expected warnings
// because no miners were started in those containers. so we can ignore those lines
const cleanLines = (container: string, lines: string[]): string[] => {
return lines.filter(
(line) =>
!/EVM miner address is not set for ChainId/.test(line) &&
container !== 'appdev-consensus' &&
container !== 'bootnode-consensus'
);
};

test('should show no errors on startup', async () => {
const promises = containerArray.map(filterErrorLines(cleanLines));
const results = await Promise.all(promises);

results.forEach((logsArray) => {
expect(logsArray.length).toBe(0);
});
});
test('should show no errors during block production', async () => {
const devnetStatus = await getDevnetStatus();
await waitForMinCutHeight(devnetStatus.cutHeight + 98 * 1, { timeoutSeconds: 150 });

const promises = containerArray.map(filterErrorLines(cleanLines));
const results = await Promise.all(promises);

results.forEach((logsArray) => {
expect(logsArray.length).toBe(0);
});
});
});
Loading