Skip to content

Commit 73fc2bc

Browse files
committed
new p2p interface scenario
1 parent 9cefd65 commit 73fc2bc

File tree

2 files changed

+86
-5
lines changed

2 files changed

+86
-5
lines changed

test/data/scenario_p2p_interface.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
from collections import defaultdict
3+
from time import sleep
4+
5+
from test_framework.messages import CInv, msg_getdata
6+
from test_framework.p2p import P2PInterface
7+
from warnet.test_framework_bridge import WarnetTestFramework
8+
9+
10+
def cli_help():
11+
return "Run P2P GETDATA test"
12+
13+
14+
class P2PStoreBlock(P2PInterface):
15+
def __init__(self):
16+
super().__init__()
17+
self.blocks = defaultdict(int)
18+
19+
def on_block(self, message):
20+
message.block.calc_sha256()
21+
self.blocks[message.block.sha256] += 1
22+
23+
24+
class GetdataTest(WarnetTestFramework):
25+
def set_test_params(self):
26+
self.num_nodes = 1
27+
28+
def run_test(self):
29+
while not self.warnet.network_connected():
30+
self.log.info("Waiting for complete network connection...")
31+
sleep(5)
32+
self.log.info("Network connected")
33+
34+
self.log.info("Adding the p2p connection")
35+
36+
p2p_block_store = self.nodes[0].add_p2p_connection(
37+
P2PStoreBlock(), dstaddr=self.warnet.tanks[0].ipv4, dstport=18444
38+
)
39+
40+
self.log.info("test that an invalid GETDATA doesn't prevent processing of future messages")
41+
42+
# Send invalid message and verify that node responds to later ping
43+
invalid_getdata = msg_getdata()
44+
invalid_getdata.inv.append(CInv(t=0, h=0)) # INV type 0 is invalid.
45+
p2p_block_store.send_and_ping(invalid_getdata)
46+
47+
# Check getdata still works by fetching tip block
48+
best_block = int(self.nodes[0].getbestblockhash(), 16)
49+
good_getdata = msg_getdata()
50+
good_getdata.inv.append(CInv(t=2, h=best_block))
51+
p2p_block_store.send_and_ping(good_getdata)
52+
p2p_block_store.wait_until(lambda: p2p_block_store.blocks[best_block] == 1)
53+
54+
55+
if __name__ == "__main__":
56+
GetdataTest().main()

test/scenarios_test.py

+30-5
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ def setup_network(self):
2626

2727
def test_scenarios(self):
2828
self.check_available_scenarios()
29-
self.run_and_check_scenario("miner_std")
30-
self.run_and_check_scenario_from_file("src/warnet/scenarios/miner_std.py")
29+
self.run_and_check_miner_scenario("miner_std")
30+
self.run_and_check_miner_scenario_from_file("src/warnet/scenarios/miner_std.py")
31+
self.run_and_check_scenario_from_file("test/data/scenario_p2p_interface.py")
3132

3233
def check_available_scenarios(self):
3334
self.log.info("Checking available scenarios")
@@ -42,22 +43,46 @@ def scenario_running(self, scenario_name: str):
4243
running = scenario_name in active[0]["cmd"]
4344
return running and len(active) == 1
4445

45-
def run_and_check_scenario(self, scenario_name):
46+
def run_and_check_scenario_from_file(self, scenario_file):
47+
scenario_name = self.get_scenario_name_from_path(scenario_file)
48+
49+
def check_scenario_clean_exit():
50+
running = self.rpc("scenarios_list_running")
51+
scenarios = [s for s in running if s["cmd"].strip() == scenario_name]
52+
if not scenarios:
53+
return False
54+
scenario = scenarios[0]
55+
if scenario["active"]:
56+
return False
57+
if scenario["return_code"] != 0:
58+
raise Exception(
59+
f"Scenario {scenario_name} failed with return code {scenario['return_code']}"
60+
)
61+
return True
62+
63+
self.log.info(f"Running scenario: {scenario_name}")
64+
self.warcli(f"scenarios run-file {scenario_file}")
65+
self.wait_for_predicate(lambda: check_scenario_clean_exit())
66+
67+
def run_and_check_miner_scenario(self, scenario_name):
4668
self.log.info(f"Running scenario: {scenario_name}")
4769
self.warcli(f"scenarios run {scenario_name} --allnodes --interval=1")
4870
self.wait_for_predicate(lambda: self.scenario_running(scenario_name))
4971
self.wait_for_predicate(lambda: self.check_blocks(30))
5072
self.stop_scenario()
5173

52-
def run_and_check_scenario_from_file(self, scenario_file):
74+
def run_and_check_miner_scenario_from_file(self, scenario_file):
5375
self.log.info(f"Running scenario from file: {scenario_file}")
5476
self.warcli(f"scenarios run-file {scenario_file} --allnodes --interval=1")
5577
start = int(self.warcli("bitcoin rpc 0 getblockcount"))
56-
scenario_name = os.path.splitext(os.path.basename(scenario_file))[0]
78+
scenario_name = self.get_scenario_name_from_path(scenario_file)
5779
self.wait_for_predicate(lambda: self.scenario_running(scenario_name))
5880
self.wait_for_predicate(lambda: self.check_blocks(2, start=start))
5981
self.stop_scenario()
6082

83+
def get_scenario_name_from_path(self, scenario_file):
84+
return os.path.splitext(os.path.basename(scenario_file))[0]
85+
6186
def check_blocks(self, target_blocks, start: int = 0):
6287
running = self.rpc("scenarios_list_running")
6388
assert len(running) == 1, f"Expected one running scenario, got {len(running)}"

0 commit comments

Comments
 (0)