Skip to content

Commit 36d3268

Browse files
authored
Problem: no negative test for state check (#1254)
* Problem: no negative test for state check * only allow status update once
1 parent 95da881 commit 36d3268

File tree

5 files changed

+62
-28
lines changed

5 files changed

+62
-28
lines changed

integration_tests/contracts/contracts/TestICA.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ contract TestICA {
1111
address constant module_address = 0x89A7EF2F08B1c018D5Cc88836249b84Dd5392905;
1212
uint64 lastSeq;
1313
enum Status {
14-
NONE,
14+
PENDING,
1515
SUCCESS,
1616
FAIL
1717
}
@@ -78,9 +78,10 @@ contract TestICA {
7878
);
7979
}
8080

81-
function callSubmitMsgs(string memory connectionID, bytes memory data, uint256 timeout) public returns (uint64) {
81+
function callSubmitMsgs(string memory connectionID, string calldata packetSrcChannel, bytes memory data, uint256 timeout) public returns (uint64) {
8282
require(account == msg.sender, "not authorized");
8383
lastSeq = ica.submitMsgs(connectionID, data, timeout);
84+
statusMap[packetSrcChannel][lastSeq] = Status.PENDING;
8485
return lastSeq;
8586
}
8687

@@ -109,6 +110,11 @@ contract TestICA {
109110
function onPacketResultCallback(string calldata packetSrcChannel, uint64 seq, bool ack) external payable returns (bool) {
110111
// To prevent called by arbitrary user
111112
require(msg.sender == module_address);
113+
Status currentStatus = statusMap[packetSrcChannel][seq];
114+
if (currentStatus != Status.PENDING) {
115+
return true;
116+
}
117+
delete statusMap[packetSrcChannel][seq];
112118
Status status = Status.FAIL;
113119
if (ack) {
114120
status = Status.SUCCESS;

integration_tests/cosmoscli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ def icaauth_submit_tx(self, connid, tx, timeout_duration="1h", **kwargs):
12721272
rsp = self.event_query_tx_for(rsp["txhash"])
12731273
return rsp
12741274

1275-
def ica_ctrl_send_tx(self, connid, tx, **kwargs):
1275+
def ica_ctrl_send_tx(self, connid, tx, timeout_in_ns=None, **kwargs):
12761276
default_kwargs = {
12771277
"home": self.data_dir,
12781278
"node": self.node_rpc,
@@ -1287,6 +1287,8 @@ def ica_ctrl_send_tx(self, connid, tx, **kwargs):
12871287
"send-tx",
12881288
connid,
12891289
tx,
1290+
"--relative-packet-timeout" if timeout_in_ns else None,
1291+
timeout_in_ns if timeout_in_ns else None,
12901292
"-y",
12911293
**(default_kwargs | kwargs),
12921294
)

integration_tests/ibc_utils.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import json
33
import subprocess
44
from contextlib import contextmanager
5+
from enum import IntEnum
56
from pathlib import Path
67
from typing import NamedTuple
78

@@ -25,6 +26,10 @@
2526
RATIO = 10**10
2627

2728

29+
class Status(IntEnum):
30+
PENDING, SUCCESS, FAIL = range(3)
31+
32+
2833
class IBCNetwork(NamedTuple):
2934
cronos: Cronos
3035
chainmain: Chainmain
@@ -622,6 +627,24 @@ def check_tx():
622627
assert raised
623628

624629

630+
def wait_for_status_change(tcontract, channel_id, seq, timeout=None):
631+
print(f"wait for status change for {seq}")
632+
633+
def check_status():
634+
status = tcontract.caller.getStatus(channel_id, seq)
635+
return status
636+
637+
if timeout is None:
638+
wait_for_fn("current status", check_status)
639+
else:
640+
try:
641+
print(f"should assert timeout err when pass {timeout}s")
642+
wait_for_fn("current status", check_status, timeout=timeout)
643+
except TimeoutError:
644+
raised = True
645+
assert raised
646+
647+
625648
def register_acc(cli, connid):
626649
print("register ica account")
627650
rsp = cli.icaauth_register_account(

integration_tests/test_ica.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from pystarport import cluster
55

66
from .ibc_utils import (
7+
Status,
78
deploy_contract,
89
funds_ica,
910
gen_send_msg,
@@ -12,6 +13,7 @@
1213
register_acc,
1314
wait_for_check_channel_ready,
1415
wait_for_check_tx,
16+
wait_for_status_change,
1517
)
1618
from .utils import CONTRACTS, wait_for_fn
1719

@@ -42,6 +44,8 @@ def test_ica(ibc, tmp_path):
4244
jsonfile = CONTRACTS["TestICA"]
4345
tcontract = deploy_contract(ibc.cronos.w3, jsonfile)
4446
memo = {"src_callback": {"address": tcontract.address}}
47+
timeout_in_ns = 6000000000
48+
seq = 1
4549

4650
def generated_tx_packet(msg_num):
4751
# generate a transaction to send to host chain
@@ -60,16 +64,22 @@ def send_tx(msg_num, gas="200000"):
6064
rsp = cli_controller.ica_ctrl_send_tx(
6165
connid,
6266
generated_tx,
67+
timeout_in_ns,
6368
gas=gas,
6469
from_="signer2",
6570
)
6671
assert rsp["code"] == 0, rsp["raw_log"]
72+
events = parse_events_rpc(rsp["events"])
73+
assert int(events.get("send_packet")["packet_sequence"]) == seq
6774
wait_for_check_tx(cli_host, ica_address, num_txs)
6875

6976
msg_num = 10
77+
assert tcontract.caller.getStatus(channel_id, seq) == Status.PENDING
7078
send_tx(msg_num)
7179
balance -= amount * msg_num
7280
assert cli_host.balance(ica_address, denom=denom) == balance
81+
wait_for_status_change(tcontract, channel_id, seq, timeout_in_ns / 1e9)
82+
assert tcontract.caller.getStatus(channel_id, seq) == Status.PENDING
7383

7484
def check_for_ack():
7585
criteria = "message.action=/ibc.core.channel.v1.MsgAcknowledgement"

integration_tests/test_ica_precompile.py

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import base64
22
import json
3-
from enum import IntEnum
43

54
import pytest
65
from eth_utils import keccak
76
from pystarport import cluster
87
from web3.datastructures import AttributeDict
98

109
from .ibc_utils import (
10+
Status,
1111
funds_ica,
1212
gen_send_msg,
1313
get_next_channel,
1414
prepare_network,
1515
wait_for_check_channel_ready,
1616
wait_for_check_tx,
17+
wait_for_status_change,
1718
)
1819
from .utils import (
1920
ADDRS,
@@ -35,10 +36,6 @@
3536
amt = 1000
3637

3738

38-
class Status(IntEnum):
39-
NONE, SUCCESS, FAIL = range(3)
40-
41-
4239
@pytest.fixture(scope="module")
4340
def ibc(request, tmp_path_factory):
4441
"prepare-network"
@@ -76,11 +73,12 @@ def submit_msgs(
7673
add_delegate,
7774
expected_seq,
7875
event,
76+
channel_id,
7977
timeout=no_timeout,
8078
amount=amt,
8179
need_wait=True,
8280
msg_num=2,
83-
channel_id="",
81+
with_channel_id=True,
8482
):
8583
cli_host = ibc.chainmain.cosmos_cli()
8684
cli_controller = ibc.cronos.cosmos_cli()
@@ -110,7 +108,10 @@ def submit_msgs(
110108
num_txs = len(cli_host.query_all_txs(ica_address)["txs"])
111109
str = base64.b64decode(generated_packet["data"])
112110
# submit transaction on host chain on behalf of interchain account
113-
tx = func(connid, str, timeout).build_transaction(data)
111+
if with_channel_id:
112+
tx = func(connid, channel_id, str, timeout).build_transaction(data)
113+
else:
114+
tx = func(connid, str, timeout).build_transaction(data)
114115
receipt = send_transaction(w3, tx, keys)
115116
assert receipt.status == 1
116117
if timeout < no_timeout:
@@ -160,7 +161,8 @@ def test_call(ibc):
160161
False,
161162
expected_seq,
162163
contract.events.SubmitMsgsResult,
163-
channel_id=channel_id,
164+
channel_id,
165+
with_channel_id=False,
164166
)
165167
balance -= diff
166168
assert cli_host.balance(ica_address, denom=denom) == balance
@@ -173,22 +175,13 @@ def test_call(ibc):
173175
True,
174176
expected_seq,
175177
contract.events.SubmitMsgsResult,
176-
channel_id=channel_id,
178+
channel_id,
179+
with_channel_id=False,
177180
)
178181
balance -= diff
179182
assert cli_host.balance(ica_address, denom=denom) == balance
180183

181184

182-
def wait_for_status_change(tcontract, channel_id, seq):
183-
print(f"wait for status change for {seq}")
184-
185-
def check_status():
186-
status = tcontract.caller.getStatus(channel_id, seq)
187-
return status
188-
189-
wait_for_fn("current status", check_status)
190-
191-
192185
def wait_for_packet_log(start, event, channel_id, seq, status):
193186
print("wait for log arrive", seq, status)
194187
expected = AttributeDict(
@@ -218,7 +211,7 @@ def test_sc_call(ibc):
218211
name = "signer2"
219212
signer = ADDRS[name]
220213
keys = KEYS[name]
221-
default_gas = 400000
214+
default_gas = 500000
222215
data = {"from": signer, "gas": default_gas}
223216
channel_id = get_next_channel(cli_controller, connid)
224217
ica_address = register_acc(
@@ -270,7 +263,7 @@ def submit_msgs_ro(func, str):
270263
False,
271264
expected_seq,
272265
contract.events.SubmitMsgsResult,
273-
channel_id=channel_id,
266+
channel_id,
274267
)
275268
submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str)
276269
submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str)
@@ -293,7 +286,7 @@ def submit_msgs_ro(func, str):
293286
True,
294287
expected_seq,
295288
contract.events.SubmitMsgsResult,
296-
channel_id=channel_id,
289+
channel_id,
297290
)
298291
submit_msgs_ro(tcontract.functions.delegateSubmitMsgs, str)
299292
submit_msgs_ro(tcontract.functions.staticSubmitMsgs, str)
@@ -317,9 +310,9 @@ def submit_msgs_ro(func, str):
317310
False,
318311
expected_seq,
319312
contract.events.SubmitMsgsResult,
313+
channel_id,
320314
amount=100000001,
321315
need_wait=False,
322-
channel_id=channel_id,
323316
)
324317
last_seq = tcontract.caller.getLastSeq()
325318
wait_for_status_change(tcontract, channel_id, last_seq)
@@ -342,9 +335,9 @@ def submit_msgs_ro(func, str):
342335
False,
343336
expected_seq,
344337
contract.events.SubmitMsgsResult,
338+
channel_id,
345339
timeout,
346340
msg_num=100,
347-
channel_id=channel_id,
348341
)
349342
last_seq = tcontract.caller.getLastSeq()
350343
wait_for_status_change(tcontract, channel_id, last_seq)
@@ -377,7 +370,7 @@ def submit_msgs_ro(func, str):
377370
False,
378371
expected_seq,
379372
contract.events.SubmitMsgsResult,
380-
channel_id=channel_id2,
373+
channel_id2,
381374
)
382375
last_seq = tcontract.caller.getLastSeq()
383376
wait_for_status_change(tcontract, channel_id2, last_seq)

0 commit comments

Comments
 (0)