Supports evmos as blockchain fullnode in python tests (#40)

* refine blockchain type

* Supports evmos

* cp evmos to code dir

* improve timestamp
This commit is contained in:
Bo QIU 2024-04-09 15:45:02 +08:00 committed by GitHub
parent 0047ab22d4
commit 3e22a6a027
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 245 additions and 38 deletions

View File

@ -0,0 +1,63 @@
#!/bin/bash
set -e
EVMOSD=$(cd $(dirname ${BASH_SOURCE[0]})/../tmp; pwd)/evmosd
ROOT_DIR=${1:-.}
NUM_NODES=${2:-3}
P2P_PORT_START=${3:-26656}
CHAIN_ID=evmospy_9000-777
# install jq if not unavailable
jq --version >/dev/null 2>&1 || sudo snap install jq -y
mkdir -p $ROOT_DIR
# Init configs
for ((i=0; i<$NUM_NODES; i++)) do
$EVMOSD init node$i --home $ROOT_DIR/node$i --chain-id $CHAIN_ID
# Change parameter token denominations to aevmos
GENESIS=$ROOT_DIR/node$i/config/genesis.json
TMP_GENESIS=$ROOT_DIR/node$i/config/tmp_genesis.json
cat $GENESIS | jq '.app_state["staking"]["params"]["bond_denom"]="aevmos"' >$TMP_GENESIS && mv $TMP_GENESIS $GENESIS
cat $GENESIS | jq '.app_state["gov"]["params"]["min_deposit"][0]["denom"]="aevmos"' >$TMP_GENESIS && mv $TMP_GENESIS $GENESIS
# Change app.toml
APP_TOML=$ROOT_DIR/node$i/config/app.toml
sed -i 's/minimum-gas-prices = "0aevmos"/minimum-gas-prices = "1aevmos"/' $APP_TOML
sed -i '/\[json-rpc\]/,/^\[/ s/enable = false/enable = true/' $APP_TOML
# Change config.toml
CONFIG_TOML=$ROOT_DIR/node$i/config/config.toml
sed -i '/seeds = /c\seeds = ""' $CONFIG_TOML
sed -i 's/addr_book_strict = true/addr_book_strict = false/' $CONFIG_TOML
done
# Update persistent_peers in config.toml
for ((i=1; i<$NUM_NODES; i++)) do
PERSISTENT_NODES=""
for ((j=0; j<$i; j++)) do
if [[ $j -gt 0 ]]; then PERSISTENT_NODES=$PERSISTENT_NODES,; fi
NODE_ID=`$EVMOSD tendermint show-node-id --home $ROOT_DIR/node$j`
P2P_PORT=$(($P2P_PORT_START+$j))
PERSISTENT_NODES=$PERSISTENT_NODES$NODE_ID@127.0.0.1:$P2P_PORT
done
sed -i "/persistent_peers = /c\persistent_peers = \"$PERSISTENT_NODES\"" $ROOT_DIR/node$i/config/config.toml
done
# Create genesis with a single validator
$EVMOSD keys add val0 --keyring-backend test --home $ROOT_DIR/node0
$EVMOSD add-genesis-account val0 1000000000evmos --keyring-backend test --home $ROOT_DIR/node0
# add genesis account for tests, see GENESIS_PRIV_KEY and GENESIS_PRIV_KEY1 in node_config.py
$EVMOSD add-genesis-account evmos1l0j9dqdvd3fatfqywhm4y6avrln4jracaapkme 1000000000evmos --home $ROOT_DIR/node0
$EVMOSD add-genesis-account evmos1pemg6y3etj9tlhkl0vdwkrw36f74u2nlpxf6wc 1000000000evmos --home $ROOT_DIR/node0
mkdir -p $ROOT_DIR/gentxs
$EVMOSD gentx val0 500000000evmos --keyring-backend test --home $ROOT_DIR/node0 --output-document $ROOT_DIR/gentxs/node0.json
$EVMOSD collect-gentxs --home $ROOT_DIR/node0 --gentx-dir $ROOT_DIR/gentxs
$EVMOSD validate-genesis --home $ROOT_DIR/node0
for ((i=1; i<$NUM_NODES; i++)) do
cp $ROOT_DIR/node0/config/genesis.json $ROOT_DIR/node$i/config/genesis.json
done

View File

@ -2,6 +2,7 @@ from web3 import Web3
ZGS_CONFIG = {
"log_config_file": "log_config",
"confirmation_block_count": 1,
}
BSC_CONFIG = dict(
@ -28,6 +29,7 @@ CONFLUX_CONFIG = dict(
)
BLOCK_SIZE_LIMIT = 200 * 1024
# 0xfbe45681Ac6C53D5a40475F7526baC1FE7590fb8
GENESIS_PRIV_KEY = "46b9e861b63d3509c88b7817275a30d22d62c8cd8fa6486ddee35ef0d8e0495f"
MINER_ID = "308a6e102a5829ba35e4ba1da0473c3e8bd45f5d3ffb91e31adb43f25463dddb"
GENESIS_ACCOUNT = Web3().eth.account.from_key(GENESIS_PRIV_KEY)
@ -37,6 +39,7 @@ TX_PARAMS = {
"from": GENESIS_ACCOUNT.address,
}
# 0x0e768D12395C8ABFDEdF7b1aEB0Dd1D27d5E2A7F
GENESIS_PRIV_KEY1 = "9a6d3ba2b0c7514b16a006ee605055d71b9edfad183aeb2d9790e9d4ccced471"
GENESIS_ACCOUNT1 = Web3().eth.account.from_key(GENESIS_PRIV_KEY1)
TX_PARAMS1 = {

View File

@ -2,7 +2,6 @@
from test_framework.blockchain_node import BlockChainNodeType
from test_framework.test_framework import TestFramework
from config.node_config import MINER_ID, GENESIS_PRIV_KEY
from test_framework.blockchain_node import BlockChainNodeType
from utility.submission import create_submission, submit_data
from utility.utils import wait_until

View File

@ -2,7 +2,6 @@
from test_framework.blockchain_node import BlockChainNodeType
from test_framework.test_framework import TestFramework
from config.node_config import MINER_ID, GENESIS_PRIV_KEY
from test_framework.blockchain_node import BlockChainNodeType
from utility.submission import create_submission, submit_data
from utility.utils import wait_until, assert_equal, assert_greater_than

View File

@ -2,7 +2,6 @@
import random
from test_framework.blockchain_node import BlockChainNodeType
from test_framework.test_framework import TestFramework
from utility.submission import create_submission
from utility.submission import submit_data
@ -81,4 +80,4 @@ class RandomTest(TestFramework):
if __name__ == "__main__":
RandomTest(blockchain_node_type=BlockChainNodeType.Conflux).main()
RandomTest().main()

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
from test_framework.test_framework import TestFramework
from test_framework.blockchain_node import BlockChainNodeType
from test_framework.test_framework import TestFramework
from test_framework.conflux_node import connect_nodes, disconnect_nodes, sync_blocks
from config.node_config import CONFLUX_CONFIG, TX_PARAMS1
from utility.submission import create_submission, submit_data

View File

@ -1,4 +1,3 @@
import json
import os
import subprocess
import tempfile
@ -14,9 +13,6 @@ from config.node_config import (
GENESIS_PRIV_KEY1,
TX_PARAMS,
MINER_ID,
NO_MERKLE_PROOF_FLAG,
NO_SEAL_FLAG,
TX_PARAMS1,
)
from utility.simple_rpc_proxy import SimpleRpcProxy
from utility.utils import (
@ -30,6 +26,7 @@ from test_framework.contracts import load_contract_metadata
class BlockChainNodeType(Enum):
Conflux = 0
BSC = 1
Evmos = 2
@unique
@ -46,7 +43,7 @@ class TestNode:
def __init__(
self, node_type, index, data_dir, rpc_url, binary, config, log, rpc_timeout=10
):
assert os.path.exists(binary), ("blockchain binary not found: %s" % binary)
assert os.path.exists(binary), ("Binary not found: %s" % binary)
self.node_type = node_type
self.index = index
self.data_dir = data_dir

View File

@ -0,0 +1,82 @@
import os
import subprocess
import tempfile
from test_framework.blockchain_node import BlockChainNodeType, BlockchainNode
from utility.utils import blockchain_rpc_port, arrange_port
EVMOS_PORT_CATEGORY_WS = 0
EVMOS_PORT_CATEGORY_P2P = 1
EVMOS_PORT_CATEGORY_RPC = 2
EVMOS_PORT_CATEGORY_PPROF = 3
def evmos_init_genesis(root_dir: str, num_nodes: int):
assert num_nodes > 0, "Invalid number of blockchain nodes: %s" % num_nodes
shell_script = os.path.join(
os.path.dirname(os.path.realpath(__file__)), # test_framework folder
"..", "config", "evmos-init-genesis.sh"
)
evmosd_dir = os.path.join(root_dir, "evmosd")
os.mkdir(evmosd_dir)
log_file = tempfile.NamedTemporaryFile(dir=evmosd_dir, delete=False, prefix="init_genesis_", suffix=".log")
p2p_port_start = arrange_port(EVMOS_PORT_CATEGORY_P2P, 0)
ret = subprocess.run(
args=["bash", shell_script, evmosd_dir, str(num_nodes), str(p2p_port_start)],
stdout=log_file,
stderr=log_file,
)
log_file.close()
assert ret.returncode == 0, "Failed to init evmos genesis, see more details in log file: %s" % log_file.name
class EvmosNode(BlockchainNode):
def __init__(
self,
index,
root_dir,
binary,
updated_config,
contract_path,
log,
rpc_timeout=10,
):
assert len(updated_config) == 0, "updated_config not supported for evmos"
data_dir = os.path.join(root_dir, "evmosd", "node" + str(index))
rpc_url = "http://127.0.0.1:%s" % blockchain_rpc_port(index)
super().__init__(
index,
data_dir,
rpc_url,
binary,
{},
contract_path,
log,
BlockChainNodeType.Evmos,
rpc_timeout,
)
self.config_file = None
self.args = [
binary, "start",
"--home", data_dir,
# overwrite json rpc http port: 8545
"--json-rpc.address", "127.0.0.1:%s" % blockchain_rpc_port(index),
# overwrite json rpc ws port: 8546
"--json-rpc.ws-address", "127.0.0.1:%s" % arrange_port(EVMOS_PORT_CATEGORY_WS, index),
# overwrite p2p port: 26656
"--p2p.laddr", "tcp://127.0.0.1:%s" % arrange_port(EVMOS_PORT_CATEGORY_P2P, index),
# overwrite rpc port: 26657
"--rpc.laddr", "tcp://127.0.0.1:%s" % arrange_port(EVMOS_PORT_CATEGORY_RPC, index),
# overwrite pprof port: 6060
"--rpc.pprof_laddr", "127.0.0.1:%s" % arrange_port(EVMOS_PORT_CATEGORY_PPROF, index),
]
def setup_config(self):
""" Already batch initialized by shell script in framework """

View File

@ -16,8 +16,8 @@ from test_framework.bsc_node import BSCNode
from test_framework.contract_proxy import FlowContractProxy, MineContractProxy, IRewardContractProxy
from test_framework.zgs_node import ZgsNode
from test_framework.blockchain_node import BlockChainNodeType
from test_framework.conflux_node import ConfluxNode, connect_sample_nodes, sync_blocks
from test_framework.conflux_node import ConfluxNode, connect_sample_nodes
from test_framework.evmos_node import EvmosNode, evmos_init_genesis
from utility.utils import PortMin, is_windows_platform, wait_until
__file_path__ = os.path.dirname(os.path.realpath(__file__))
@ -33,7 +33,7 @@ TEST_EXIT_FAILED = 1
class TestFramework:
def __init__(self, blockchain_node_type=BlockChainNodeType.Conflux):
def __init__(self, blockchain_node_type=BlockChainNodeType.Evmos):
if "http_proxy" in os.environ:
# Print a warning message in yellow color
print("\n\033[93m ⚠️ Warning: You've set the environment variable 'http_proxy', which might lead to testing issues.\033[0m\n")
@ -49,6 +49,7 @@ class TestFramework:
self.enable_market = False
self.mine_period = 100
# Set default binary path
binary_ext = ".exe" if is_windows_platform() else ""
tests_dir = os.path.dirname(__file_path__)
root_dir = os.path.dirname(tests_dir)
@ -58,6 +59,9 @@ class TestFramework:
self.__default_geth_binary__ = os.path.join(
tests_dir, "tmp", "geth" + binary_ext
)
self.__default_evmos_binary__ = os.path.join(
tests_dir, "tmp", "evmosd" + binary_ext
)
self.__default_zgs_node_binary__ = os.path.join(
root_dir, "target", "release", "zgs_node" + binary_ext
)
@ -66,6 +70,10 @@ class TestFramework:
)
def __setup_blockchain_node(self):
if self.blockchain_node_type == BlockChainNodeType.Evmos:
evmos_init_genesis(self.root_dir, self.num_blockchain_nodes)
self.log.info("Evmos genesis initialized for %s nodes" % self.num_blockchain_nodes)
for i in range(self.num_blockchain_nodes):
if i in self.blockchain_node_configs:
updated_config = self.blockchain_node_configs[i]
@ -92,6 +100,15 @@ class TestFramework:
self.contract_path,
self.log,
)
elif self.blockchain_node_type == BlockChainNodeType.Evmos:
node = EvmosNode(
i,
self.root_dir,
self.blockchain_binary,
updated_config,
self.contract_path,
self.log,
)
else:
raise NotImplementedError
@ -141,6 +158,14 @@ class TestFramework:
# The default is `dev` mode with auto mining, so it's not guaranteed that blocks
# can be synced in time for `sync_blocks` to pass.
# sync_blocks(self.blockchain_nodes)
elif self.blockchain_node_type == BlockChainNodeType.Evmos:
# wait for the first block
self.log.debug("Wait 3 seconds for evmos node to generate first block")
time.sleep(3)
for node in self.blockchain_nodes:
wait_until(lambda: node.net_peerCount() == self.num_blockchain_nodes - 1)
wait_until(lambda: node.eth_blockNumber() is not None)
wait_until(lambda: int(node.eth_blockNumber(), 16) > 0)
contract, tx_hash, mine_contract, reward_contract = self.blockchain_nodes[0].setup_contract(self.enable_market, self.mine_period)
self.contract = FlowContractProxy(contract, self.blockchain_nodes)
@ -172,7 +197,7 @@ class TestFramework:
)
self.nodes.append(node)
node.setup_config()
# wait firt node start for connection
# wait first node start for connection
if i > 0:
time.sleep(1)
node.start()
@ -196,6 +221,13 @@ class TestFramework:
type=str,
)
parser.add_argument(
"--evmos-binary",
dest="evmos",
default=self.__default_evmos_binary__,
type=str,
)
parser.add_argument(
"--zerog-storage-binary",
dest="zerog_storage",
@ -353,7 +385,7 @@ class TestFramework:
self.__setup_zgs_node()
def stop_nodes(self):
# stop ionion nodes first
# stop storage nodes first
for node in self.nodes:
node.stop()
@ -394,8 +426,12 @@ class TestFramework:
if self.blockchain_node_type == BlockChainNodeType.Conflux:
self.blockchain_binary = os.path.abspath(self.options.conflux)
else:
elif self.blockchain_node_type == BlockChainNodeType.BSC:
self.blockchain_binary = os.path.abspath(self.options.bsc)
elif self.blockchain_node_type == BlockChainNodeType.Evmos:
self.blockchain_binary = os.path.abspath(self.options.evmos)
else:
raise NotImplementedError
self.zgs_binary = os.path.abspath(self.options.zerog_storage)
self.cli_binary = os.path.abspath(self.options.cli)
@ -412,6 +448,7 @@ class TestFramework:
try:
self.setup_params()
self.setup_nodes()
self.log.debug("========== start to run tests ==========")
self.run_test()
success = TestStatus.PASSED
except AssertionError as e:

View File

@ -66,7 +66,7 @@ class ZgsNode(TestNode):
os.mkdir(self.data_dir)
log_config_path = os.path.join(self.data_dir, self.config["log_config_file"])
with open(log_config_path, "w") as f:
f.write("debug")
f.write("debug,hyper=info,h2=info")
initialize_toml_config(self.config_file, self.config)

View File

@ -15,6 +15,7 @@ DEFAULT_PORT_MAX = 65535
DEFAULT_PORT_RANGE = 500
CONFLUX_BINARY = "conflux.exe" if is_windows_platform() else "conflux"
EVMOS_BINARY = "evmosd.exe" if is_windows_platform() else "evmosd"
def print_testcase_result(color, glyph, script, start_time):
print(color[1] + glyph + " Testcase " + script + "\telapsed: " + str(int(time.time() - start_time)) + " seconds" + color[0], flush=True)
@ -59,13 +60,29 @@ def run_single_test(py, script, test_dir, index, port_min, port_max):
print_testcase_result(BLUE, TICK, script, start_time)
def run_all(test_dir: str, test_subdirs: list[str]=[], slow_tests: set[str]={}, long_manual_tests: set[str]={}):
start_time = time.time()
tmp_dir = os.path.join(test_dir, "tmp")
if not os.path.exists(tmp_dir):
os.makedirs(tmp_dir, exist_ok=True)
build_conflux_if_absent(tmp_dir)
# Build conflux binary if absent
build_from_github(
dir=tmp_dir,
binary_name=CONFLUX_BINARY,
github_url="https://github.com/Conflux-Chain/conflux-rust.git",
build_cmd="cargo build --release --bin conflux",
compiled_relative_path=["target", "release"],
)
# Build evmos binary if absent
build_from_github(
dir=tmp_dir,
binary_name=EVMOS_BINARY,
github_url="https://github.com/0glabs/0g-evmos.git",
build_cmd="make install; cp $(go env GOPATH)/bin/evmosd .",
compiled_relative_path=[],
)
start_time = time.time()
parser = argparse.ArgumentParser(usage="%(prog)s [options]")
parser.add_argument(
@ -139,29 +156,38 @@ def run_all(test_dir: str, test_subdirs: list[str]=[], slow_tests: set[str]={},
print(c)
sys.exit(1)
def build_from_github(dir: str, binary_name: str, github_url: str, build_cmd: str, compiled_relative_path: list[str]) -> bool:
binary_path = os.path.join(dir, binary_name)
if os.path.exists(binary_path):
return False
def build_conflux_if_absent(tmp_dir):
conflux_path = os.path.join(tmp_dir, CONFLUX_BINARY)
if os.path.exists(conflux_path):
return
start_time = time.time()
conflux_tmp_dir = os.path.join(tmp_dir, "conflux_tmp")
if os.path.exists(conflux_tmp_dir):
shutil.rmtree(conflux_tmp_dir)
clone_command = "git clone https://github.com/Conflux-Chain/conflux-rust.git"
clone_with_path = clone_command + " " + conflux_tmp_dir
os.system(clone_with_path)
# clone code from github to a temp folder
code_tmp_dir_name = (binary_name[:-4] if is_windows_platform() else binary_name) + "_tmp"
code_tmp_dir = os.path.join(dir, code_tmp_dir_name)
if os.path.exists(code_tmp_dir):
shutil.rmtree(code_tmp_dir)
clone_command = "git clone " + github_url + " " + code_tmp_dir
os.system(clone_command)
# build binary
origin_path = os.getcwd()
os.chdir(conflux_tmp_dir)
os.system("cargo build --release --bin conflux")
os.chdir(code_tmp_dir)
os.system(build_cmd)
path = os.path.join(conflux_tmp_dir, "target", "release", CONFLUX_BINARY)
shutil.copyfile(path, conflux_path)
# copy compiled binary to right place
compiled_binary = os.path.join(code_tmp_dir, *compiled_relative_path, binary_name)
shutil.copyfile(compiled_binary, binary_path)
if not is_windows_platform():
st = os.stat(conflux_path)
os.chmod(conflux_path, st.st_mode | stat.S_IEXEC)
st = os.stat(binary_path)
os.chmod(binary_path, st.st_mode | stat.S_IEXEC)
os.chdir(origin_path)
shutil.rmtree(code_tmp_dir, ignore_errors=True)
print("Completed to build binary " + binary_name + ", Elapsed: " + str(int(time.time() - start_time)) + " seconds", flush=True)
return True

View File

@ -37,6 +37,8 @@ def blockchain_rpc_port(n):
def blockchain_rpc_port_core(n):
return PortMin.n + 4 * MAX_NODES + n
def arrange_port(category: int, node_index: int) -> int:
return PortMin.n + (100 + category) * MAX_NODES + node_index
def wait_until(predicate, *, attempts=float("inf"), timeout=float("inf"), lock=None):
if attempts == float("inf") and timeout == float("inf"):