wallet_startup.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2017-present The Bitcoin Core developers
   3  # Distributed under the MIT software license, see the accompanying
   4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  """Test wallet load on startup.
   6  
   7  Verify that a bitcoind node can maintain list of wallets loading on startup
   8  """
   9  import os
  10  import shutil
  11  import stat
  12  import uuid
  13  
  14  
  15  from test_framework.test_framework import BitcoinTestFramework
  16  from test_framework.util import (
  17      assert_equal,
  18      assert_raises_rpc_error,
  19      is_dir_writable,
  20  )
  21  
  22  
  23  class WalletStartupTest(BitcoinTestFramework):
  24      def set_test_params(self):
  25          self.setup_clean_chain = True
  26          self.num_nodes = 1
  27  
  28      def skip_test_if_missing_module(self):
  29          self.skip_if_no_wallet()
  30  
  31      def setup_nodes(self):
  32          self.add_nodes(self.num_nodes)
  33          self.start_nodes()
  34  
  35      def create_unnamed_wallet(self, **kwargs):
  36          """
  37          createwallet disallows empty wallet names, so create a temporary named wallet
  38          and move its wallet.dat to the unnamed wallet location
  39          """
  40          wallet_name = uuid.uuid4().hex
  41          self.nodes[0].createwallet(wallet_name=wallet_name, **kwargs)
  42          self.nodes[0].unloadwallet(wallet_name)
  43          shutil.move(self.nodes[0].wallets_path / wallet_name / "wallet.dat", self.nodes[0].wallets_path / "wallet.dat")
  44          (self.nodes[0].wallets_path / wallet_name).rmdir()
  45  
  46      def test_load_unwritable_wallet(self, node):
  47          self.log.info("Test wallet load failure due to non-writable directory")
  48          wallet_name = "bad_permissions"
  49  
  50          node.createwallet(wallet_name)
  51          node.unloadwallet(wallet_name)
  52  
  53          dir_path = node.wallets_path / wallet_name
  54          original_dir_perms = dir_path.stat().st_mode
  55          os.chmod(dir_path, original_dir_perms & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH))
  56  
  57          if is_dir_writable(dir_path):
  58              self.log.warning("Skipping load non-writable directory test: unable to enforce read-only permissions")
  59          else:
  60              # Ensure we don't load a wallet located in a non-writable directory.
  61              # The node will crash later on if we cannot write to disk.
  62              assert_raises_rpc_error(-4, f"SQLiteDatabase: Failed to open database in directory '{str(dir_path)}': directory is not writable", node.loadwallet, wallet_name)
  63  
  64          # Reset directory permissions for cleanup
  65          dir_path.chmod(original_dir_perms)
  66  
  67      def run_test(self):
  68          self.log.info('Should start without any wallets')
  69          assert_equal(self.nodes[0].listwallets(), [])
  70          assert_equal(self.nodes[0].listwalletdir(), {'wallets': []})
  71  
  72          self.log.info('New default wallet should load by default when there are no other wallets')
  73          self.create_unnamed_wallet(load_on_startup=False)
  74          self.restart_node(0)
  75          assert_equal(self.nodes[0].listwallets(), [''])
  76  
  77          self.log.info('Test load on startup behavior')
  78          self.nodes[0].createwallet(wallet_name='w0', load_on_startup=True)
  79          self.nodes[0].createwallet(wallet_name='w1', load_on_startup=False)
  80          self.nodes[0].createwallet(wallet_name='w2', load_on_startup=True)
  81          self.nodes[0].createwallet(wallet_name='w3', load_on_startup=False)
  82          self.nodes[0].createwallet(wallet_name='w4', load_on_startup=False)
  83          self.nodes[0].unloadwallet(wallet_name='w0', load_on_startup=False)
  84          self.nodes[0].unloadwallet(wallet_name='w4', load_on_startup=False)
  85          self.nodes[0].loadwallet(filename='w4', load_on_startup=True)
  86          assert_equal(set(self.nodes[0].listwallets()), set(('', 'w1', 'w2', 'w3', 'w4')))
  87          self.restart_node(0)
  88          assert_equal(set(self.nodes[0].listwallets()), set(('', 'w2', 'w4')))
  89          self.nodes[0].unloadwallet(wallet_name='', load_on_startup=False)
  90          self.nodes[0].unloadwallet(wallet_name='w4', load_on_startup=False)
  91          self.nodes[0].loadwallet(filename='w3', load_on_startup=True)
  92          self.nodes[0].loadwallet(filename='')
  93          self.restart_node(0)
  94          assert_equal(set(self.nodes[0].listwallets()), set(('w2', 'w3')))
  95  
  96          self.test_load_unwritable_wallet(self.nodes[0])
  97  
  98  if __name__ == '__main__':
  99      WalletStartupTest(__file__).main()
 100