From d3162aedfe00702465adfd13dcbe544eddcdefb3 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Fri, 13 Dec 2024 15:12:33 +0800 Subject: [PATCH] Problem: query with iavl legacy iterator is not tested --- .../configs/cosmovisor_recent.jsonnet | 34 ++++++ .../configs/upgrade-test-package-recent.nix | 26 +++++ .../contracts/contracts/CheckpointOracle.sol | 17 +++ integration_tests/test_upgrade.py | 93 ++-------------- integration_tests/test_upgrade_recent.py | 101 ++++++++++++++++++ integration_tests/utils.py | 83 +++++++++++++- 6 files changed, 267 insertions(+), 87 deletions(-) create mode 100644 integration_tests/configs/cosmovisor_recent.jsonnet create mode 100644 integration_tests/configs/upgrade-test-package-recent.nix create mode 100644 integration_tests/contracts/contracts/CheckpointOracle.sol create mode 100644 integration_tests/test_upgrade_recent.py diff --git a/integration_tests/configs/cosmovisor_recent.jsonnet b/integration_tests/configs/cosmovisor_recent.jsonnet new file mode 100644 index 0000000000..8fb93d721c --- /dev/null +++ b/integration_tests/configs/cosmovisor_recent.jsonnet @@ -0,0 +1,34 @@ +local config = import 'default.jsonnet'; + +config { + 'cronos_777-1'+: { + 'app-config'+: { + 'app-db-backend': 'rocksdb', + 'iavl-lazy-loading':: super['iavl-lazy-loading'], + }, + validators: [super.validators[0] { + 'app-config'+: { + store: { + streamers: ['versiondb'], + memiavl:: super.memiavl, + versiondb:: super.versiondb, + }, + }, + }] + super.validators[1:], + genesis+: { + consensus_params: { + block: { + max_bytes: '1048576', + max_gas: '81500000', + }, + }, + app_state+: { + gov+: { + params+: { + expedited_voting_period:: super['expedited_voting_period'], + }, + }, + }, + }, + }, +} diff --git a/integration_tests/configs/upgrade-test-package-recent.nix b/integration_tests/configs/upgrade-test-package-recent.nix new file mode 100644 index 0000000000..9ab30f1534 --- /dev/null +++ b/integration_tests/configs/upgrade-test-package-recent.nix @@ -0,0 +1,26 @@ +let + pkgs = import ../../nix { }; + fetchFlake = + repo: rev: + (pkgs.flake-compat { + src = { + outPath = builtins.fetchTarball "https://github.com/${repo}/archive/${rev}.tar.gz"; + inherit rev; + shortRev = builtins.substring 0 7 rev; + }; + }).defaultNix; + # release/v1.3.x + releasedGenesis = + (fetchFlake "crypto-org-chain/cronos" "e1d819c862b30f0ce978baf2addb12516568639e").default; + current = pkgs.callPackage ../../. { }; +in +pkgs.linkFarm "upgrade-test-package" [ + { + name = "genesis"; + path = releasedGenesis; + } + { + name = "v1.4"; + path = current; + } +] diff --git a/integration_tests/contracts/contracts/CheckpointOracle.sol b/integration_tests/contracts/contracts/CheckpointOracle.sol new file mode 100644 index 0000000000..276360e157 --- /dev/null +++ b/integration_tests/contracts/contracts/CheckpointOracle.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.4; + +contract CheckpointOracle { + mapping(address => bool) admins; + address[] adminList; + uint64 sectionIndex; + uint height; + bytes32 hash; + uint sectionSize; + uint processConfirms; + uint threshold; + + function VotingThreshold() public view returns (uint) { + return threshold; + } +} diff --git a/integration_tests/test_upgrade.py b/integration_tests/test_upgrade.py index 142d5a7429..763cbba29c 100644 --- a/integration_tests/test_upgrade.py +++ b/integration_tests/test_upgrade.py @@ -9,20 +9,18 @@ import pytest import requests from pystarport import ports -from pystarport.cluster import SUPERVISOR_CONFIG_FILE from .network import Cronos, setup_custom_cronos from .utils import ( ADDRS, CONTRACTS, - approve_proposal, assert_gov_params, deploy_contract, - edit_ini_sections, + do_upgrade, get_consensus_params, get_send_enable, + post_init, send_transaction, - wait_for_block, wait_for_new_blocks, wait_for_port, ) @@ -44,42 +42,6 @@ def get_txs(base_port, end): return res -def init_cosmovisor(home): - """ - build and setup cosmovisor directory structure in each node's home directory - """ - cosmovisor = home / "cosmovisor" - cosmovisor.mkdir() - (cosmovisor / "upgrades").symlink_to("../../../upgrades") - (cosmovisor / "genesis").symlink_to("./upgrades/genesis") - - -def post_init(path, base_port, config): - """ - prepare cosmovisor for each node - """ - chain_id = "cronos_777-1" - data = path / chain_id - cfg = json.loads((data / "config.json").read_text()) - for i, _ in enumerate(cfg["validators"]): - home = data / f"node{i}" - init_cosmovisor(home) - - edit_ini_sections( - chain_id, - data / SUPERVISOR_CONFIG_FILE, - lambda i, _: { - "command": f"cosmovisor run start --home %(here)s/node{i}", - "environment": ( - "DAEMON_NAME=cronosd," - "DAEMON_SHUTDOWN_GRACE=1m," - "UNSAFE_SKIP_BACKUP=true," - f"DAEMON_HOME=%(here)s/node{i}" - ), - }, - ) - - def setup_cronos_test(tmp_path_factory): path = tmp_path_factory.mktemp("upgrade") port = 26200 @@ -163,52 +125,11 @@ def exec(c, tmp_path_factory): wait_for_port(ports.evmrpc_port(base_port)) wait_for_new_blocks(cli, 1) - def do_upgrade(plan_name, target, mode=None): - print(f"upgrade {plan_name} height: {target}") - if plan_name == "v1.4.0-rc5-testnet": - rsp = cli.software_upgrade( - "community", - { - "name": plan_name, - "title": "upgrade test", - "note": "ditto", - "upgrade-height": target, - "summary": "summary", - "deposit": "10000basetcro", - }, - ) - assert rsp["code"] == 0, rsp["raw_log"] - approve_proposal(c, rsp["events"]) - else: - rsp = cli.gov_propose_legacy( - "community", - "software-upgrade", - { - "name": plan_name, - "title": "upgrade test", - "description": "ditto", - "upgrade-height": target, - "deposit": "10000basetcro", - }, - mode=mode, - ) - assert rsp["code"] == 0, rsp["raw_log"] - approve_proposal(c, rsp["logs"][0]["events"]) - - # update cli chain binary - c.chain_binary = ( - Path(c.chain_binary).parent.parent.parent / f"{plan_name}/bin/cronosd" - ) - # block should pass the target height - wait_for_block(c.cosmos_cli(), target + 2, timeout=480) - wait_for_port(ports.rpc_port(base_port)) - return c.cosmos_cli() - # test migrate keystore cli.migrate_keystore() height = cli.block_height() target_height0 = height + 15 - cli = do_upgrade("v1.1.0", target_height0, "block") + cli = do_upgrade(c, "v1.1.0", target_height0, "block") check_basic_tx(c) height = cli.block_height() @@ -231,7 +152,7 @@ def do_upgrade(plan_name, target, mode=None): ) print("old values", old_height, old_balance, old_base_fee) - cli = do_upgrade("v1.2", target_height1) + cli = do_upgrade(c, "v1.2", target_height1) check_basic_tx(c) # deploy contract should still work @@ -287,11 +208,11 @@ def do_upgrade(plan_name, target, mode=None): height = cli.block_height() txs = get_txs(base_port, height) - cli = do_upgrade("v1.3", height + 15) + cli = do_upgrade(c, "v1.3", height + 15) assert txs == get_txs(base_port, height) gov_param = cli.query_params("gov") - cli = do_upgrade("v1.4", cli.block_height() + 15) + cli = do_upgrade(c, "v1.4", cli.block_height() + 15) assert_evm_params(cli, e0, target_height0 - 1) assert_evm_params(cli, e1, target_height1 - 1) @@ -302,7 +223,7 @@ def do_upgrade(plan_name, target, mode=None): cli.query_params("icaauth") assert_gov_params(cli, gov_param) - cli = do_upgrade("v1.4.0-rc5-testnet", cli.block_height() + 15) + cli = do_upgrade(c, "v1.4.0-rc5-testnet", cli.block_height() + 15) check_basic_tx(c) diff --git a/integration_tests/test_upgrade_recent.py b/integration_tests/test_upgrade_recent.py new file mode 100644 index 0000000000..6bc9a4a91d --- /dev/null +++ b/integration_tests/test_upgrade_recent.py @@ -0,0 +1,101 @@ +import shutil +import stat +import subprocess +from concurrent.futures import ThreadPoolExecutor, as_completed +from contextlib import contextmanager +from pathlib import Path + +import pytest +import requests +from pystarport import ports + +from .network import setup_custom_cronos +from .utils import CONTRACTS, deploy_contract, do_upgrade, post_init + +pytestmark = pytest.mark.upgrade + + +@pytest.fixture(scope="module") +def custom_cronos(tmp_path_factory): + yield from setup_cronos_test(tmp_path_factory) + + +def get_txs(base_port, end): + port = ports.rpc_port(base_port) + res = [] + for h in range(1, end): + url = f"http://127.0.0.1:{port}/block_results?height={h}" + res.append(requests.get(url).json().get("result")["txs_results"]) + return res + + +def setup_cronos_test(tmp_path_factory): + path = tmp_path_factory.mktemp("upgrade") + port = 27100 + nix_name = "upgrade-test-package-recent" + cfg_name = "cosmovisor_recent" + configdir = Path(__file__).parent + cmd = [ + "nix-build", + configdir / f"configs/{nix_name}.nix", + ] + print(*cmd) + subprocess.run(cmd, check=True) + + # copy the content so the new directory is writable. + upgrades = path / "upgrades" + shutil.copytree("./result", upgrades) + mod = stat.S_IRWXU + upgrades.chmod(mod) + for d in upgrades.iterdir(): + d.chmod(mod) + + # init with genesis binary + with contextmanager(setup_custom_cronos)( + path, + port, + configdir / f"configs/{cfg_name}.jsonnet", + post_init=post_init, + chain_binary=str(upgrades / "genesis/bin/cronosd"), + ) as cronos: + yield cronos + + +def call(port, params): + url = f"http://127.0.0.1:{ports.evmrpc_port(port)}" + rsp = requests.post(url, json=params) + assert rsp.status_code == 200 + return rsp.json() + + +def call_check(c, address): + batch = 10 + concurrent = 10 + base_port = c.base_port(0) + param = { + "jsonrpc": "2.0", + "method": "eth_call", + "params": [ + { + "data": "0x0be5b6ba", + "to": address, + }, + "latest", + ], + "id": 1, + } + params = [] + for _ in range(batch): + params.append(param) + with ThreadPoolExecutor(concurrent) as executor: + tasks = [executor.submit(call, base_port, params) for _ in range(0, concurrent)] + results = [future.result() for future in as_completed(tasks)] + assert len(results) == concurrent + + +def test_cosmovisor_upgrade(custom_cronos): + c = custom_cronos + cli = c.cosmos_cli() + cli = do_upgrade(c, "v1.4", cli.block_height() + 15) + res = deploy_contract(c.w3, CONTRACTS["CheckpointOracle"]) + [call_check(c, res.address) for _ in range(10)] diff --git a/integration_tests/utils.py b/integration_tests/utils.py index 5ea3680dbb..3de987725f 100644 --- a/integration_tests/utils.py +++ b/integration_tests/utils.py @@ -24,7 +24,8 @@ from eth_account import Account from eth_utils import abi, to_checksum_address from hexbytes import HexBytes -from pystarport import ledger +from pystarport import ledger, ports +from pystarport.cluster import SUPERVISOR_CONFIG_FILE from web3._utils.contracts import abi_to_signature, find_matching_event_abi from web3._utils.events import get_event_data from web3._utils.method_formatters import receipt_formatter @@ -63,6 +64,7 @@ "TestICA": "TestICA.sol", "Random": "Random.sol", "TestRelayer": "TestRelayer.sol", + "CheckpointOracle": "CheckpointOracle.sol", } @@ -786,3 +788,82 @@ def assert_gov_params(cli, old_param): expedited_param = get_expedited_params(old_param) for key, value in expedited_param.items(): assert param[key] == value, param + + +def init_cosmovisor(home): + """ + build and setup cosmovisor directory structure in each node's home directory + """ + cosmovisor = home / "cosmovisor" + cosmovisor.mkdir() + (cosmovisor / "upgrades").symlink_to("../../../upgrades") + (cosmovisor / "genesis").symlink_to("./upgrades/genesis") + + +def post_init(path, base_port, config): + """ + prepare cosmovisor for each node + """ + chain_id = "cronos_777-1" + data = path / chain_id + cfg = json.loads((data / "config.json").read_text()) + for i, _ in enumerate(cfg["validators"]): + home = data / f"node{i}" + init_cosmovisor(home) + + edit_ini_sections( + chain_id, + data / SUPERVISOR_CONFIG_FILE, + lambda i, _: { + "command": f"cosmovisor run start --home %(here)s/node{i}", + "environment": ( + "DAEMON_NAME=cronosd," + "DAEMON_SHUTDOWN_GRACE=1m," + "UNSAFE_SKIP_BACKUP=true," + f"DAEMON_HOME=%(here)s/node{i}" + ), + }, + ) + + +def do_upgrade(c, plan_name, target, mode=None): + print(f"upgrade {plan_name} height: {target}") + cli = c.cosmos_cli() + if plan_name == "v1.4.0-rc5-testnet": + rsp = cli.software_upgrade( + "community", + { + "name": plan_name, + "title": "upgrade test", + "note": "ditto", + "upgrade-height": target, + "summary": "summary", + "deposit": "10000basetcro", + }, + ) + assert rsp["code"] == 0, rsp["raw_log"] + approve_proposal(c, rsp["events"]) + else: + rsp = cli.gov_propose_legacy( + "community", + "software-upgrade", + { + "name": plan_name, + "title": "upgrade test", + "description": "ditto", + "upgrade-height": target, + "deposit": "10000basetcro", + }, + mode=mode, + ) + assert rsp["code"] == 0, rsp["raw_log"] + approve_proposal(c, rsp["logs"][0]["events"]) + + # update cli chain binary + c.chain_binary = ( + Path(c.chain_binary).parent.parent.parent / f"{plan_name}/bin/cronosd" + ) + # block should pass the target height + wait_for_block(c.cosmos_cli(), target + 2, timeout=480) + wait_for_port(ports.rpc_port(c.base_port(0))) + return c.cosmos_cli()