Skip to content

Commit

Permalink
Problem: no stateful precompiled contract for ica (#1163)
Browse files Browse the repository at this point in the history
* register ica

* send tx

add doc

* test send tx

* emit event

fix decode

* pass converter

* gen binding

* ica event

* choose default decorder

* Apply suggestions from code review

* emit res

* adjust emit

* pass encode proto msg

* fix lint

* test

* add seq

* Revert "add seq"

This reverts commit af97a1a.

* Revert "pass encode proto msg"

This reverts commit 766071f.

* avoid fork ibc-go

cleanup

* test timeout_duration

* Update integration_tests/test_upgrade.py

Signed-off-by: mmsqe <[email protected]>

* test ica rly

* cleanup

* test multi types

* make proto-all

* Apply suggestions from code review

* test readonly call

* fix lint

* allow control by contract

* pack output

* point to log fix

* fix call ica

* make use of binding

rm dup sol

* add last seq

* cleanup

* seq as uint64

* Apply suggestions from code review

* update rly

* pass raw data into precompile

* fix py lint

* fix packet data

* fix resolve

---------

Signed-off-by: mmsqe <[email protected]>
Co-authored-by: HuangYi <[email protected]>
  • Loading branch information
mmsqe and yihuang authored Sep 25, 2023
1 parent a47e6b1 commit 3313f54
Show file tree
Hide file tree
Showing 38 changed files with 1,189 additions and 272 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
- (deps) [#1121](https://github.com/crypto-org-chain/cronos/pull/1121) Bump Cosmos-SDK to v0.47.5 and ibc-go to v7.2.0.
- [cronos#1014](https://github.com/crypto-org-chain/cronos/pull/1014) Support stateful precompiled contract for relayer.
- [cronos#1165](https://github.com/crypto-org-chain/cronos/pull/1165) Icaauth module is not adjusted correctly in ibc-go v7.2.0.
- [cronos#1163](https://github.com/crypto-org-chain/cronos/pull/1163) Support stateful precompiled contract for ica.
- [cronos#837](https://github.com/crypto-org-chain/cronos/pull/837) Support stateful precompiled contract for bank.

### Bug Fixes
Expand Down
1 change: 1 addition & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,7 @@ func New(
[]vm.PrecompiledContract{
cronosprecompiles.NewBankContract(app.BankKeeper, appCodec),
cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec),
cronosprecompiles.NewIcaContract(&app.ICAAuthKeeper, appCodec),
},
allKeys,
)
Expand Down
2 changes: 1 addition & 1 deletion app/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func benchmarkERC20Transfer(b *testing.B, db dbm.DB) {
ethSigner := ethtypes.LatestSignerForChainID(chainID)

signTx := func(msg *evmtypes.MsgEthereumTx) ([]byte, error) {
msg.From = address.String()
msg.From = address.Bytes()
if err := msg.Sign(ethSigner, signer); err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,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.20230921025237-ae144329ecaf
github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135
// 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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,8 @@ github.com/crypto-org-chain/cometbft-db v0.0.0-20230921030527-0d47d7537e32 h1:Vq
github.com/crypto-org-chain/cometbft-db v0.0.0-20230921030527-0d47d7537e32/go.mod h1:V32HRAjDsAYLfAT90mk0O9UH+sE7P5apfiCmmmVLt3Q=
github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20230905040840-b3af5590283b h1:d2GOFR3i3BjDlPsmJkp8Gsrt9LK2nq2IVEnE/rMv1Fo=
github.com/crypto-org-chain/cosmos-sdk v0.46.0-beta2.0.20230905040840-b3af5590283b/go.mod h1:EHwCeN9IXonsjKcjpS12MqeStdZvIdxt3VYXhus3G3c=
github.com/crypto-org-chain/ethermint v0.6.1-0.20230921025237-ae144329ecaf h1:XvwFJ6kPHOYevfNjshq4n2nazvYzoSaQ8AjSYWSfUhI=
github.com/crypto-org-chain/ethermint v0.6.1-0.20230921025237-ae144329ecaf/go.mod h1:KtjU2MHMCTcLnAoS9C3U3f+vx4f9HHNQRcOlxXiVDxY=
github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135 h1:hF+Xu71O4pKb8kvlGRO41qR9dqavoaqg4k1xOKZ0m9k=
github.com/crypto-org-chain/ethermint v0.6.1-0.20230925010909-716b0754a135/go.mod h1:KtjU2MHMCTcLnAoS9C3U3f+vx4f9HHNQRcOlxXiVDxY=
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=
Expand Down
4 changes: 2 additions & 2 deletions gomod2nix.toml
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ schema = 3
hash = "sha256-GgcReGsIIuBE2TabDYqDO9sBGogdVr9RSh4arQzdPnE="
replaced = "github.com/evmos/go-ethereum"
[mod."github.com/evmos/ethermint"]
version = "v0.6.1-0.20230921025237-ae144329ecaf"
hash = "sha256-ZDzwB65qROKNIB4Yv1i+5FTJoejeuRCcUzUacyuFBFw="
version = "v0.6.1-0.20230925010909-716b0754a135"
hash = "sha256-I4NiYqyR3Cgs4QWrqod9ABCtpU0c5LVlyGr38GNjAxg="
replaced = "github.com/crypto-org-chain/ethermint"
[mod."github.com/felixge/httpsnoop"]
version = "v1.0.2"
Expand Down
6 changes: 6 additions & 0 deletions integration_tests/configs/ibc.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ config {
base_fee: '0',
},
},
icaauth: {
params: {
min_timeout_duration: '1ms',
},
},
},
},
},
Expand Down Expand Up @@ -100,6 +105,7 @@ config {
params: {
allow_messages: [
'/cosmos.bank.v1beta1.MsgSend',
'/cosmos.staking.v1beta1.MsgDelegate',
],
},
},
Expand Down
95 changes: 95 additions & 0 deletions integration_tests/contracts/contracts/TestICA.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {IICAModule} from "./src/ICA.sol";

contract TestICA {
address constant icaContract = 0x0000000000000000000000000000000000000066;
IICAModule ica = IICAModule(icaContract);
address account;
uint64 lastAckSeq;

function encodeRegister(string memory connectionID, string memory version) internal view returns (bytes memory) {
return abi.encodeWithSignature(
"registerAccount(string,string)",
connectionID, msg.sender, version
);
}

function callRegister(string memory connectionID, string memory version) public returns (bool) {
require(account == address(0) || account == msg.sender, "register fail");
bool result = ica.registerAccount(connectionID, version);
require(result, "call failed");
account = msg.sender;
}

function getAccount() public view returns (address) {
return account;
}

function delegateRegister(string memory connectionID, string memory version) public returns (bool) {
(bool result,) = icaContract.delegatecall(encodeRegister(connectionID, version));
require(result, "call failed");
return true;
}

function staticRegister(string memory connectionID, string memory version) public returns (bool) {
(bool result,) = icaContract.staticcall(encodeRegister(connectionID, version));
require(result, "call failed");
return true;
}

function encodeQueryAccount(string memory connectionID, address addr) internal view returns (bytes memory) {
return abi.encodeWithSignature(
"queryAccount(string,address)",
connectionID, addr
);
}

function callQueryAccount(string memory connectionID, address addr) public returns (string memory) {
return ica.queryAccount(connectionID, addr);
}

function delegateQueryAccount(string memory connectionID, address addr) public returns (string memory) {
(bool result, bytes memory data) = icaContract.delegatecall(encodeQueryAccount(connectionID, addr));
require(result, "call failed");
return abi.decode(data, (string));
}

function staticQueryAccount(string memory connectionID, address addr) public returns (string memory) {
(bool result, bytes memory data) = icaContract.staticcall(encodeQueryAccount(connectionID, addr));
require(result, "call failed");
return abi.decode(data, (string));
}

function encodeSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) internal view returns (bytes memory) {
return abi.encodeWithSignature(
"submitMsgs(string,bytes,uint256)",
connectionID, msg.sender, data, timeout
);
}

function callSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) {
require(account == msg.sender, "not authorized");
lastAckSeq = ica.submitMsgs(connectionID, data, timeout);
return lastAckSeq;
}

function delegateSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) {
(bool result, bytes memory data) = icaContract.delegatecall(encodeSubmitMsgs(connectionID, data, timeout));
require(result, "call failed");
lastAckSeq = abi.decode(data, (uint64));
return lastAckSeq;
}

function staticSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) {
(bool result, bytes memory data) = icaContract.staticcall(encodeSubmitMsgs(connectionID, data, timeout));
require(result, "call failed");
lastAckSeq = abi.decode(data, (uint64));
return lastAckSeq;
}

