Skip to content

Commit

Permalink
Problem: ibc channel upgrade related methods are not supported (#1612)
Browse files Browse the repository at this point in the history
* Problem: ibc channel upgrade related methods are not supported

* upgrade ica
  • Loading branch information
mmsqe authored Sep 30, 2024
1 parent 3d3cfed commit 1226cce
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* [#1600](https://github.com/crypto-org-chain/cronos/pull/1600) Update ethermint to avoid unnecessary block result in header related api call.
* [#1606](https://github.com/crypto-org-chain/cronos/pull/1606) Fix pebbledb support.
* [#1610](https://github.com/crypto-org-chain/cronos/pull/1610) Sync e2ee module with v1.3.x branch.
* [#1612](https://github.com/crypto-org-chain/cronos/pull/1612) Support ibc channel upgrade related methods.

### Bug Fixes

Expand Down
44 changes: 41 additions & 3 deletions integration_tests/cosmoscli.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from dateutil.parser import isoparse
from pystarport.utils import build_cli_args_safe, format_doc_string, interact

from .utils import get_sync_info
from .utils import CRONOS_ADDRESS_PREFIX, get_sync_info

# the default initial base fee used by integration tests
DEFAULT_GAS_PRICE = "100000000000basetcro"
Expand All @@ -34,14 +34,14 @@ class ModuleAccount(enum.Enum):
@format_doc_string(
options=",".join(v.value for v in ModuleAccount.__members__.values())
)
def module_address(name):
def module_address(name, prefix=CRONOS_ADDRESS_PREFIX):
"""
get address of module accounts
:param name: name of module account, values: {options}
"""
data = hashlib.sha256(ModuleAccount(name).value.encode()).digest()[:20]
return bech32.bech32_encode("cro", bech32.convertbits(data, 8, 5))
return bech32.bech32_encode(prefix, bech32.convertbits(data, 8, 5))


class ChainCommand:
Expand Down Expand Up @@ -1238,6 +1238,27 @@ def ibc_recover_client(self, proposal, **kwargs):
rsp = self.event_query_tx_for(rsp["txhash"])
return rsp

def ibc_upgrade_channels(self, version, from_addr, **kwargs):
kwargs.setdefault("gas_prices", DEFAULT_GAS_PRICE)
kwargs.setdefault("gas", 600000)
return json.loads(
self.raw(
"tx",
"ibc",
"channel",
"upgrade-channels",
json.dumps(version),
"-y",
"--json",
from_=from_addr,
keyring_backend="test",
chain_id=self.chain_id,
home=self.data_dir,
stderr=subprocess.DEVNULL,
**kwargs,
)
)

def submit_gov_proposal(self, proposal, **kwargs):
default_kwargs = self.get_default_kwargs()
kwargs.setdefault("broadcast_mode", "sync")
Expand Down Expand Up @@ -1428,6 +1449,23 @@ def ibc_query_channels(self, connid, **kwargs):
)
)

def ibc_query_channel(self, port_id, channel_id, **kwargs):
default_kwargs = {
"node": self.node_rpc,
"output": "json",
}
return json.loads(
self.raw(
"q",
"ibc",
"channel",
"end",
port_id,
channel_id,
**(default_kwargs | kwargs),
)
)

def ibc_query_ack(self, port_id, channel_id, packet_seq, **kwargs):
default_kwargs = {
"node": self.node_rpc,
Expand Down
29 changes: 15 additions & 14 deletions integration_tests/ibc_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,7 @@ def prepare_network(
call_rly_cmd(path, connection_only, version)

if incentivized:
# register fee payee
src_chain = cronos.cosmos_cli()
dst_chain = chainmain.cosmos_cli()
rsp = dst_chain.register_counterparty_payee(
"transfer",
"channel-0",
dst_chain.address("relayer"),
src_chain.address("signer1"),
from_="relayer",
fees="100000000basecro",
)
assert rsp["code"] == 0, rsp["raw_log"]
register_fee_payee(cronos.cosmos_cli(), chainmain.cosmos_cli())

port = None
if is_relay:
Expand All @@ -226,6 +215,18 @@ def prepare_network(
wait_for_port(port)


def register_fee_payee(src_chain, dst_chain):
rsp = dst_chain.register_counterparty_payee(
"transfer",
"channel-0",
dst_chain.address("relayer"),
src_chain.address("signer1"),
from_="relayer",
fees="100000000basecro",
)
assert rsp["code"] == 0, rsp["raw_log"]


def assert_ready(ibc):
# wait for hermes
output = subprocess.getoutput(
Expand Down Expand Up @@ -772,7 +773,7 @@ def register_acc(cli, connid, ordering=ChannelOrder.ORDERED.value, signer="signe
version=v,
ordering=ordering,
)
_, channel_id = assert_channel_open_init(rsp)
port_id, channel_id = assert_channel_open_init(rsp)
wait_for_check_channel_ready(cli, connid, channel_id)

print("query ica account")
Expand All @@ -781,7 +782,7 @@ def register_acc(cli, connid, ordering=ChannelOrder.ORDERED.value, signer="signe
cli.address(signer),
)["address"]
print("ica address", ica_address, "channel_id", channel_id)
return ica_address, channel_id
return ica_address, port_id, channel_id


def funds_ica(cli, adr, signer="signer2"):
Expand Down
41 changes: 38 additions & 3 deletions integration_tests/test_ibc.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import json

import pytest

from .cosmoscli import module_address
from .ibc_utils import (
RATIO,
assert_ready,
Expand All @@ -10,10 +13,13 @@
ibc_incentivized_transfer,
ibc_transfer,
prepare_network,
register_fee_payee,
wait_for_check_channel_ready,
)
from .utils import (
ADDRS,
CONTRACTS,
approve_proposal,
deploy_contract,
parse_events_rpc,
send_transaction,
Expand Down Expand Up @@ -58,10 +64,39 @@ def test_ibc_transfer(ibc):
assert not dup, f"duplicate {dup} in {event['type']}"


def test_ibc_incentivized_transfer(ibc):
def test_ibc_incentivized_transfer(ibc, tmp_path):
if not ibc.incentivized:
# this test case only works for incentivized channel.
return
# upgrade to incentivized
src_chain = ibc.cronos.cosmos_cli()
dst_chain = ibc.chainmain.cosmos_cli()
version = {"fee_version": "ics29-1", "app_version": "ics20-1"}
community = "community"
authority = module_address("gov")
connid = "connection-0"
channel_id = "channel-0"
deposit = "1basetcro"
proposal_src = src_chain.ibc_upgrade_channels(
version,
community,
deposit=deposit,
title="channel-upgrade-title",
summary="summary",
port_pattern="transfer",
channel_ids=channel_id,
)
proposal_src["deposit"] = deposit
proposal_src["proposer"] = authority
proposal_src["messages"][0]["signer"] = authority
proposal = tmp_path / "proposal.json"
proposal.write_text(json.dumps(proposal_src))
rsp = src_chain.submit_gov_proposal(proposal, from_=community)
assert rsp["code"] == 0, rsp["raw_log"]
approve_proposal(ibc.cronos, rsp["events"])
wait_for_check_channel_ready(
src_chain, connid, channel_id, "STATE_FLUSHCOMPLETE"
)
wait_for_check_channel_ready(src_chain, connid, channel_id)
register_fee_payee(src_chain, dst_chain)
ibc_incentivized_transfer(ibc)


Expand Down
45 changes: 41 additions & 4 deletions integration_tests/test_ica.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from pystarport import cluster

from .cosmoscli import module_address
from .ibc_utils import (
ChannelOrder,
Status,
Expand All @@ -17,7 +18,7 @@
wait_for_check_tx,
wait_for_status_change,
)
from .utils import CONTRACTS, wait_for_fn
from .utils import CONTRACTS, approve_proposal, wait_for_fn

pytestmark = pytest.mark.ica

Expand All @@ -39,12 +40,12 @@ def ibc(request, tmp_path_factory):
@pytest.mark.parametrize(
"order", [ChannelOrder.ORDERED.value, ChannelOrder.UNORDERED.value]
)
def test_ica(ibc, order):
def test_ica(ibc, order, tmp_path):
signer = "signer2" if order == ChannelOrder.ORDERED.value else "community"
connid = "connection-0"
cli_host = ibc.chainmain.cosmos_cli()
cli_controller = ibc.cronos.cosmos_cli()
ica_address, channel_id = register_acc(
ica_address, _, channel_id = register_acc(
cli_controller, connid, ordering=order, signer=signer
)
balance = funds_ica(cli_host, ica_address, signer=signer)
Expand Down Expand Up @@ -118,9 +119,45 @@ def submit_msgs(msg_num, timeout_in_s=no_timeout, gas="200000"):
else:
wait_for_check_channel_ready(cli_controller, connid, channel_id, "STATE_CLOSED")
# reopen ica account after channel get closed
ica_address2, channel_id2 = register_acc(cli_controller, connid)
ica_address2, port_id2, channel_id2 = register_acc(cli_controller, connid)
assert ica_address2 == ica_address, ica_address2
assert channel_id2 != channel_id, channel_id2
# upgrade to unordered channel
channel = cli_controller.ibc_query_channel(port_id2, channel_id2)
version_data = json.loads(channel["channel"]["version"])
community = "community"
authority = module_address("gov")
deposit = "1basetcro"
proposal_src = cli_controller.ibc_upgrade_channels(
json.loads(version_data["app_version"]),
community,
deposit=deposit,
title="channel-upgrade-title",
summary="summary",
port_pattern=port_id2,
channel_ids=channel_id2,
)
proposal_src["deposit"] = deposit
proposal_src["proposer"] = authority
proposal_src["messages"][0]["signer"] = authority
proposal_src["messages"][0]["fields"]["ordering"] = ChannelOrder.UNORDERED.value
proposal = tmp_path / "proposal.json"
proposal.write_text(json.dumps(proposal_src))
rsp = cli_controller.submit_gov_proposal(proposal, from_=community)
assert rsp["code"] == 0, rsp["raw_log"]
approve_proposal(ibc.cronos, rsp["events"])
wait_for_check_channel_ready(
cli_controller, connid, channel_id2, "STATE_FLUSHCOMPLETE"
)
wait_for_check_channel_ready(cli_controller, connid, channel_id2)
# submit large txs to trigger close channel with small timeout for order channel
msg_num = 140
submit_msgs(msg_num, 0.005, "600000")
assert cli_host.balance(ica_address, denom=denom) == balance
with pytest.raises(AssertionError) as exc:
register_acc(cli_controller, connid)
assert "existing active channel" in str(exc.value)

# submit normal txs should work
msg_num = 2
submit_msgs(msg_num)
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/test_ica_incentivized.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def test_incentivized(ibc):
connid = "connection-0"
cli_host = ibc.chainmain.cosmos_cli()
cli_controller = ibc.cronos.cosmos_cli()
ica_address, channel_id = register_acc(cli_controller, connid)
ica_address, _, channel_id = register_acc(cli_controller, connid)
relayer = cli_controller.address("signer1")
balance = funds_ica(cli_host, ica_address)
ibc.cronos.supervisorctl("stop", "relayer-demo")
Expand Down
45 changes: 45 additions & 0 deletions x/cronos/middleware/conversion_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
cronoskeeper "github.com/crypto-org-chain/cronos/v2/x/cronos/keeper"
)

var _ porttypes.UpgradableModule = (*IBCConversionModule)(nil)

// IBCConversionModule implements the ICS26 interface.
type IBCConversionModule struct {
app porttypes.IBCModule
Expand Down Expand Up @@ -228,3 +230,46 @@ func (im IBCConversionModule) getIbcDenomFromPacketAndData(
denomTrace := transferTypes.ParseDenomTrace(prefixedDenom)
return denomTrace.IBCDenom()
}

// OnChanUpgradeInit implements the IBCModule interface
func (im IBCConversionModule) OnChanUpgradeInit(
ctx sdk.Context,
portID string,
channelID string,
proposedOrder channeltypes.Order,
proposedConnectionHops []string,
proposedVersion string,
) (string, error) {
cbs, ok := im.app.(porttypes.UpgradableModule)
if !ok {
return "", errors.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")
}
return cbs.OnChanUpgradeInit(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion)
}

// OnChanUpgradeAck implements the IBCModule interface
func (im IBCConversionModule) OnChanUpgradeAck(ctx sdk.Context, portID, channelID, counterpartyVersion string) error {
cbs, ok := im.app.(porttypes.UpgradableModule)
if !ok {
return errors.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")
}
return cbs.OnChanUpgradeAck(ctx, portID, channelID, counterpartyVersion)
}

// OnChanUpgradeOpen implements the IBCModule interface
func (im IBCConversionModule) OnChanUpgradeOpen(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, proposedVersion string) {
cbs, ok := im.app.(porttypes.UpgradableModule)
if !ok {
panic(errors.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack"))
}
cbs.OnChanUpgradeOpen(ctx, portID, channelID, proposedOrder, proposedConnectionHops, proposedVersion)
}

// OnChanUpgradeTry implement s the IBCModule interface
func (im IBCConversionModule) OnChanUpgradeTry(ctx sdk.Context, portID, channelID string, proposedOrder channeltypes.Order, proposedConnectionHops []string, counterpartyVersion string) (string, error) {
cbs, ok := im.app.(porttypes.UpgradableModule)
if !ok {
return "", errors.Wrap(porttypes.ErrInvalidRoute, "upgrade route not found to module in application callstack")
}
return cbs.OnChanUpgradeTry(ctx, portID, channelID, proposedOrder, proposedConnectionHops, counterpartyVersion)
}

0 comments on commit 1226cce

Please sign in to comment.