diff --git a/ci/simple_config.toml b/ci/simple_config.toml index 35be457c28..5012fadfc7 100644 --- a/ci/simple_config.toml +++ b/ci/simple_config.toml @@ -13,7 +13,7 @@ key_name = 'testkey' store_prefix = 'ibc' fee_denom = 'stake' fee_amount = 10 -gas = 200000 +gas = 400000 clock_drift = '5s' trusting_period = '14days' @@ -28,6 +28,6 @@ key_name = 'testkey' store_prefix = 'ibc' fee_denom = 'stake' fee_amount = 10 -gas = 200000 +gas = 400000 clock_drift = '5s' trusting_period = '14days' diff --git a/e2e/e2e/packet.py b/e2e/e2e/packet.py index 7002964075..03ea883ba9 100644 --- a/e2e/e2e/packet.py +++ b/e2e/e2e/packet.py @@ -1,3 +1,5 @@ +from typing import Optional + from .cmd import * from .common import * @@ -27,10 +29,24 @@ class TxPacketSend(Cmd[TxPacketSendRes]): src_chain_id: ChainId src_port: PortId src_channel: ChannelId - timeout_offset: int + amount: int + height_offset: int + number_msgs: Optional[int] def args(self) -> List[str]: - return [self.dst_chain_id, self.src_chain_id, self.src_port, self.src_channel, "9999", str(self.timeout_offset)] + args = [ + self.dst_chain_id, + self.src_chain_id, + self.src_port, + self.src_channel, + str(self.amount), + str(self.height_offset), + ] + + if self.number_msgs != None: + args.extend(['-n', str(self.number_msgs)]) + + return args def process(self, result: Any) -> TxPacketSendRes: entry = find_entry(result, 'SendPacket') @@ -110,15 +126,80 @@ def process(self, result: Any) -> TxPacketAckRes: entry = find_entry(result, 'AcknowledgePacket') return from_dict(TxPacketAckRes, entry) -# ============================================================================= + +# ----------------------------------------------------------------------------- + +@cmd("query packet unreceived-packets") +@dataclass +class QueryUnreceivedPackets(Cmd[List[int]]): + dst_chain_id: ChainId + src_chain_id: ChainId + src_port: PortId + src_channel: ChannelId + + def args(self) -> List[str]: + return [self.dst_chain_id, self.src_chain_id, self.src_port, self.src_channel] + + def process(self, result: Any) -> List[int]: + return from_dict(List[int], result) + + +def query_unreceived_packets( + c: Config, + dst: ChainId, + src: ChainId, + src_port: PortId, + src_channel: ChannelId, +) -> List[int]: + cmd = QueryUnreceivedPackets( + dst_chain_id=dst, src_chain_id=src, src_port=src_port, src_channel=src_channel) + + return cmd.run(c).success() + +# ----------------------------------------------------------------------------- + + +@cmd("query packet unreceived-acks") +@dataclass +class QueryUnreceivedAcks(Cmd[List[int]]): + dst_chain_id: ChainId + src_chain_id: ChainId + src_port: PortId + src_channel: ChannelId + + def args(self) -> List[str]: + return [self.dst_chain_id, self.src_chain_id, self.src_port, self.src_channel] + + def process(self, result: Any) -> List[int]: + return from_dict(List[int], result) + + +def query_unreceived_acks( + c: Config, + dst: ChainId, + src: ChainId, + src_port: PortId, + src_channel: ChannelId, +) -> List[int]: + cmd = QueryUnreceivedAcks( + dst_chain_id=dst, src_chain_id=src, src_port=src_port, src_channel=src_channel) + + return cmd.run(c).success() + + # TRANSFER (packet send) # ============================================================================= -def packet_send(c: Config, src: ChainId, dst: ChainId, src_port: PortId, src_channel: ChannelId, timeout_offset: int) -> Packet: +def packet_send(c: Config, src: ChainId, dst: ChainId, + src_port: PortId, src_channel: ChannelId, + amount: int, height_offset: int, number_msgs: Optional[int] = None) -> Packet: + cmd = TxPacketSend(dst_chain_id=dst, src_chain_id=src, src_port=src_port, src_channel=src_channel, - timeout_offset=timeout_offset) + amount=amount, + number_msgs=number_msgs, + height_offset=height_offset) res = cmd.run(c).success() l.info( @@ -140,7 +221,7 @@ def packet_recv(c: Config, dst: ChainId, src: ChainId, src_port: PortId, src_cha def packet_timeout(c: Config, dst: ChainId, src: ChainId, src_port: PortId, src_channel: ChannelId) -> Packet: cmd = TxPacketTimeout(dst_chain_id=dst, src_chain_id=src, - src_port=src_port, src_channel=src_channel) + src_port=src_port, src_channel=src_channel) res = cmd.run(c).success() l.info( @@ -165,7 +246,8 @@ def ping_pong(c: Config, a_chan: ChannelId, b_chan: ChannelId, port_id: PortId = PortId('transfer')): - pkt_send_a = packet_send(c, side_a, side_b, port_id, a_chan, 1000) + pkt_send_a = packet_send(c, side_a, side_b, port_id, + a_chan, amount=9999, height_offset=1000) split() @@ -186,7 +268,8 @@ def ping_pong(c: Config, split() - pkt_send_b = packet_send(c, side_b, side_a, port_id, b_chan, 1000) + pkt_send_b = packet_send(c, side_b, side_a, port_id, + b_chan, amount=9999, height_offset=1000) split() @@ -206,11 +289,12 @@ def ping_pong(c: Config, def timeout(c: Config, - side_a: ChainId, side_b: ChainId, - a_chan: ChannelId, b_chan: ChannelId, - port_id: PortId = PortId('transfer')): + side_a: ChainId, side_b: ChainId, + a_chan: ChannelId, b_chan: ChannelId, + port_id: PortId = PortId('transfer')): - pkt_send_a = packet_send(c, side_a, side_b, port_id, a_chan, 1) + pkt_send_a = packet_send(c, side_a, side_b, port_id, + a_chan, amount=9999, height_offset=1) split() @@ -222,7 +306,8 @@ def timeout(c: Config, split() - pkt_send_b = packet_send(c, side_b, side_a, port_id, b_chan, 1) + pkt_send_b = packet_send(c, side_b, side_a, port_id, + b_chan, amount=9999, height_offset=1) split() @@ -234,6 +319,7 @@ def timeout(c: Config, split() + def find_entry(result: Any, key: str) -> Any: for entry in result: if key in entry: diff --git a/e2e/e2e/relayer.py b/e2e/e2e/relayer.py new file mode 100644 index 0000000000..e50e0817f6 --- /dev/null +++ b/e2e/e2e/relayer.py @@ -0,0 +1,22 @@ + +from subprocess import Popen +import logging as l +from typing import Optional + +from .cmd import Config +from .common import ChainId, PortId, ChannelId + + +def start(c: Config, src: ChainId, dst: ChainId, src_port: Optional[PortId], src_channel: Optional[ChannelId]) -> Popen: + args = [str(src), str(dst)] + if src_port != None: + args.extend(['-p', str(src_port)]) + if src_channel != None: + args.extend(['-c', str(src_channel)]) + + full_cmd = f'{c.relayer_cmd} -c {c.config_file} --json start'.split(' ') + full_cmd.extend(args) + + l.debug(' '.join(full_cmd)) + + return Popen(full_cmd) diff --git a/e2e/pyrightconfig.json b/e2e/pyrightconfig.json new file mode 100644 index 0000000000..2c63c08510 --- /dev/null +++ b/e2e/pyrightconfig.json @@ -0,0 +1,2 @@ +{ +} diff --git a/e2e/run.py b/e2e/run.py index a86c0882ec..454ad021f4 100755 --- a/e2e/run.py +++ b/e2e/run.py @@ -2,17 +2,128 @@ import argparse import logging as l + from pathlib import Path import e2e.channel as channel import e2e.client as client import e2e.connection as connection import e2e.packet as packet +import e2e.relayer as relayer from e2e.cmd import Config from e2e.common import * -def run(c: Config): +def loop(c: Config): + IBC_0 = ChainId('ibc-0') + IBC_1 = ChainId('ibc-1') + + TRANSFER = PortId('transfer') + IBC_0_CHANNEL = ChannelId('channel-0') + IBC_1_CHANNEL = ChannelId('channel-1') + + # 1. create some unreceived acks + + # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 2 + packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, + src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=2) + + # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 2 + packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, + src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=2) + sleep(5.0) + + # hermes tx raw packet-recv ibc-1 ibc-0 transfer channel-0 + packet.packet_recv(c, src=IBC_0, dst=IBC_1, + src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + # hermes tx raw packet-recv ibc-0 ibc-1 transfer channel-1 + packet.packet_recv(c, src=IBC_1, dst=IBC_0, + src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + + # 2. create some unreceived packets + + # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 + packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, + src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=3) + + # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 4 + packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, + src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=4) + + sleep(5.0) + + # 3. verify the expected number of unreceived packets and acks on each channel end + + # hermes query packet unreceived-packets ibc-0 ibc-1 transfer channel-1 + unreceived = packet.query_unreceived_packets( + c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + + assert (len(unreceived) == 3), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-acks ibc-0 ibc-1 transfer channel-1 + unreceived = packet.query_unreceived_acks( + c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + + assert (len(unreceived) == 2), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-packets ibc-1 ibc-0 transfer channel-0 + unreceived = packet.query_unreceived_packets( + c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + assert (len(unreceived) == 4), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-acks ibc-1 ibc-0 transfer channel-0 + unreceived = packet.query_unreceived_acks( + c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + assert (len(unreceived) == 2), (unreceived, "unreceived packet mismatch") + + # 4. start relaying on the channel - it should clear the unreceived packets + proc = relayer.start(c, src=IBC_0, dst=IBC_1, + src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + # 5. wait a bit and make sure there are no pending packets + + # hermes tx raw ft-transfer ibc-0 ibc-1 transfer channel-1 10000 1000 -n 3 + packet.packet_send(c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, + src_channel=IBC_1_CHANNEL, amount=10000, height_offset=1000, number_msgs=3) + + # hermes tx raw ft-transfer ibc-1 ibc-0 transfer channel-0 10000 1000 -n 4 + packet.packet_send(c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, + src_channel=IBC_0_CHANNEL, amount=10000, height_offset=1000, number_msgs=4) + + sleep(10.0) + + # hermes query packet unreceived-packets ibc-0 ibc-1 transfer channel-1 + unreceived = packet.query_unreceived_packets( + c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + + assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-acks ibc-0 ibc-1 transfer channel-1 + unreceived = packet.query_unreceived_acks( + c, src=IBC_1, dst=IBC_0, src_port=TRANSFER, src_channel=IBC_1_CHANNEL) + + assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-packets ibc-1 ibc-0 transfer channel-0 + unreceived = packet.query_unreceived_packets( + c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") + + # hermes query packet unreceived-acks ibc-1 ibc-0 transfer channel-0 + unreceived = packet.query_unreceived_acks( + c, src=IBC_0, dst=IBC_1, src_port=TRANSFER, src_channel=IBC_0_CHANNEL) + + assert (len(unreceived) == 0), (unreceived, "unreceived packet mismatch") + + # 6. All good, stop the relayer + proc.kill() + + +def raw(c: Config): IBC_0 = ChainId('ibc-0') IBC_1 = ChainId('ibc-1') @@ -43,6 +154,8 @@ def run(c: Config): split() + sleep(5) + packet.timeout(c, IBC_0, IBC_1, ibc0_chan_id, ibc1_chan_id) split() @@ -90,7 +203,8 @@ def main(): format='%(asctime)s [%(levelname)8s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S') - run(config) + raw(config) + loop(config) if __name__ == "__main__":