function getLastAckSeq() public view returns (uint256) {
return lastAckSeq;
}
}
21 changes: 6 additions & 15 deletions integration_tests/cosmoscli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,10 +1062,10 @@ def set_delegate_keys(self, val_addr, acc_addr, eth_addr, signature, **kwargs):
)

def query_gravity_params(self):
return json.loads(self.raw("query", "gravity", "params", home=self.data_dir))
return self.query_params("gravity")

def query_evm_params(self):
return json.loads(self.raw("query", "evm", "params", home=self.data_dir))
def query_params(self, module="cronos"):
return json.loads(self.raw("query", module, "params", home=self.data_dir))

def query_signer_set_txs(self):
return json.loads(
Expand Down Expand Up @@ -1275,7 +1275,7 @@ def icaauth_register_account(self, connid, **kwargs):
rsp = self.event_query_tx_for(rsp["txhash"])
return rsp

def icaauth_submit_tx(self, connid, tx, **kwargs):
def icaauth_submit_tx(self, connid, tx, timeout_duration="1h", **kwargs):
default_kwargs = {
"home": self.data_dir,
"node": self.node_rpc,
Expand All @@ -1289,6 +1289,8 @@ def icaauth_submit_tx(self, connid, tx, **kwargs):
"submit-tx",
connid,
tx,
"--timeout-duration" if timeout_duration else None,
timeout_duration if timeout_duration else None,
"-y",
**(default_kwargs | kwargs),
)
Expand Down Expand Up @@ -1586,17 +1588,6 @@ def turn_bridge(self, enable, **kwargs):
)
)

