diff --git a/tests/floresta-cli/getblockheader.py b/tests/floresta-cli/getblockheader.py index ee9d781db..94b516480 100644 --- a/tests/floresta-cli/getblockheader.py +++ b/tests/floresta-cli/getblockheader.py @@ -1,32 +1,22 @@ """ -floresta_cli_getblockheader.py +getblockheader.py This functional test cli utility to interact with a Floresta node with `getblockheader` """ +import re +import time from test_framework import FlorestaTestFramework -from test_framework.rpc.floresta import REGTEST_RPC_SERVER +DATA_DIR = FlorestaTestFramework.get_integration_test_dir() -class GetBlockheaderHeightZeroTest(FlorestaTestFramework): + +class GetBlockheaderTest(FlorestaTestFramework): """ - Test `getblockheader` with a fresh node and expect a result like this: - - ````bash - $> ./target/release floresta_cli --network=regtest getblockheader \ - 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206 - { - "version": 1, - "prev_blockhash": "0000000000000000000000000000000000000000000000000000000000000000", - "merkle_root": "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", - "time": 1296688602, - "bits": 545259519, - "nonce": 2 - } - ``` + Compare the `getblockheader` command output with a known block header with + the values from utreexod and bitcoind. """ - nodes = [-1] version = 1 blockhash = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" prev_blockhash = "0000000000000000000000000000000000000000000000000000000000000000" @@ -37,35 +27,97 @@ class GetBlockheaderHeightZeroTest(FlorestaTestFramework): def set_test_params(self): """ - Setup a single node + Setup three nodes for the test: florestad, utreexod (miner), + and bitcoind. """ + name = self.__class__.__name__.lower() + self.v2transport = False + self.data_dirs = GetBlockheaderTest.create_data_dirs(DATA_DIR, name, 3) + self.florestad = self.add_node(variant="florestad") + self.utreexod = self.add_node( + variant="utreexod", + extra_args=[ + f"--datadir={self.data_dirs[1]}", + "--miningaddr=bcrt1q4gfcga7jfjmm02zpvrh4ttc5k7lmnq2re52z2y", + "--prune=0", + ], + ) + + self.bitcoind = self.add_node( + variant="bitcoind", extra_args=[f"-datadir={self.data_dirs[2]}"] + ) + def run_test(self): """ - Run JSONRPC and get the header of the genesis block + Run JSONRPC and get the block headers of heights 0 to 1O. """ - # Start node + self.log("=== Starting nodes...") self.run_node(self.florestad) + self.run_node(self.utreexod) + self.run_node(self.bitcoind) - # Test assertions - response = self.florestad.rpc.get_blockheader( - GetBlockheaderHeightZeroTest.blockhash + self.log("=== Mining blocks with utreexod") + self.utreexod.rpc.generate(10) + time.sleep(5) + + self.log("=== Connect floresta to utreexod") + host = self.utreexod.get_host() + port = self.utreexod.get_port("p2p") + self.florestad.rpc.addnode( + f"{host}:{port}", command="onetry", v2transport=False ) - self.assertEqual(response["version"], GetBlockheaderHeightZeroTest.version) - self.assertEqual( - response["prev_blockhash"], GetBlockheaderHeightZeroTest.prev_blockhash + + self.log("=== Waiting for floresta to connect to utreexod...") + time.sleep(5) + peer_info = self.florestad.rpc.get_peerinfo() + self.assertMatch( + peer_info[0]["user_agent"], + re.compile(r"/btcwire:\d+\.\d+\.\d+/utreexod:\d+\.\d+\.\d+/"), ) - self.assertEqual( - response["merkle_root"], GetBlockheaderHeightZeroTest.merkle_root + + self.log("=== Connect bitcoind to utreexod") + self.bitcoind.rpc.addnode(f"{host}:{port}", command="onetry", v2transport=False) + + self.log("=== Waiting for bitcoind to connect to utreexod...") + time.sleep(5) + peer_info = self.bitcoind.rpc.get_peerinfo() + self.assertMatch( + peer_info[0]["subver"], + re.compile(r"/btcwire:\d+\.\d+\.\d+/utreexod:\d+\.\d+\.\d+/"), ) - self.assertEqual(response["time"], GetBlockheaderHeightZeroTest.time) - self.assertEqual(response["bits"], GetBlockheaderHeightZeroTest.bits) - self.assertEqual(response["nonce"], GetBlockheaderHeightZeroTest.nonce) + + self.log("=== Wait for the nodes to sync...") + time.sleep(5) + + self.log("=== Get the tip block") + block_count = self.florestad.rpc.get_block_count() + + for i in range(0, block_count + 1): + self.log(f"=== Get blockhash for height {i}...") + hash = self.florestad.rpc.get_blockhash(i) + + self.log(f"=== Check the correct blockheader for height {i}...") + header_floresta = self.florestad.rpc.get_blockheader(hash) + header_utreexod = self.utreexod.rpc.get_blockheader(hash) + header_bitcoind = self.bitcoind.rpc.get_blockheader(hash) + + for field in ( + "version", + "prev_blockhash", + "merkle_root", + "time", + "bits", + "nonce", + ): + self.log(f"=== Get file {field} for hash {hash}...") + self.assertEqual(header_floresta[field], header_utreexod[field]) + self.assertEqual(header_floresta[field], header_bitcoind[field]) # stop the node self.stop() if __name__ == "__main__": - GetBlockheaderHeightZeroTest().main() + GetBlockheaderTest().main() diff --git a/tests/test_framework/rpc/bitcoin.py b/tests/test_framework/rpc/bitcoin.py index 6d4c5fb51..90da4485d 100644 --- a/tests/test_framework/rpc/bitcoin.py +++ b/tests/test_framework/rpc/bitcoin.py @@ -98,3 +98,16 @@ def addnode(self, node: str, command: str, v2transport: bool = False): raise ValueError(f"Invalid command '{command}'") return self.perform_request("addnode", params=[node, command, v2transport]) + + def get_blockheader(self, block_hash: str) -> dict: + """ + Get the block header for a given block hash by performing + `perform_request('getblockheader', params=[str])` + + Args: + block_hash: The hash of the block to get the header for. + + Returns: + A dictionary containing the block header information. + """ + return self.perform_request("getblockheader", params=[block_hash]) diff --git a/tests/test_framework/rpc/utreexo.py b/tests/test_framework/rpc/utreexo.py index 31304f8fc..7d3a21828 100644 --- a/tests/test_framework/rpc/utreexo.py +++ b/tests/test_framework/rpc/utreexo.py @@ -115,3 +115,16 @@ def get_block_count(self) -> int: Get block count of the node by performing `perform_request('getblockcount') """ return self.perform_request("getblockcount") + + def get_blockheader(self, block_hash: str) -> dict: + """ + Get the block header for a given block hash by performing + `perform_request('getblockheader', params=[str])` + + Args: + block_hash: The hash of the block to get the header for. + + Returns: + A dictionary containing the block header information. + """ + return self.perform_request("getblockheader", params=[block_hash])