From 394bce57c8cd9409128207e1946fb4297010fc10 Mon Sep 17 00:00:00 2001 From: yihuang Date: Thu, 2 Nov 2023 13:17:05 +0800 Subject: [PATCH 1/3] Problem: logs in callback contract are lost (#1233) * Problem: logs in callback contract are lost Closes: #1231 Solution: - re-emit those logs * Update CHANGELOG.md Signed-off-by: yihuang * constant refactor * fix getLogs * use precompile relayer to test ica callback * cover crc20 callbacks as well * inject the statedb in ethermint * simplify assert log * test without rly precompile * cleanup * Revert "test without rly precompile" This reverts commit 25c3feedfb8e85b2509f82a39cc0743e7c778a2d. --------- Signed-off-by: yihuang Co-authored-by: mmsqe --- CHANGELOG.md | 1 + go.mod | 2 +- go.sum | 4 ++-- gomod2nix.toml | 4 ++-- integration_tests/test_ica_precompile.py | 21 +++++++++++++++++++-- x/cronos/keeper/evm.go | 10 ++++++++++ 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 664257e030..2e11d90d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - [#1217](https://github.com/crypto-org-chain/cronos/pull/1217) Use the default chain-id behavour in sdk. - [#1216](https://github.com/crypto-org-chain/cronos/pull/1216) Update ethermint to fix of avoid redundant parse chainID from gensis when start server. - [#1230](https://github.com/crypto-org-chain/cronos/pull/1230) Fix mem store in versiondb multistore. +- [#1233](https://github.com/crypto-org-chain/cronos/pull/1233) Re-emit logs in callback contract. *October 17, 2023* diff --git a/go.mod b/go.mod index 49be3460c3..561b82d3f2 100644 --- a/go.mod +++ b/go.mod @@ -234,7 +234,7 @@ replace ( // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 github.com/ethereum/go-ethereum => github.com/evmos/go-ethereum v1.10.26-evmos-rc1 - github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.6.1-0.20231027030935-291bfa0458c4 + github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.6.1-0.20231101080732-b9078abfe0fd // Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0 diff --git a/go.sum b/go.sum index 00183b6562..147cee1f5e 100644 --- a/go.sum +++ b/go.sum @@ -484,8 +484,8 @@ github.com/crypto-org-chain/cometbft-db v0.0.0-20231011055109-57922ac52a63 h1:R1 github.com/crypto-org-chain/cometbft-db v0.0.0-20231011055109-57922ac52a63/go.mod h1:rocwIfnS+kA060x64gkSIRvWB9StSppIkJuo5MWzL24= github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20231013072415-eec017435467 h1:m0/aHPIJAzi2MSP3TXzzbLTFf+koRFQiaYmerRZUtK4= github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20231013072415-eec017435467/go.mod h1:G384omH7cXgm90xXR7xpHvsKG7vdBaDuz4To6GpTHUU= -github.com/crypto-org-chain/ethermint v0.6.1-0.20231027030935-291bfa0458c4 h1:uLaq7qqIYJ2tJ5fQE5EBvqAgvM5Y4jWbz9V4AURwMGI= -github.com/crypto-org-chain/ethermint v0.6.1-0.20231027030935-291bfa0458c4/go.mod h1:rbAKU2rftDobCIoCiol3SO+bTqw2cERu9TEki7PvfK0= +github.com/crypto-org-chain/ethermint v0.6.1-0.20231101080732-b9078abfe0fd h1:8AWwJrxYtQxoZ1rrM9+w6MLScVe6LzskRo8UF9ep7Qs= +github.com/crypto-org-chain/ethermint v0.6.1-0.20231101080732-b9078abfe0fd/go.mod h1:rbAKU2rftDobCIoCiol3SO+bTqw2cERu9TEki7PvfK0= github.com/crypto-org-chain/gravity-bridge/module/v2 v2.0.1-0.20230825054824-75403cd90c6e h1:rSTc35OBjjCBx47rHPWBCIHNGPbMnEj8f7fNcK2TjVI= github.com/crypto-org-chain/gravity-bridge/module/v2 v2.0.1-0.20230825054824-75403cd90c6e/go.mod h1:HBaDqlFjlaXJwVQtA7jHejyaA7xwjXI2o6pU/ccP3tE= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= diff --git a/gomod2nix.toml b/gomod2nix.toml index a208b4cfe0..f433fd8f68 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -216,8 +216,8 @@ schema = 3 hash = "sha256-GgcReGsIIuBE2TabDYqDO9sBGogdVr9RSh4arQzdPnE=" replaced = "github.com/evmos/go-ethereum" [mod."github.com/evmos/ethermint"] - version = "v0.6.1-0.20231027030935-291bfa0458c4" - hash = "sha256-T+iQ9tSyGTvJn7wSIFCFWqUeU9KUk3Ml4v1rgC9FENk=" + version = "v0.6.1-0.20231101080732-b9078abfe0fd" + hash = "sha256-FlKoOdJbNqQfloOxV5AGd5TIm3VLjoZW8YOLnuJY7FY=" replaced = "github.com/crypto-org-chain/ethermint" [mod."github.com/felixge/httpsnoop"] version = "v1.0.2" diff --git a/integration_tests/test_ica_precompile.py b/integration_tests/test_ica_precompile.py index 52c39e14c7..0174d4a66f 100644 --- a/integration_tests/test_ica_precompile.py +++ b/integration_tests/test_ica_precompile.py @@ -3,6 +3,7 @@ from enum import IntEnum import pytest +from pystarport import cluster from web3.datastructures import AttributeDict from .ibc_utils import ( @@ -45,9 +46,15 @@ class Status(IntEnum): @pytest.fixture(scope="module") def ibc(request, tmp_path_factory): "prepare-network" - name = "ibc" + name = "ibc_rly" path = tmp_path_factory.mktemp(name) - yield from prepare_network(path, name, incentivized=False, connection_only=True) + yield from prepare_network( + path, + name, + incentivized=False, + connection_only=True, + relayer=cluster.Relayer.RLY.value, + ) def register_acc(cli, w3, register, query, data, addr, channel_id): @@ -177,6 +184,12 @@ def check_status(): wait_for_fn("current status", check_status) +def assert_packet_result(event, seq, status): + (logs) = event.getLogs() + assert len(logs) > 0 + return logs[0].args == AttributeDict({"seq": seq, "status": status}) + + def test_sc_call(ibc): cli_host = ibc.chainmain.cosmos_cli() cli_controller = ibc.cronos.cosmos_cli() @@ -243,6 +256,7 @@ def submit_msgs_ro(func, str): status = tcontract.caller.statusMap(last_seq) assert expected_seq == last_seq assert status == Status.SUCCESS + assert_packet_result(tcontract.events.OnPacketResult, last_seq, status) balance -= diff assert cli_host.balance(ica_address, denom=denom) == balance @@ -262,6 +276,7 @@ def submit_msgs_ro(func, str): status = tcontract.caller.statusMap(last_seq) assert expected_seq == last_seq assert status == Status.SUCCESS + assert_packet_result(tcontract.events.OnPacketResult, last_seq, status) balance -= diff assert cli_host.balance(ica_address, denom=denom) == balance @@ -282,6 +297,7 @@ def submit_msgs_ro(func, str): status = tcontract.caller.statusMap(last_seq) assert expected_seq == last_seq assert status == Status.FAIL + assert_packet_result(tcontract.events.OnPacketResult, last_seq, status) assert cli_host.balance(ica_address, denom=denom) == balance # balance should not change on timeout @@ -301,4 +317,5 @@ def submit_msgs_ro(func, str): status = tcontract.caller.statusMap(last_seq) assert expected_seq == last_seq assert status == Status.FAIL + assert_packet_result(tcontract.events.OnPacketResult, last_seq, status) assert cli_host.balance(ica_address, denom=denom) == balance diff --git a/x/cronos/keeper/evm.go b/x/cronos/keeper/evm.go index 3b17abb73b..b722a17204 100644 --- a/x/cronos/keeper/evm.go +++ b/x/cronos/keeper/evm.go @@ -8,7 +8,9 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/evmos/ethermint/x/evm/statedb" evmtypes "github.com/evmos/ethermint/x/evm/types" "github.com/crypto-org-chain/cronos/v2/x/cronos/types" @@ -35,6 +37,14 @@ func (k Keeper) CallEVM(ctx sdk.Context, to *common.Address, data []byte, value if err != nil { return nil, nil, err } + + // if the call is from an precompiled contract call, then re-emit the logs into the original stateDB. + if stateDB, ok := ctx.Value(statedb.StateDBContextKey).(vm.StateDB); ok { + for _, l := range ret.Logs { + stateDB.AddLog(l.ToEthereum()) + } + } + return &msg, ret, nil } From 0553602865adbefd79500182bdf34c86f623e0a9 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 2 Nov 2023 17:14:24 +0800 Subject: [PATCH 2/3] simplify event test --- integration_tests/test_ica_precompile.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/integration_tests/test_ica_precompile.py b/integration_tests/test_ica_precompile.py index 0174d4a66f..3b6448ae3d 100644 --- a/integration_tests/test_ica_precompile.py +++ b/integration_tests/test_ica_precompile.py @@ -21,16 +21,11 @@ KEYS, deploy_contract, eth_to_bech32, - get_logs_since, - get_method_map, - get_topic_data, send_transaction, wait_for_fn, ) CONTRACT = "0x0000000000000000000000000000000000000066" -contract_info = json.loads(CONTRACT_ABIS["IICAModule"].read_text()) -method_map = get_method_map(contract_info) connid = "connection-0" no_timeout = 300000000000 denom = "basecro" @@ -79,6 +74,7 @@ def submit_msgs( ica_address, add_delegate, expected_seq, + event, timeout=no_timeout, amount=amt, need_wait=True, @@ -109,7 +105,6 @@ def submit_msgs( diff_amt += amt1 generated_packet = cli_controller.ica_generate_packet_data(json.dumps(msgs)) num_txs = len(cli_host.query_all_txs(ica_address)["txs"]) - start = w3.eth.get_block_number() str = base64.b64decode(generated_packet["data"]) # submit transaction on host chain on behalf of interchain account tx = func(connid, str, timeout).build_transaction(data) @@ -120,12 +115,9 @@ def submit_msgs( print(f"wait for {timeout_in_s}s") wait_for_check_tx(cli_host, ica_address, num_txs, timeout_in_s) else: - logs = get_logs_since(w3, CONTRACT, start) - expected = [{"seq": expected_seq}] - assert len(logs) == len(expected) - for i, log in enumerate(logs): - method_name, args = get_topic_data(w3, method_map, contract_info, log) - assert args == AttributeDict(expected[i]), [i, method_name] + (logs) = event.getLogs() + assert len(logs) > 0 + assert logs[0].args == AttributeDict({"seq": expected_seq}) if need_wait: wait_for_check_tx(cli_host, ica_address, num_txs) return str, diff_amt @@ -137,6 +129,7 @@ def test_call(ibc): w3 = ibc.cronos.w3 name = "signer2" addr = ADDRS[name] + contract_info = json.loads(CONTRACT_ABIS["IICAModule"].read_text()) contract = w3.eth.contract(address=CONTRACT, abi=contract_info) data = {"from": ADDRS[name]} ica_address = register_acc( @@ -157,6 +150,7 @@ def test_call(ibc): ica_address, False, expected_seq, + contract.events.SubmitMsgsResult, ) balance -= diff assert cli_host.balance(ica_address, denom=denom) == balance @@ -168,6 +162,7 @@ def test_call(ibc): ica_address, True, expected_seq, + contract.events.SubmitMsgsResult, ) balance -= diff assert cli_host.balance(ica_address, denom=denom) == balance @@ -194,6 +189,7 @@ def test_sc_call(ibc): cli_host = ibc.chainmain.cosmos_cli() cli_controller = ibc.cronos.cosmos_cli() w3 = ibc.cronos.w3 + contract_info = json.loads(CONTRACT_ABIS["IICAModule"].read_text()) contract = w3.eth.contract(address=CONTRACT, abi=contract_info) jsonfile = CONTRACTS["TestICA"] tcontract = deploy_contract(w3, jsonfile) @@ -248,6 +244,7 @@ def submit_msgs_ro(func, str): ica_address, False, expected_seq, + contract.events.SubmitMsgsResult, ) submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str) submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str) @@ -268,6 +265,7 @@ def submit_msgs_ro(func, str): ica_address, True, expected_seq, + contract.events.SubmitMsgsResult, ) submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str) submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str) @@ -289,6 +287,7 @@ def submit_msgs_ro(func, str): ica_address, False, expected_seq, + contract.events.SubmitMsgsResult, amount=100000001, need_wait=False, ) @@ -310,6 +309,7 @@ def submit_msgs_ro(func, str): ica_address, False, expected_seq, + contract.events.SubmitMsgsResult, timeout, ) last_seq = tcontract.caller.getLastSeq() From 5be231fdc21ad056ff05abb45a0d983e18321bd1 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Thu, 2 Nov 2023 18:03:49 +0800 Subject: [PATCH 3/3] logs --- integration_tests/test_ibc_rly.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/integration_tests/test_ibc_rly.py b/integration_tests/test_ibc_rly.py index 7e32f0c2f1..bf91a7ef52 100644 --- a/integration_tests/test_ibc_rly.py +++ b/integration_tests/test_ibc_rly.py @@ -189,6 +189,7 @@ def check_balance_change(): wait_for_fn("balance change", check_balance_change) assert old_dst_balance + dst_amount == new_dst_balance logs = get_logs_since(w3, CONTRACT, start) + print("mm-test_ibc", logs) relayer0 = ibc.chainmain.cosmos_cli().address("relayer") relayer = to_checksum_address(bech32_to_eth(relayer0)) cronos_addr = module_address("cronos") @@ -205,6 +206,31 @@ def check_balance_change(): for i, log in enumerate(logs): method_name, args = get_topic_data(w3, method_map, contract_info, log) assert args == AttributeDict(expected[i]), [i, method_name] + + # contract = w3.eth.contract(address=CONTRACT, abi=contract_info) + # # recv_packet + # (logs1) = contract.events.RecvPacket.getLogs() + # print("mm-logs1", logs1) + # # denom_trace + # (logs2) = contract.events.DenominationTrace.getLogs() + # print("mm-logs2", logs2) + # # send_from_module_to_acc + # (logs3) = contract.events.CoinReceived.getLogs() + # print("mm-logs3", logs3) + # (logs4) = contract.events.Coinbase.getLogs() + # print("mm-logs4", logs4) + # # send_from_module_to_acc send_coins + # (logs5) = contract.events.CoinSpent.getLogs() + # print("mm-logs5", logs5) + # (logs7) = contract.events.Transfer.getLogs() + # print("mm-logs7", logs7) + # # fungible + # (logs8) = contract.events.FungibleTokenPacket.getLogs() + # print("mm-logs8", logs8) + # # write_ack + # (logs17) = contract.events.WriteAcknowledgement.getLogs() + # print("mm-logs17", logs17) + def get_escrow_address(cli, channel): @@ -276,6 +302,7 @@ def test_cronos_transfer_source_tokens(ibc): escrow = get_escrow_address(cli, channel) dst_adr = ibc.chainmain.cosmos_cli().address("signer2") expected = get_transfer_source_tokens_topics(dst_adr, amount, contract, escrow) + print("mm-test_cronos_transfer_source_tokens", logs) assert len(logs) == len(expected) for i, log in enumerate(logs): method_name, args = get_topic_data(w3, method_map, contract_info, log)