def query_params(self):
"query cronos params"
return json.loads(
self.raw(
"query",
"cronos",
"params",
home=self.data_dir,
)
)

def evm_params(self, **kwargs):
default_kwargs = {
"node": self.node_rpc,
Expand Down
19 changes: 17 additions & 2 deletions integration_tests/ibc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,21 @@ def funds_ica(cli, adr):
rsp = cli.transfer("signer2", adr, "1cro", gas_prices="1000000basecro")
assert rsp["code"] == 0, rsp["raw_log"]
wait_for_new_blocks(cli, 1)

amt = 100000000
# check if the funds are received in interchain account
assert cli.balance(adr, denom="basecro") == 100000000
assert cli.balance(adr, denom="basecro") == amt
return amt


def assert_channel_open_init(rsp):
assert rsp["code"] == 0, rsp["raw_log"]
port_id, channel_id = next(
(
evt["attributes"][0]["value"],
evt["attributes"][1]["value"],
)
for evt in rsp["events"]
if evt["type"] == "channel_open_init"
)
print("port-id", port_id, "channel-id", channel_id)
return port_id, channel_id
62 changes: 14 additions & 48 deletions integration_tests/test_ibc_rly.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import subprocess

import pytest
from eth_utils import abi, keccak, to_checksum_address
from eth_utils import keccak, to_checksum_address
from pystarport import cluster
from web3._utils.contracts import abi_to_signature, find_matching_event_abi
from web3._utils.events import get_event_data
from web3.datastructures import AttributeDict

from .ibc_utils import (
Expand All @@ -24,14 +22,17 @@
CONTRACT_ABIS,
bech32_to_eth,
eth_to_bech32,
get_logs_since,
get_method_map,
get_topic_data,
module_address,
wait_for_fn,
wait_for_new_blocks,
)

CONTRACT = "0x0000000000000000000000000000000000000065"
method_map = None
contract_info = None
contract_info = json.loads(CONTRACT_ABIS["IRelayerModule"].read_text())
method_map = get_method_map(contract_info)
cronos_signer2 = ADDRS["signer2"]
src_amount = 10
src_denom = "basecro"
Expand Down Expand Up @@ -81,41 +82,6 @@ def rly_transfer(ibc):
subprocess.run(cmd, check=True, shell=True)


def get_method_map():
global contract_info
if contract_info is None:
contract_info = json.loads(CONTRACT_ABIS["IRelayerModule"].read_text())
global method_map
if method_map is None:
method_map = {}
for item in contract_info:
event_abi = find_matching_event_abi(contract_info, item["name"])
signature = abi_to_signature(event_abi)
key = f"0x{abi.event_signature_to_log_topic(signature).hex()}"
method_map[key] = signature
return method_map, contract_info


def get_topic_data(w3, log):
method_map, info = get_method_map()
method = method_map[log.topics[0].hex()]
name = method.split("(")[0]
event_abi = find_matching_event_abi(info, name)
event_data = get_event_data(w3.codec, event_abi, log)
return name, event_data.args


def get_logs(w3, start):
end = w3.eth.get_block_number()
return w3.eth.get_logs(
{
"fromBlock": start,
"toBlock": end,
"address": [CONTRACT],
}
)


def coin_received(receiver, amt, denom):
return {
"receiver": receiver,
Expand Down Expand Up @@ -238,7 +204,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(w3, start)
logs = get_logs_since(w3, CONTRACT, start)
relayer0 = ibc.chainmain.cosmos_cli().address("relayer")
relayer = to_checksum_address(bech32_to_eth(relayer0))
cronos_addr = module_address("cronos")
Expand All @@ -253,7 +219,7 @@ def check_balance_change():
write_ack(relayer0, cronos_signer2, src_amount, src_denom),
]
for i, log in enumerate(logs):
method_name, args = get_topic_data(w3, log)
method_name, args = get_topic_data(w3, method_map, contract_info, log)
assert args == AttributeDict(expected[i]), [i, method_name]


Expand All @@ -269,7 +235,7 @@ def test_ibc_incentivized_transfer(ibc):
wait_for_new_blocks(cli, 1)
start = w3.eth.get_block_number()
amount = ibc_incentivized_transfer(ibc)
logs = get_logs(w3, start)
logs = get_logs_since(w3, CONTRACT, start)
fee_denom = "ibcfee"
fee = f"{src_amount}{fee_denom}"
transfer_denom = "transfer/channel-0/basetcro"
Expand All @@ -294,7 +260,7 @@ def test_ibc_incentivized_transfer(ibc):
]
assert len(logs) == len(expected)
for i, log in enumerate(logs):
method_name, args = get_topic_data(w3, log)
method_name, args = get_topic_data(w3, method_map, contract_info, log)
assert args == AttributeDict(expected[i]), [i, method_name]


