def test_correct_ping(tmp_path): node1 = Node(config=Config( chain="regtest", data_dir=tmp_path / "node1", p2p_port=get_random_port(), allow_rpc=False, )) node2 = Node(config=Config( chain="regtest", data_dir=tmp_path / "node2", p2p_port=get_random_port(), allow_rpc=False, )) node1.start() node2.start() wait_until(lambda: node1.p2p_manager.is_alive()) wait_until(lambda: node2.p2p_manager.is_alive()) node2.p2p_manager.connect(("0.0.0.0", node1.p2p_port)) wait_until(lambda: len(node1.p2p_manager.connections)) connection = node1.p2p_manager.connections[0] wait_until(lambda: connection.status == P2pConnStatus.Connected) connection = node2.p2p_manager.connections[0] wait_until(lambda: connection.status == P2pConnStatus.Connected) node1.p2p_manager.connections[0].ping_sent = time.time() node1.p2p_manager.connections[0].ping_nonce = 1 node1.p2p_manager.send(Ping(1), 0) wait_until(lambda: node1.p2p_manager.connections[0].latency) node1.stop() node2.stop()
def test_chain_selection(): assert Config(chain="mainnet") == Config(chain=Main()) assert Config(chain="testnet") == Config(chain=TestNet()) assert Config(chain="signet") == Config(chain=SigNet()) assert Config(chain="regtest") == Config(chain=RegTest()) with pytest.raises(ValueError): Config(chain=None) with pytest.raises(ValueError): Config(chain="wrongchain")
def test_init(tmp_path): node = Node( config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=False, allow_rpc=True ) ) node.start() wait_until(lambda: node.rpc_manager.is_alive()) response = json.loads( requests.post( url=f"http://127.0.0.1:{node.rpc_port}", data=json.dumps( { "jsonrpc": "1.0", "id": "pytest", "method": "stop", } ).encode(), headers={"Content-Type": "text/plain"}, ).text ) assert response["result"] == "Btclib node stopping" node.stop()
def test_no_method(tmp_path): node = Node(config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=False, rpc_port=get_random_port(), )) node.start() wait_until(lambda: node.rpc_manager.is_alive()) response = json.loads( requests.post( url=f"http://127.0.0.1:{node.rpc_port}", data=json.dumps({ "jsonrpc": "1.0", "id": "pytest", }).encode(), headers={ "Content-Type": "text/plain" }, ).text) assert response["error"]["message"] == "Invalid request" node.stop()
def test_block_header_last(tmp_path): node = Node(config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=False, rpc_port=get_random_port(), )) node.start() wait_until(lambda: node.rpc_manager.is_alive()) chain = generate_random_header_chain(2000, RegTest().genesis.hash) node.index.add_headers(chain) response = json.loads( requests.post( url=f"http://127.0.0.1:{node.rpc_port}", data=json.dumps({ "jsonrpc": "1.0", "id": "pytest", "method": "getblockheader", "params": [chain[-1].hash], }).encode(), headers={ "Content-Type": "text/plain" }, ).text) assert response["result"]["hash"] == chain[-1].hash assert response["result"]["height"] == 2000 assert response["result"]["previousblockhash"] == chain[-2].hash assert "nextblockhash" not in response["result"] node.stop()
def __init__(self, config=Config()): super().__init__() self.chain = config.chain self.data_dir = config.data_dir self.data_dir.mkdir(exist_ok=True, parents=True) self.terminate_flag = threading.Event() self.logger = Logger(self.data_dir / "history.log", config.debug) self.index = BlockIndex(self.data_dir, self.chain, self.logger) self.chainstate = Chainstate(self.data_dir, self.logger) self.block_db = BlockDB(self.data_dir, self.logger) self.mempool = Mempool() self.status = NodeStatus.Starting self.download_window = [] if config.p2p_port: self.p2p_port = config.p2p_port else: self.p2p_port = None peer_db = PeerDB(self.chain, self.data_dir) self.p2p_manager = P2pManager(self, self.p2p_port, peer_db) if config.rpc_port: self.rpc_port = config.rpc_port else: self.rpc_port = None self.rpc_manager = RpcManager(self, self.rpc_port)
def test_init(tmp_path): node = Node(config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=True, allow_rpc=False)) node.start() wait_until(lambda: node.p2p_manager.is_alive()) node.stop()
def test_get_connection_count(tmp_path): node1 = Node(config=Config( chain="regtest", data_dir=tmp_path / "node1", p2p_port=get_random_port(), rpc_port=get_random_port(), )) node2 = Node(config=Config( chain="regtest", data_dir=tmp_path / "node2", p2p_port=get_random_port(), rpc_port=get_random_port(), )) node1.start() node2.start() wait_until(lambda: node1.rpc_manager.is_alive()) wait_until(lambda: node2.rpc_manager.is_alive()) node2.p2p_manager.connect(("0.0.0.0", node1.p2p_port)) wait_until(lambda: len(node1.p2p_manager.connections)) connection = node1.p2p_manager.connections[0] wait_until(lambda: connection.status == P2pConnStatus.Connected) connection = node2.p2p_manager.connections[0] wait_until(lambda: connection.status == P2pConnStatus.Connected) response = json.loads( requests.post( url=f"http://127.0.0.1:{node1.rpc_port}", data=json.dumps({ "jsonrpc": "1.0", "id": "pytest", "method": "getconnectioncount", }).encode(), headers={ "Content-Type": "text/plain" }, ).text) assert response["result"] == 1 node1.stop() node2.stop()
def test(tmp_path): node = Node( config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=False, allow_rpc=False ) ) node.status = NodeStatus.HeaderSynced length = 2000 * 1 # 2000 chain = generate_random_chain(length, RegTest().genesis.hash) headers = [block.header for block in chain] for x in range(0, length, 2000): node.index.add_headers(headers[x : x + 2000]) for x in node.index.header_dict: block_info = node.index.get_block_info(x) block_info.downloaded = True node.index.insert_block_info(block_info) for block in chain: node.block_db.add_block(block) for x in range(len(chain)): update_chain(node) assert len(node.index.active_chain) == length + 1
def test_port(): assert Config(chain="regtest", p2p_port=1).p2p_port == 1 assert Config(chain="regtest", p2p_port=1, allow_p2p=False).p2p_port != 1 assert Config(chain="regtest", rpc_port=1).rpc_port == 1 assert Config(chain="regtest", rpc_port=1, allow_rpc=False).rpc_port != 1
def test_data_dir(): config = Config(chain="regtest", data_dir="dir") assert config.data_dir != "dir"
def test_download(tmp_path): length = 3000 chain = generate_random_chain(length, RegTest().genesis.hash) headers = [block.header for block in chain] bootstrap_node = Node(config=Config( chain="regtest", data_dir=tmp_path / "node0", p2p_port=get_random_port(), allow_rpc=False, )) bootstrap_node.status = NodeStatus.HeaderSynced for x in range(0, length, 2000): bootstrap_node.index.add_headers(headers[x:x + 2000]) for x in bootstrap_node.index.header_dict: block_info = bootstrap_node.index.get_block_info(x) block_info.downloaded = True bootstrap_node.index.insert_block_info(block_info) for block in chain: bootstrap_node.block_db.add_block(block) for x in range(len(chain)): update_chain(bootstrap_node) assert bootstrap_node.status == NodeStatus.BlockSynced bootstrap_node.start() download_nodes = [bootstrap_node] for x in range(1, 10): shutil.copytree(tmp_path / "node0", tmp_path / f"node{x}") node = Node(config=Config( chain="regtest", data_dir=tmp_path / f"node{x}", p2p_port=get_random_port(), allow_rpc=False, )) node.start() wait_until(lambda: node.p2p_manager.is_alive()) download_nodes.append(node) main_node = Node(config=Config( chain="regtest", data_dir=tmp_path / "main", p2p_port=get_random_port(), allow_rpc=False, )) main_node.start() wait_until(lambda: main_node.p2p_manager.is_alive()) for node in download_nodes: main_node.p2p_manager.connect(("0.0.0.0", node.p2p_port)) time.sleep(0.25) wait_until(lambda: len(main_node.index.active_chain) == length + 1, timeout=20) wait_until(lambda: main_node.status == NodeStatus.BlockSynced, timeout=0.5) main_node.stop() main_node.join() for node in download_nodes: node.stop() node.join()
from btclib_node import Node from btclib_node.config import Config node = Node( config=Config( chain="testnet", data_dir=".btclib", p2p_port=30000, rpc_port=30001, debug=True ) ) node.start()
from btclib_node import Node from btclib_node.config import Config node = Node(config=Config(chain="mainnet", data_dir=".btclib", p2p_port=30000, rpc_port=30001, debug=True)) node.start()
def test_init(tmp_path): node = Node(config=Config( chain="regtest", data_dir=tmp_path, allow_p2p=False, allow_rpc=False)) node.start() node.stop()