Skip to content

Commit

Permalink
Add e2e test for relayer loop (informalsystems#866)
Browse files Browse the repository at this point in the history
* Add e2e test for relayer loop

* Revert ft_transfer rename

* Fix timeout test broken in previous commit

* Make number_msgs parameter optional in packet_send

* Fix the script to pass

* Increase CI gas

* Increase CI gas

Co-authored-by: Anca Zamfir <[email protected]>
  • Loading branch information
romac and ancazamfir authored May 3, 2021
1 parent 2938637 commit 4f85848
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 17 deletions.
4 changes: 2 additions & 2 deletions ci/simple_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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'
112 changes: 99 additions & 13 deletions e2e/e2e/packet.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

from .cmd import *
from .common import *

Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand All @@ -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()

Expand All @@ -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()

Expand All @@ -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()

Expand All @@ -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()

Expand All @@ -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:
Expand Down
22 changes: 22 additions & 0 deletions e2e/e2e/relayer.py
Original file line number Diff line number Diff line change
@@ -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)
2 changes: 2 additions & 0 deletions e2e/pyrightconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
118 changes: 116 additions & 2 deletions e2e/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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__":
Expand Down

0 comments on commit 4f85848

Please sign in to comment.