Expand Down Expand Up @@ -322,13 +288,13 @@ def test_cronos_transfer_source_tokens(ibc):
w3 = ibc.cronos.w3
start = w3.eth.get_block_number()
amount, contract = cronos_transfer_source_tokens(ibc)
logs = get_logs(w3, start)
logs = get_logs_since(w3, CONTRACT, start)
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)
assert len(logs) == len(expected)
for i, log in enumerate(logs):
method_name, args = get_topic_data(w3, log)
method_name, args = get_topic_data(w3, method_map, contract_info, log)
assert args == AttributeDict(expected[i]), [i, method_name]


Expand All @@ -338,11 +304,11 @@ def test_cronos_transfer_source_tokens_with_proxy(ibc):
w3 = ibc.cronos.w3
start = w3.eth.get_block_number()
amount, contract = cronos_transfer_source_tokens_with_proxy(ibc)
logs = get_logs(w3, start)
logs = get_logs_since(w3, CONTRACT, start)
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)
assert len(logs) == len(expected)
for i, log in enumerate(logs):
method_name, args = get_topic_data(w3, log)
method_name, args = get_topic_data(w3, method_map, contract_info, log)
assert args == AttributeDict(expected[i]), [i, method_name]
Loading

0 comments on commit 3313f54

Please sign in to comment.