test: added test for upgradewallet RPC #18774

pull brakmic wants to merge 1 commits into bitcoin:master from brakmic:upgradewallet-tests changing 4 files +165 −1
  1. brakmic commented at 4:18 pm on April 26, 2020: contributor

    This PR adds tests for the newly merged upgradewallet RPC.

    Additionally, it expands test_framework/util.py by adding the function adjust_bitcoin_conf_for_pre_17 to support nodes that don’t parse configuration sections.

    This test uses two older node versions, v0.15.2 and v0.16.3, to create older wallet versions to be used by upgradewallet.

    Fixes https://github.com/bitcoin/bitcoin/issues/18767

  2. in test/functional/wallet_upgradewallet.py:65 in efd6829296 outdated
    49+        ], binary_cli=[
    50+            self.options.bitcoincli,
    51+            releases_path + "/v0.16.3/bin/bitcoin-cli",
    52+        ])
    53+
    54+        self.start_nodes()
    


    MarcoFalke commented at 4:22 pm on April 26, 2020:
    Instead of modifying the test_framwork/util.py, you could just remove the line [regtest] from the bitcoin.conf in the 16.3 datadir before starting the nodes

    brakmic commented at 4:25 pm on April 26, 2020:
    Yes, but wouldn’t be better to make this generally available? For example the comment in feature_backwards_compatibility.py states that it’s not possible to test older nodes.

    MarcoFalke commented at 5:06 pm on April 26, 2020:

    Yes, if you want, you can create a generally available util method like

    0def adjust_bitcoin_conf_for_pre_16_3(conf_file):
    1  ...
    

    brakmic commented at 5:08 pm on April 26, 2020:
    Ok, will implement it. Have just force pushed a change that uses sed to make an in-file replacement.
  3. in test/functional/wallet_upgradewallet.py:55 in 64dd4032fe outdated
    50+        ], binary_cli=[
    51+            self.options.bitcoincli,
    52+            releases_path + "/v0.16.3/bin/bitcoin-cli",
    53+        ])
    54+        # older bitcoind's like v0.16.3 don't recognize config sections
    55+        subprocess.call(["sed","-i", "-e", "s/\[regtest\]/ /g", self.nodes[1].bitcoinconf])
    


    MarcoFalke commented at 5:07 pm on April 26, 2020:
    sed does not exist on windows. I think this is possible entirely in python?

    brakmic commented at 5:09 pm on April 26, 2020:
    Yes, just came to my mind. Windows! I’ll use python’s own regex utils.
  4. DrahtBot added the label Tests on Apr 26, 2020
  5. brakmic commented at 6:34 pm on April 26, 2020: contributor
    @MarcoFalke There are several error messages in travis that I don’t know how to fix. Maybe because the v0.16.3 binaries are missing on test envs?
  6. in test/functional/test_runner.py:183 in af3ff0efdc outdated
    179@@ -180,6 +180,7 @@
    180     'mempool_expiry.py',
    181     'wallet_import_rescan.py',
    182     'wallet_import_with_label.py',
    183+    'wallet_upgradewallet',
    


    MarcoFalke commented at 6:49 pm on April 26, 2020:
    0    'wallet_upgradewallet.py',
    
  7. MarcoFalke commented at 6:49 pm on April 26, 2020: member
    You’ll also need to adjust ci/test/05_before_script.sh
  8. DrahtBot commented at 7:38 pm on April 26, 2020: member

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Conflicts

    No conflicts as of last run.

  9. DrahtBot added the label Needs rebase on Apr 27, 2020
  10. in test/functional/test_framework/util.py:330 in f8049ba065 outdated
    325@@ -326,6 +326,16 @@ def initialize_datadir(dirname, n, chain):
    326         os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
    327     return datadir
    328 
    329+def adjust_bitcoin_conf_for_pre_16_3(conf_file):
    330+    conf = open(conf_file,'r', encoding='utf8')
    


    MarcoFalke commented at 1:20 am on April 27, 2020:
    python with context manager should simplify this

    brakmic commented at 11:11 am on April 27, 2020:
    Have changed it.
  11. in test/functional/wallet_upgradewallet.py:47 in f8049ba065 outdated
    37+
    38+        releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases"
    39+        if not os.path.isdir(releases_path):
    40+            if os.getenv("TEST_PREVIOUS_RELEASES") == "true":
    41+                raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path)
    42+            raise SkipTest("This test requires binaries for previous releases")
    


    MarcoFalke commented at 1:22 am on April 27, 2020:
    Can this be factored out into a def skip_if_no_previous_release(self)? Maybe a future pull?

    brakmic commented at 11:13 am on April 27, 2020:
    I’ve taken this piece of code from feature_backwards_compatibility, so I will later try it out with skip_if_no_previous_release(self).

    brakmic commented at 11:24 am on April 27, 2020:
    I think, I should then also update every test where the above code is currently in use. Will make a separate pull request for that. :)
  12. in test/functional/wallet_upgradewallet.py:88 in f8049ba065 outdated
    70+        node_master.unloadwallet("")
    71+
    72+        # Copy the 0.16.3 wallet to the last Bitcoin Core version and open it:
    73+        shutil.rmtree(node_master_wallets_dir)
    74+        shutil.copytree(
    75+            v16_3_wallets_dir,
    


    MarcoFalke commented at 1:23 am on April 27, 2020:
    don’t you need to shut down first?

    brakmic commented at 11:13 am on April 27, 2020:
    Indeed. The latest variant has it now.
  13. in test/functional/wallet_upgradewallet.py:46 in f8049ba065 outdated
    41+                raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path)
    42+            raise SkipTest("This test requires binaries for previous releases")
    43+
    44+        self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
    45+            None,
    46+            160300
    


    MarcoFalke commented at 1:38 am on April 27, 2020:
    would it be possible to user version 15, so that -usehd=0 can be passed to the wallet?

    brakmic commented at 11:14 am on April 27, 2020:
    Have added a v0.15.2 node, so that we are now testing v0.15.2 with -usehd=0 and v0.16.3 with -usehd=1.

    brakmic commented at 11:18 am on April 27, 2020:
    Btw. there is now a new helper method in util.py called get_nodes_least_version, because the framework couldn’t start the v0.15.2 node. The error was thrown in sync_mempoolsand sync_blocks. It seems to have something to do with the call of syncwithvalidationinterfacequeue. This indirectly affected the getpeerinfofrom sync_blocks, but because 0.15.2 never needed any peers for these particular tests, I thought, maybe a small helper methode for filtering those old nodes would be sufficient. If not, please, let me know what alternatives we have here.
  14. DrahtBot removed the label Needs rebase on Apr 27, 2020
  15. in test/functional/test_framework/util.py:330 in e9a0ea40d4 outdated
    325@@ -326,6 +326,14 @@ def initialize_datadir(dirname, n, chain):
    326         os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
    327     return datadir
    328 
    329+def adjust_bitcoin_conf_for_pre_16_3(conf_file):
    330+    conf_data = ""
    


    MarcoFalke commented at 11:22 am on April 27, 2020:
    This line can be removed, because python’s scopes are more fluid
  16. in test/functional/test_framework/util.py:329 in e9a0ea40d4 outdated
    325@@ -326,6 +326,14 @@ def initialize_datadir(dirname, n, chain):
    326         os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
    327     return datadir
    328 
    329+def adjust_bitcoin_conf_for_pre_16_3(conf_file):
    


    MarcoFalke commented at 11:22 am on April 27, 2020:
    0def adjust_bitcoin_conf_for_pre_17(conf_file):
    

    Sorry, this should say pre 17

  17. in test/functional/test_framework/util.py:419 in e9a0ea40d4 outdated
    415@@ -408,13 +416,22 @@ def sync_blocks(rpc_connections, *, wait=1, timeout=60):
    416         if best_hash.count(best_hash[0]) == len(rpc_connections):
    417             return
    418         # Check that each peer has at least one connection
    419-        assert (all([len(x.getpeerinfo()) for x in rpc_connections]))
    420+        assert (all([len(x.getpeerinfo()) for x in get_nodes_least_version(rpc_connections)]))
    


    MarcoFalke commented at 11:23 am on April 27, 2020:
    I don’t like making sync_all only sync the latest versions. Why is this needed here anyway?

    brakmic commented at 11:31 am on April 27, 2020:
    Because the v0.15.2 node has no peers. But you’re right, if I am not using sync_blocks it should not react at all. In a previous version of upgradewallet test there was a sync_blocks call. Will adapt the code.
  18. in test/functional/test_framework/util.py:436 in e9a0ea40d4 outdated
    442@@ -426,8 +443,8 @@ def sync_mempools(rpc_connections, *, wait=1, timeout=60, flush_scheduler=True):
    443         pool = [set(r.getrawmempool()) for r in rpc_connections]
    444         if pool.count(pool[0]) == len(rpc_connections):
    445             if flush_scheduler:
    446-                for r in rpc_connections:
    447-                    r.syncwithvalidationinterfacequeue()
    448+                for r in get_nodes_least_version(rpc_connections):
    449+                        r.syncwithvalidationinterfacequeue()
    


    MarcoFalke commented at 11:25 am on April 27, 2020:
    I’d rather remove the call to sync_mempools. You can do that by deriving the function that calls it.

    brakmic commented at 11:32 am on April 27, 2020:
    If I only knew, where am I calling sync_mempools. Will have to search a bit.

    brakmic commented at 11:34 am on April 27, 2020:
    I think, it comes indirectly from setup_network. This method also calls sync_ stuff.

    MarcoFalke commented at 11:35 am on April 27, 2020:
    You can override setup_network and provide your own impl
  19. MarcoFalke approved
  20. in test/functional/wallet_upgradewallet.py:83 in 84267045ef outdated
    78+        v16_3_wallets_dir       = os.path.join(v16_3_node.datadir, "regtest/wallets")
    79+        v15_2_wallets_dir       = os.path.join(v15_2_node.datadir, "regtest")
    80+        # stop all nodes
    81+        self.stop_node(0)
    82+        self.stop_node(1)
    83+        self.stop_node(2)
    


    achow101 commented at 10:07 pm on April 28, 2020:
    nit: self.stop_nodes instead of listing each individually?
  21. in test/functional/wallet_upgradewallet.py:93 in 84267045ef outdated
    88+            v16_3_wallets_dir,
    89+            node_master_wallets_dir
    90+        )
    91+        self.restart_node(0, ['-nowallet'])
    92+
    93+        node_master.loadwallet(node_master_wallets_dir)
    


    achow101 commented at 10:10 pm on April 28, 2020:
    Since you’re just loading the default wallet, loadwallet('') should be sufficient.
  22. in test/functional/wallet_upgradewallet.py:79 in 84267045ef outdated
    74+
    75+        self.log.info("Test upgradewallet RPC...")
    76+        # Prepare for copying of the older wallet
    77+        node_master_wallets_dir = os.path.join(node_master.datadir, "regtest/wallets")
    78+        v16_3_wallets_dir       = os.path.join(v16_3_node.datadir, "regtest/wallets")
    79+        v15_2_wallets_dir       = os.path.join(v15_2_node.datadir, "regtest")
    


    achow101 commented at 10:12 pm on April 28, 2020:
    This is the entire datadir and its going to be copying a lot more than just the wallet. Instead of copying the entire walletdir, just give the paths to the specific wallet.dat files?

    brakmic commented at 0:25 am on April 29, 2020:
    Yes, that’s much better. Have adapted the code.
  23. achow101 commented at 10:13 pm on April 28, 2020: member

    We should be be testing the specific version upgrades too, but this is a good place to start with. Those can be added in later.

    ACK 84267045efbfbe2a035e7f34851f1b3bc9964be8

  24. in test/functional/test_framework/util.py:418 in 84267045ef outdated
    421@@ -415,7 +422,6 @@ def sync_blocks(rpc_connections, *, wait=1, timeout=60):
    422         "".join("\n  {!r}".format(b) for b in best_hash),
    423     ))
    424 
    425-
    


    MarcoFalke commented at 10:39 pm on April 28, 2020:
    nit: why remove this line? Seems unrelated and goes against the pep8 rules
  25. in test/functional/test_framework/util.py:333 in 84267045ef outdated
    325@@ -326,6 +326,13 @@ def initialize_datadir(dirname, n, chain):
    326         os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
    327     return datadir
    328 
    329+def adjust_bitcoin_conf_for_pre_17(conf_file):
    330+    with open(conf_file,'r', encoding='utf8') as conf:
    331+        conf_data = conf.read()
    332+    with open(conf_file, 'w+', encoding='utf8') as conf:
    333+        conf_data_changed = re.sub(r'\[regtest\]', ' ', conf_data)
    


    MarcoFalke commented at 10:40 pm on April 28, 2020:
    0        conf_data_changed = conf_data.replace('[regtest]', '')
    

    Should be doable without relying on the regex module

  26. in test/functional/wallet_upgradewallet.py:103 in 84267045ef outdated
    70+        assert_equal(res['blocks'], 101)
    71+        node_master = self.nodes[0]
    72+        v16_3_node  = self.nodes[1]
    73+        v15_2_node  = self.nodes[2]
    74+
    75+        self.log.info("Test upgradewallet RPC...")
    


    MarcoFalke commented at 10:43 pm on April 28, 2020:
    It would be nice to send some coins around, so that we can check the balance doesn’t decrease from upgrading the wallet

    brakmic commented at 0:19 am on April 29, 2020:
    Sadly, this can’t be implemented, because old nodes aren’t connected to node_master. We had this problem with rpc_connections previously when I tried to filter out old nodes. Now, the same problem happens when trying to use sync_ methods.

    brakmic commented at 0:24 am on April 29, 2020:

    More precisely, this is the place where the error gets thrown.

    0 File "/test/functional/test_framework/test_framework.py", line 499, in sync_blocks
    1    sync_blocks(nodes or self.nodes, **kwargs)
    2  File "/test/functional/test_framework/util.py", line 418, in sync_blocks
    3    assert (all([len(x.getpeerinfo()) for x in rpc_connections]))
    

    We have seen this already. So, the question is, do we want to work on “onboarding” of old nodes so their converted wallets can be tested here, or should we rather open a dedicated PR for this?


    MarcoFalke commented at 0:33 am on April 29, 2020:

    So syncing the blockchain is the issue?

    Can be done in a really dumb way:

    0def dumb_sync_blocks(...):
    1 node_from = select node with max height
    2 for i in range(max(blockheight)):
    3  b = node_from.getblock(lbockhash=node_from.getblockhash(i), verbose=0)
    4  for n in nodes:
    5    n.submitblock(b)
    

    brakmic commented at 10:51 am on April 29, 2020:

    Thanks. Have tried it, but the v0.15.2 node doesn’t expand its chain with submitted blocks. Interestingly, in its blockchaininfo the header count gets increased while block count remains at 0. The other node, v0.16.3 is working fine. Here my variant of dumb_sync_blocks

    0def dumb_sync_blocks(self):
    1    node_from = self.nodes[0]
    2    to_height = node_from.getblockheader(node_from.getbestblockhash())['height']
    3    for n in range(1, len(self.nodes)):
    4        height = self.nodes[n].getblockheader(self.nodes[n].getbestblockhash())['height']
    5        for i in range(height, to_height+1):
    6            b = node_from.getblock(blockhash=node_from.getblockhash(i), verbose=0)
    7            self.nodes[n].submitblock(b)
    8        new_height = self.nodes[n].getblockheader(self.nodes[n].getbestblockhash())['height']
    9        print("node: {}, new best height: {}".format(n, new_height))
    

    The output is like this:

    0node: 1, new best height: 101
    1node: 2, new best height: 0
    

    Here their respective blockchaininfo jsons:

    v0.16.3

    0{
    1'chain': 'regtest', 
    2'blocks': 101, 
    3'headers': 101, 
    4'bestblockhash': '1a2f4021b111f20b12071bb68c92dc0037a2237ae034b345b002971dbb9f5e16', }
    

    v0.15.2

    0{
    1'chain': 'regtest', 
    2'blocks': 0, 
    3'headers': 101, 
    4'bestblockhash': '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206' }
    

    In the test code I am sending some coins to both wallets and then calling dumb_sync_blocks to update all chains.

    0node_master.generatetoaddress(101, v16_3_address)
    1self.dumb_sync_blocks()
    

    MarcoFalke commented at 12:01 pm on April 29, 2020:
    Ah, right. regtest was hardforked

    brakmic commented at 12:07 pm on April 29, 2020:
    Ok, then I will be doing balance tests with v0.16.3 only? v0.15.2 can still be used for upgrade tests. Is this acceptable?

    MarcoFalke commented at 12:10 pm on April 29, 2020:

    It might be possible to apply a hack and either:

    • never produce witnesses (use legacy-1-addresses)
    • maybe strip the witness from the blocks before submitting, but I doubt that works because VERIFY_WITNESS should be enforced from genesis, always.

    MarcoFalke commented at 12:11 pm on April 29, 2020:
    You don’t have to do this, I am happy to merge the pull in its current state. Just let me know.

    brakmic commented at 12:15 pm on April 29, 2020:
    Thanks. I think I should try to implement it. If it works, fine. If not, then you can merge the current state. Will come back to you later.

    brakmic commented at 1:28 pm on April 29, 2020:

    Well, I have managed to sync the chains, but there is no way to make proper transactions. I have stolen a few things from p2p_segwit, like build_next_block for manual block generation and syncing:

     0node: 1, new best height: 101
     1node: 2, new best height: 101
     2{
     3'chain': 'regtest', 
     4'blocks': 101, 
     5'headers': 101, 
     6'bestblockhash': '0f2cfae3d63464c070eea6a8305f6f02245e69f41987c186da1c7f8af2bb1547', }
     7{
     8'chain': 'regtest', 
     9'blocks': 101, 
    10'headers': 101, 
    11'bestblockhash': '0f2cfae3d63464c070eea6a8305f6f02245e69f41987c186da1c7f8af2bb1547'}
    

    However, I see no way how to update balance of v0.15.2 as I’d need to build a transaction that would have to have the witness field.

    I will now push the latest changes.

  27. in test/functional/wallet_upgradewallet.py:151 in 84267045ef outdated
    117+        # calling upgradewallet with explicit version number
    118+        # should return nothing if successful
    119+        assert_equal(wallet.upgradewallet(169900), "")
    120+        new_version = wallet.getwalletinfo()["walletversion"]
    121+        # upgraded wallet should have version 169900
    122+        assert_equal(new_version, 169900)
    


    MarcoFalke commented at 10:45 pm on April 28, 2020:
    Is this now an HD wallet? If yes, would be nice to check that the master key hash is present in the wallet info (or something like that)

    brakmic commented at 0:21 am on April 29, 2020:
    Have added appropriate tests.
  28. MarcoFalke approved
  29. MarcoFalke commented at 10:45 pm on April 28, 2020: member

    ACK

    some more suggestions

  30. in test/functional/test_framework/util.py:332 in fa016debd2 outdated
    325@@ -326,6 +326,13 @@ def initialize_datadir(dirname, n, chain):
    326         os.makedirs(os.path.join(datadir, 'stdout'), exist_ok=True)
    327     return datadir
    328 
    329+def adjust_bitcoin_conf_for_pre_17(conf_file):
    330+    with open(conf_file,'r', encoding='utf8') as conf:
    331+        conf_data = conf.read()
    332+    with open(conf_file, 'w+', encoding='utf8') as conf:
    


    MarcoFalke commented at 1:34 pm on April 29, 2020:
    0    with open(conf_file, 'w', encoding='utf8') as conf:
    

    no need for the read flag

  31. in test/functional/wallet_upgradewallet.py:77 in d4fab8820c outdated
    72+        to test version upgrade and master hash key presence.
    73+        v0.16.3 is being used to test version upgrade and balances.
    74+        Further info: https://github.com/bitcoin/bitcoin/pull/18774#discussion_r416967844
    75+        """
    76+        node_from = self.nodes[0]
    77+        to_height = node_from.getblockheader(node_from.getbestblockhash())['height']
    


    MarcoFalke commented at 1:36 pm on April 29, 2020:
    0        to_height = node_from.getblockcount()
    
  32. in test/functional/wallet_upgradewallet.py:79 in d4fab8820c outdated
    74+        Further info: https://github.com/bitcoin/bitcoin/pull/18774#discussion_r416967844
    75+        """
    76+        node_from = self.nodes[0]
    77+        to_height = node_from.getblockheader(node_from.getbestblockhash())['height']
    78+        for n in range(1, len(self.nodes)):
    79+            height = self.nodes[n].getblockheader(self.nodes[n].getbestblockhash())['height']
    


    MarcoFalke commented at 1:37 pm on April 29, 2020:
    0            height = self.nodes[n].getblockcount()
    
  33. in test/functional/wallet_upgradewallet.py:85 in d4fab8820c outdated
    78+        for n in range(1, len(self.nodes)):
    79+            height = self.nodes[n].getblockheader(self.nodes[n].getbestblockhash())['height']
    80+            for i in range(height, to_height+1):
    81+                b = node_from.getblock(blockhash=node_from.getblockhash(i), verbose=0)
    82+                self.nodes[n].submitblock(b)
    83+
    


    MarcoFalke commented at 1:39 pm on April 29, 2020:
    0            assert_equal(self.nodes[n].getblockcount(), to_height)
    

    brakmic commented at 2:06 pm on April 29, 2020:
    Thanks. Btw., have tried to add you as Co-Author, but couldn’t find your email or “no-reply” email.
  34. MarcoFalke approved
  35. test: added test for upgradewallet RPC 66fe7b1a98
  36. MarcoFalke approved
  37. MarcoFalke commented at 2:16 pm on April 29, 2020: member
    ACK. Will be merged as soon as travis is green
  38. MarcoFalke merged this on Apr 29, 2020
  39. MarcoFalke closed this on Apr 29, 2020

  40. brakmic deleted the branch on Apr 29, 2020
  41. MarcoFalke referenced this in commit 3930014abc on May 8, 2020
  42. sidhujag referenced this in commit 52118221d4 on May 12, 2020
  43. DrahtBot locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-09-29 01:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me