wallet_importmulti.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2014-2022 The Limenka 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 the importmulti RPC.
   6  
   7  Test importmulti by generating keys on node0, importing the scriptPubKeys and
   8  addresses on node1 and then testing the address info for the different address
   9  variants.
  10  
  11  - `get_key()` and `get_multisig()` are called to generate keys on node0 and
  12    return the privkeys, pubkeys and all variants of scriptPubKey and address.
  13  - `test_importmulti()` is called to send an importmulti call to node1, test
  14    success, and (if unsuccessful) test the error code and error message returned.
  15  - `test_address()` is called to call getaddressinfo for an address on node1
  16    and test the values returned."""
  17  
  18  from test_framework.blocktools import COINBASE_MATURITY
  19  from test_framework.script import (
  20      CScript,
  21      OP_NOP,
  22  )
  23  from test_framework.test_framework import LimenkaTestFramework
  24  from test_framework.descriptors import descsum_create
  25  from test_framework.util import (
  26      assert_equal,
  27      assert_greater_than,
  28      assert_raises_rpc_error,
  29  )
  30  from test_framework.wallet_util import (
  31      get_key,
  32      get_multisig,
  33      test_address,
  34  )
  35  
  36  
  37  class ImportMultiTest(LimenkaTestFramework):
  38      def add_options(self, parser):
  39          self.add_wallet_options(parser, descriptors=False)
  40  
  41      def set_test_params(self):
  42          self.num_nodes = 2
  43          self.extra_args = [["-addresstype=legacy"], ["-addresstype=legacy"]]
  44          self.setup_clean_chain = True
  45  
  46      def skip_test_if_missing_module(self):
  47          self.skip_if_no_wallet()
  48  
  49      def setup_network(self):
  50          self.setup_nodes()
  51  
  52      def test_importmulti(self, req, success, error_code=None, error_message=None, warnings=None):
  53          """Run importmulti and assert success"""
  54          if warnings is None:
  55              warnings = []
  56          result = self.nodes[1].importmulti([req])
  57          observed_warnings = []
  58          if 'warnings' in result[0]:
  59              observed_warnings = result[0]['warnings']
  60          assert_equal("\n".join(sorted(warnings)), "\n".join(sorted(observed_warnings)))
  61          assert_equal(result[0]['success'], success)
  62          if error_code is not None:
  63              assert_equal(result[0]['error']['code'], error_code)
  64              assert_equal(result[0]['error']['message'], error_message)
  65  
  66      def run_test(self):
  67          self.log.info("Mining blocks...")
  68          self.generate(self.nodes[0], 1, sync_fun=self.no_op)
  69          self.generate(self.nodes[1], 1, sync_fun=self.no_op)
  70          timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
  71  
  72          node0_address1 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())
  73  
  74          # Check only one address
  75          assert_equal(node0_address1['ismine'], True)
  76  
  77          # Node 1 sync test
  78          assert_equal(self.nodes[1].getblockcount(), 1)
  79  
  80          # Address Test - before import
  81          address_info = self.nodes[1].getaddressinfo(node0_address1['address'])
  82          assert_equal(address_info['iswatchonly'], False)
  83          assert_equal(address_info['ismine'], False)
  84  
  85          # RPC importmulti -----------------------------------------------
  86  
  87          # Limenka Address (implicit non-internal)
  88          self.log.info("Should import an address")
  89          key = get_key(self.nodes[0])
  90          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
  91                                 "timestamp": "now"},
  92                                success=True)
  93          test_address(self.nodes[1],
  94                       key.p2pkh_addr,
  95                       iswatchonly=True,
  96                       ismine=False,
  97                       timestamp=timestamp,
  98                       ischange=False)
  99          watchonly_address = key.p2pkh_addr
 100          watchonly_timestamp = timestamp
 101  
 102          self.log.info("Should not import an invalid address")
 103          self.test_importmulti({"scriptPubKey": {"address": "not valid address"},
 104                                 "timestamp": "now"},
 105                                success=False,
 106                                error_code=-5,
 107                                error_message='Invalid address \"not valid address\"')
 108  
 109          # ScriptPubKey + internal
 110          self.log.info("Should import a scriptPubKey with internal flag")
 111          key = get_key(self.nodes[0])
 112          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 113                                 "timestamp": "now",
 114                                 "internal": True},
 115                                success=True)
 116          test_address(self.nodes[1],
 117                       key.p2pkh_addr,
 118                       iswatchonly=True,
 119                       ismine=False,
 120                       timestamp=timestamp,
 121                       ischange=True)
 122  
 123          # ScriptPubKey + internal + label
 124          self.log.info("Should not allow a label to be specified when internal is true")
 125          key = get_key(self.nodes[0])
 126          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 127                                 "timestamp": "now",
 128                                 "internal": True,
 129                                 "label": "Unsuccessful labelling for internal addresses"},
 130                                success=False,
 131                                error_code=-8,
 132                                error_message='Internal addresses should not have a label')
 133  
 134          # Nonstandard scriptPubKey + !internal
 135          self.log.info("Should not import a nonstandard scriptPubKey without internal flag")
 136          nonstandardScriptPubKey = key.p2pkh_script + CScript([OP_NOP]).hex()
 137          key = get_key(self.nodes[0])
 138          self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey,
 139                                 "timestamp": "now"},
 140                                success=False,
 141                                error_code=-8,
 142                                error_message='Internal must be set to true for nonstandard scriptPubKey imports.')
 143          test_address(self.nodes[1],
 144                       key.p2pkh_addr,
 145                       iswatchonly=False,
 146                       ismine=False,
 147                       timestamp=None)
 148  
 149          # Address + Public key + !Internal(explicit)
 150          self.log.info("Should import an address with public key")
 151          key = get_key(self.nodes[0])
 152          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 153                                 "timestamp": "now",
 154                                 "pubkeys": [key.pubkey],
 155                                 "internal": False},
 156                                success=True,
 157                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 158          test_address(self.nodes[1],
 159                       key.p2pkh_addr,
 160                       iswatchonly=True,
 161                       ismine=False,
 162                       timestamp=timestamp)
 163  
 164          # ScriptPubKey + Public key + internal
 165          self.log.info("Should import a scriptPubKey with internal and with public key")
 166          key = get_key(self.nodes[0])
 167          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 168                                 "timestamp": "now",
 169                                 "pubkeys": [key.pubkey],
 170                                 "internal": True},
 171                                success=True,
 172                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 173          test_address(self.nodes[1],
 174                       key.p2pkh_addr,
 175                       iswatchonly=True,
 176                       ismine=False,
 177                       timestamp=timestamp)
 178  
 179          # Nonstandard scriptPubKey + Public key + !internal
 180          self.log.info("Should not import a nonstandard scriptPubKey without internal and with public key")
 181          key = get_key(self.nodes[0])
 182          self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey,
 183                                 "timestamp": "now",
 184                                 "pubkeys": [key.pubkey]},
 185                                success=False,
 186                                error_code=-8,
 187                                error_message='Internal must be set to true for nonstandard scriptPubKey imports.')
 188          test_address(self.nodes[1],
 189                       key.p2pkh_addr,
 190                       iswatchonly=False,
 191                       ismine=False,
 192                       timestamp=None)
 193  
 194          # Address + Private key + !watchonly
 195          self.log.info("Should import an address with private key")
 196          key = get_key(self.nodes[0])
 197          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 198                                 "timestamp": "now",
 199                                 "keys": [key.privkey]},
 200                                success=True)
 201          test_address(self.nodes[1],
 202                       key.p2pkh_addr,
 203                       iswatchonly=False,
 204                       ismine=True,
 205                       timestamp=timestamp)
 206  
 207          self.log.info("Should not import an address with private key if is already imported")
 208          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 209                                 "timestamp": "now",
 210                                 "keys": [key.privkey]},
 211                                success=False,
 212                                error_code=-4,
 213                                error_message='The wallet already contains the private key for this address or script ("' + key.p2pkh_script + '")')
 214  
 215          # Address + Private key + watchonly
 216          self.log.info("Should import an address with private key and with watchonly")
 217          key = get_key(self.nodes[0])
 218          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 219                                 "timestamp": "now",
 220                                 "keys": [key.privkey],
 221                                 "watchonly": True},
 222                                success=True,
 223                                warnings=["All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag."])
 224          test_address(self.nodes[1],
 225                       key.p2pkh_addr,
 226                       iswatchonly=False,
 227                       ismine=True,
 228                       timestamp=timestamp)
 229  
 230          # ScriptPubKey + Private key + internal
 231          self.log.info("Should import a scriptPubKey with internal and with private key")
 232          key = get_key(self.nodes[0])
 233          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 234                                 "timestamp": "now",
 235                                 "keys": [key.privkey],
 236                                 "internal": True},
 237                                success=True)
 238          test_address(self.nodes[1],
 239                       key.p2pkh_addr,
 240                       iswatchonly=False,
 241                       ismine=True,
 242                       timestamp=timestamp)
 243  
 244          # Nonstandard scriptPubKey + Private key + !internal
 245          self.log.info("Should not import a nonstandard scriptPubKey without internal and with private key")
 246          key = get_key(self.nodes[0])
 247          self.test_importmulti({"scriptPubKey": nonstandardScriptPubKey,
 248                                 "timestamp": "now",
 249                                 "keys": [key.privkey]},
 250                                success=False,
 251                                error_code=-8,
 252                                error_message='Internal must be set to true for nonstandard scriptPubKey imports.')
 253          test_address(self.nodes[1],
 254                       key.p2pkh_addr,
 255                       iswatchonly=False,
 256                       ismine=False,
 257                       timestamp=None)
 258  
 259          # P2SH address
 260          multisig = get_multisig(self.nodes[0])
 261          self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=self.no_op)
 262          self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
 263          self.generate(self.nodes[1], 1, sync_fun=self.no_op)
 264          timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
 265  
 266          self.log.info("Should import a p2sh")
 267          self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
 268                                 "timestamp": "now"},
 269                                success=True)
 270          test_address(self.nodes[1],
 271                       multisig.p2sh_addr,
 272                       isscript=True,
 273                       iswatchonly=True,
 274                       timestamp=timestamp)
 275          p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]
 276          assert_equal(p2shunspent['spendable'], False)
 277          assert_equal(p2shunspent['solvable'], False)
 278  
 279          # P2SH + Redeem script
 280          multisig = get_multisig(self.nodes[0])
 281          self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=self.no_op)
 282          self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
 283          self.generate(self.nodes[1], 1, sync_fun=self.no_op)
 284          timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
 285  
 286          self.log.info("Should import a p2sh with respective redeem script")
 287          self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
 288                                 "timestamp": "now",
 289                                 "redeemscript": multisig.redeem_script},
 290                                success=True,
 291                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 292          test_address(self.nodes[1],
 293                       multisig.p2sh_addr, timestamp=timestamp, iswatchonly=True, ismine=False, solvable=True)
 294  
 295          p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]
 296          assert_equal(p2shunspent['spendable'], False)
 297          assert_equal(p2shunspent['solvable'], True)
 298  
 299          # P2SH + Redeem script + Private Keys + !Watchonly
 300          multisig = get_multisig(self.nodes[0])
 301          self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=self.no_op)
 302          self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
 303          self.generate(self.nodes[1], 1, sync_fun=self.no_op)
 304          timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
 305  
 306          self.log.info("Should import a p2sh with respective redeem script and private keys")
 307          self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
 308                                 "timestamp": "now",
 309                                 "redeemscript": multisig.redeem_script,
 310                                 "keys": multisig.privkeys[0:2]},
 311                                success=True,
 312                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 313          test_address(self.nodes[1],
 314                       multisig.p2sh_addr,
 315                       timestamp=timestamp,
 316                       ismine=False,
 317                       iswatchonly=True,
 318                       solvable=True)
 319  
 320          p2shunspent = self.nodes[1].listunspent(0, 999999, [multisig.p2sh_addr])[0]
 321          assert_equal(p2shunspent['spendable'], False)
 322          assert_equal(p2shunspent['solvable'], True)
 323  
 324          # P2SH + Redeem script + Private Keys + Watchonly
 325          multisig = get_multisig(self.nodes[0])
 326          self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=self.no_op)
 327          self.nodes[1].sendtoaddress(multisig.p2sh_addr, 10.00)
 328          self.generate(self.nodes[1], 1, sync_fun=self.no_op)
 329          timestamp = self.nodes[1].getblock(self.nodes[1].getbestblockhash())['mediantime']
 330  
 331          self.log.info("Should import a p2sh with respective redeem script and private keys")
 332          self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_addr},
 333                                 "timestamp": "now",
 334                                 "redeemscript": multisig.redeem_script,
 335                                 "keys": multisig.privkeys[0:2],
 336                                 "watchonly": True},
 337                                success=True)
 338          test_address(self.nodes[1],
 339                       multisig.p2sh_addr,
 340                       iswatchonly=True,
 341                       ismine=False,
 342                       solvable=True,
 343                       timestamp=timestamp)
 344  
 345          # Address + Public key + !Internal + Wrong pubkey
 346          self.log.info("Should not import an address with the wrong public key as non-solvable")
 347          key = get_key(self.nodes[0])
 348          wrong_key = get_key(self.nodes[0]).pubkey
 349          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 350                                 "timestamp": "now",
 351                                 "pubkeys": [wrong_key]},
 352                                success=True,
 353                                warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 354          test_address(self.nodes[1],
 355                       key.p2pkh_addr,
 356                       iswatchonly=True,
 357                       ismine=False,
 358                       solvable=False,
 359                       timestamp=timestamp)
 360  
 361          # ScriptPubKey + Public key + internal + Wrong pubkey
 362          self.log.info("Should import a scriptPubKey with internal and with a wrong public key as non-solvable")
 363          key = get_key(self.nodes[0])
 364          wrong_key = get_key(self.nodes[0]).pubkey
 365          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 366                                 "timestamp": "now",
 367                                 "pubkeys": [wrong_key],
 368                                 "internal": True},
 369                                success=True,
 370                                warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 371          test_address(self.nodes[1],
 372                       key.p2pkh_addr,
 373                       iswatchonly=True,
 374                       ismine=False,
 375                       solvable=False,
 376                       timestamp=timestamp)
 377  
 378          # Address + Private key + !watchonly + Wrong private key
 379          self.log.info("Should import an address with a wrong private key as non-solvable")
 380          key = get_key(self.nodes[0])
 381          wrong_privkey = get_key(self.nodes[0]).privkey
 382          self.test_importmulti({"scriptPubKey": {"address": key.p2pkh_addr},
 383                                 "timestamp": "now",
 384                                 "keys": [wrong_privkey]},
 385                                 success=True,
 386                                 warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 387          test_address(self.nodes[1],
 388                       key.p2pkh_addr,
 389                       iswatchonly=True,
 390                       ismine=False,
 391                       solvable=False,
 392                       timestamp=timestamp)
 393  
 394          # ScriptPubKey + Private key + internal + Wrong private key
 395          self.log.info("Should import a scriptPubKey with internal and with a wrong private key as non-solvable")
 396          key = get_key(self.nodes[0])
 397          wrong_privkey = get_key(self.nodes[0]).privkey
 398          self.test_importmulti({"scriptPubKey": key.p2pkh_script,
 399                                 "timestamp": "now",
 400                                 "keys": [wrong_privkey],
 401                                 "internal": True},
 402                                success=True,
 403                                warnings=["Importing as non-solvable: some required keys are missing. If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.", "Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 404          test_address(self.nodes[1],
 405                       key.p2pkh_addr,
 406                       iswatchonly=True,
 407                       ismine=False,
 408                       solvable=False,
 409                       timestamp=timestamp)
 410  
 411          # Importing existing watch only address with new timestamp should replace saved timestamp.
 412          assert_greater_than(timestamp, watchonly_timestamp)
 413          self.log.info("Should replace previously saved watch only timestamp.")
 414          self.test_importmulti({"scriptPubKey": {"address": watchonly_address},
 415                                 "timestamp": "now"},
 416                                success=True)
 417          test_address(self.nodes[1],
 418                       watchonly_address,
 419                       iswatchonly=True,
 420                       ismine=False,
 421                       timestamp=timestamp)
 422          watchonly_timestamp = timestamp
 423  
 424          # restart nodes to check for proper serialization/deserialization of watch only address
 425          self.stop_nodes()
 426          self.start_nodes()
 427          test_address(self.nodes[1],
 428                       watchonly_address,
 429                       iswatchonly=True,
 430                       ismine=False,
 431                       timestamp=watchonly_timestamp)
 432  
 433          # Bad or missing timestamps
 434          self.log.info("Should throw on invalid or missing timestamp values")
 435          assert_raises_rpc_error(-3, 'Missing required timestamp field for key',
 436                                  self.nodes[1].importmulti, [{"scriptPubKey": key.p2pkh_script}])
 437          assert_raises_rpc_error(-3, 'Expected number or "now" timestamp value for key. got type string',
 438                                  self.nodes[1].importmulti, [{
 439                                      "scriptPubKey": key.p2pkh_script,
 440                                      "timestamp": ""
 441                                  }])
 442  
 443          # Import P2WPKH address as watch only
 444          self.log.info("Should import a P2WPKH address as watch only")
 445          key = get_key(self.nodes[0])
 446          self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr},
 447                                 "timestamp": "now"},
 448                                success=True)
 449          test_address(self.nodes[1],
 450                       key.p2wpkh_addr,
 451                       iswatchonly=True,
 452                       solvable=False)
 453  
 454          # Import P2WPKH address with public key but no private key
 455          self.log.info("Should import a P2WPKH address and public key as solvable but not spendable")
 456          key = get_key(self.nodes[0])
 457          self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr},
 458                                 "timestamp": "now",
 459                                 "pubkeys": [key.pubkey]},
 460                                success=True,
 461                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 462          test_address(self.nodes[1],
 463                       key.p2wpkh_addr,
 464                       ismine=False,
 465                       solvable=True)
 466  
 467          # Import P2WPKH address with key and check it is spendable
 468          self.log.info("Should import a P2WPKH address with key")
 469          key = get_key(self.nodes[0])
 470          self.test_importmulti({"scriptPubKey": {"address": key.p2wpkh_addr},
 471                                 "timestamp": "now",
 472                                 "keys": [key.privkey]},
 473                                success=True)
 474          test_address(self.nodes[1],
 475                       key.p2wpkh_addr,
 476                       iswatchonly=False,
 477                       ismine=True)
 478  
 479          # P2WSH multisig address without scripts or keys
 480          multisig = get_multisig(self.nodes[0])
 481          self.log.info("Should import a p2wsh multisig as watch only without respective redeem script and private keys")
 482          self.test_importmulti({"scriptPubKey": {"address": multisig.p2wsh_addr},
 483                                 "timestamp": "now"},
 484                                success=True)
 485          test_address(self.nodes[1],
 486                       multisig.p2sh_addr,
 487                       solvable=False)
 488  
 489          # Same P2WSH multisig address as above, but now with witnessscript + private keys
 490          self.log.info("Should import a p2wsh with respective witness script and private keys")
 491          self.test_importmulti({"scriptPubKey": {"address": multisig.p2wsh_addr},
 492                                 "timestamp": "now",
 493                                 "witnessscript": multisig.redeem_script,
 494                                 "keys": multisig.privkeys},
 495                                success=True)
 496          test_address(self.nodes[1],
 497                       multisig.p2sh_addr,
 498                       solvable=True,
 499                       ismine=True,
 500                       sigsrequired=2)
 501  
 502          # P2SH-P2WPKH address with no redeemscript or public or private key
 503          key = get_key(self.nodes[0])
 504          self.log.info("Should import a p2sh-p2wpkh without redeem script or keys")
 505          self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr},
 506                                 "timestamp": "now"},
 507                                success=True)
 508          test_address(self.nodes[1],
 509                       key.p2sh_p2wpkh_addr,
 510                       solvable=False,
 511                       ismine=False)
 512  
 513          # P2SH-P2WPKH address + redeemscript + public key with no private key
 514          self.log.info("Should import a p2sh-p2wpkh with respective redeem script and pubkey as solvable")
 515          self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr},
 516                                 "timestamp": "now",
 517                                 "redeemscript": key.p2sh_p2wpkh_redeem_script,
 518                                 "pubkeys": [key.pubkey]},
 519                                success=True,
 520                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 521          test_address(self.nodes[1],
 522                       key.p2sh_p2wpkh_addr,
 523                       solvable=True,
 524                       ismine=False)
 525  
 526          # P2SH-P2WPKH address + redeemscript + private key
 527          key = get_key(self.nodes[0])
 528          self.log.info("Should import a p2sh-p2wpkh with respective redeem script and private keys")
 529          self.test_importmulti({"scriptPubKey": {"address": key.p2sh_p2wpkh_addr},
 530                                 "timestamp": "now",
 531                                 "redeemscript": key.p2sh_p2wpkh_redeem_script,
 532                                 "keys": [key.privkey]},
 533                                success=True)
 534          test_address(self.nodes[1],
 535                       key.p2sh_p2wpkh_addr,
 536                       solvable=True,
 537                       ismine=True)
 538  
 539          # P2SH-P2WSH multisig + redeemscript with no private key
 540          multisig = get_multisig(self.nodes[0])
 541          self.log.info("Should import a p2sh-p2wsh with respective redeem script but no private key")
 542          self.test_importmulti({"scriptPubKey": {"address": multisig.p2sh_p2wsh_addr},
 543                                 "timestamp": "now",
 544                                 "redeemscript": multisig.p2wsh_script,
 545                                 "witnessscript": multisig.redeem_script},
 546                                success=True,
 547                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 548          test_address(self.nodes[1],
 549                       multisig.p2sh_p2wsh_addr,
 550                       solvable=True,
 551                       ismine=False)
 552  
 553          # Test importing of a P2SH-P2WPKH address via descriptor + private key
 554          key = get_key(self.nodes[0])
 555          self.log.info("Should not import a p2sh-p2wpkh address from descriptor without checksum and private key")
 556          self.test_importmulti({"desc": "sh(wpkh(" + key.pubkey + "))",
 557                                 "timestamp": "now",
 558                                 "label": "Unsuccessful P2SH-P2WPKH descriptor import",
 559                                 "keys": [key.privkey]},
 560                                success=False,
 561                                error_code=-5,
 562                                error_message="Missing checksum")
 563  
 564          # Test importing of a P2SH-P2WPKH address via descriptor + private key
 565          key = get_key(self.nodes[0])
 566          p2sh_p2wpkh_label = "Successful P2SH-P2WPKH descriptor import"
 567          self.log.info("Should import a p2sh-p2wpkh address from descriptor and private key")
 568          self.test_importmulti({"desc": descsum_create("sh(wpkh(" + key.pubkey + "))"),
 569                                 "timestamp": "now",
 570                                 "label": p2sh_p2wpkh_label,
 571                                 "keys": [key.privkey]},
 572                                success=True)
 573          test_address(self.nodes[1],
 574                       key.p2sh_p2wpkh_addr,
 575                       solvable=True,
 576                       ismine=True,
 577                       labels=[p2sh_p2wpkh_label])
 578  
 579          # Test ranged descriptor fails if range is not specified
 580          xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
 581          addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1'
 582          addresses += ["bcrt1qrd3n235cj2czsfmsuvqqpr3lu6lg0ju7scl8gn", "bcrt1qfqeppuvj0ww98r6qghmdkj70tv8qpchehegrg8"] # wpkh subscripts corresponding to the above addresses
 583          desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))"
 584          self.log.info("Ranged descriptor import should fail without a specified range")
 585          self.test_importmulti({"desc": descsum_create(desc),
 586                                 "timestamp": "now"},
 587                                success=False,
 588                                error_code=-8,
 589                                error_message='Descriptor is ranged, please specify the range')
 590  
 591          # Test importing of a ranged descriptor with xpriv
 592          self.log.info("Should import the ranged descriptor with specified range as solvable")
 593          self.test_importmulti({"desc": descsum_create(desc),
 594                                 "timestamp": "now",
 595                                 "range": 1},
 596                                success=True)
 597          for address in addresses:
 598              test_address(self.nodes[1],
 599                           address,
 600                           solvable=True,
 601                           ismine=True)
 602  
 603          self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": -1},
 604                                success=False, error_code=-8, error_message='End of range is too high')
 605  
 606          self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]},
 607                                success=False, error_code=-8, error_message='Range should be greater or equal than 0')
 608  
 609          self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]},
 610                                success=False, error_code=-8, error_message='End of range is too high')
 611  
 612          self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]},
 613                                success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end')
 614  
 615          self.test_importmulti({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]},
 616                                success=False, error_code=-8, error_message='Range is too large')
 617  
 618          # Test importing a descriptor containing a WIF private key
 619          wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh"
 620          address = "2MuhcG52uHPknxDgmGPsV18jSHFBnnRgjPg"
 621          desc = "sh(wpkh(" + wif_priv + "))"
 622          self.log.info("Should import a descriptor with a WIF private key as spendable")
 623          self.test_importmulti({"desc": descsum_create(desc),
 624                                 "timestamp": "now"},
 625                                success=True)
 626          test_address(self.nodes[1],
 627                       address,
 628                       solvable=True,
 629                       ismine=True)
 630  
 631          # dump the private key to ensure it matches what was imported
 632          privkey = self.nodes[1].dumpprivkey(address)
 633          assert_equal(privkey, wif_priv)
 634  
 635          # Test importing of a P2PKH address via descriptor
 636          key = get_key(self.nodes[0])
 637          p2pkh_label = "P2PKH descriptor import"
 638          self.log.info("Should import a p2pkh address from descriptor")
 639          self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"),
 640                                 "timestamp": "now",
 641                                 "label": p2pkh_label},
 642                                True,
 643                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 644          test_address(self.nodes[1],
 645                       key.p2pkh_addr,
 646                       solvable=True,
 647                       ismine=False,
 648                       labels=[p2pkh_label])
 649  
 650          # Test import fails if both desc and scriptPubKey are provided
 651          key = get_key(self.nodes[0])
 652          self.log.info("Import should fail if both scriptPubKey and desc are provided")
 653          self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"),
 654                                 "scriptPubKey": {"address": key.p2pkh_addr},
 655                                 "timestamp": "now"},
 656                                success=False,
 657                                error_code=-8,
 658                                error_message='Both a descriptor and a scriptPubKey should not be provided.')
 659  
 660          # Test import fails if neither desc nor scriptPubKey are present
 661          key = get_key(self.nodes[0])
 662          self.log.info("Import should fail if neither a descriptor nor a scriptPubKey are provided")
 663          self.test_importmulti({"timestamp": "now"},
 664                                success=False,
 665                                error_code=-8,
 666                                error_message='Either a descriptor or scriptPubKey must be provided.')
 667  
 668          # Test importing of a multisig via descriptor
 669          key1 = get_key(self.nodes[0])
 670          key2 = get_key(self.nodes[0])
 671          self.log.info("Should import a 1-of-2 bare multisig from descriptor")
 672          self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"),
 673                                 "timestamp": "now"},
 674                                success=True,
 675                                warnings=["Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag."])
 676          self.log.info("Should not treat individual keys from the imported bare multisig as watchonly")
 677          test_address(self.nodes[1],
 678                       key1.p2pkh_addr,
 679                       ismine=False,
 680                       iswatchonly=False)
 681  
 682          # Import pubkeys with key origin info
 683          self.log.info("Addresses should have hd keypath and master key id after import with key origin")
 684          pub_addr = self.nodes[1].getnewaddress()
 685          pub_addr = self.nodes[1].getnewaddress(address_type="bech32")
 686          info = self.nodes[1].getaddressinfo(pub_addr)
 687          pub = info['pubkey']
 688          pub_keypath = info['hdkeypath']
 689          pub_fpr = info['hdmasterfingerprint']
 690          result = self.nodes[0].importmulti(
 691              [{
 692                  'desc' : descsum_create("wpkh([" + pub_fpr + pub_keypath[1:] +"]" + pub + ")"),
 693                  "timestamp": "now",
 694              }]
 695          )
 696          assert result[0]['success']
 697          pub_import_info = self.nodes[0].getaddressinfo(pub_addr)
 698          assert_equal(pub_import_info['hdmasterfingerprint'], pub_fpr)
 699          assert_equal(pub_import_info['pubkey'], pub)
 700          assert_equal(pub_import_info['hdkeypath'], pub_keypath)
 701  
 702          # Import privkeys with key origin info
 703          priv_addr = self.nodes[1].getnewaddress(address_type="bech32")
 704          info = self.nodes[1].getaddressinfo(priv_addr)
 705          priv = self.nodes[1].dumpprivkey(priv_addr)
 706          priv_keypath = info['hdkeypath']
 707          priv_fpr = info['hdmasterfingerprint']
 708          result = self.nodes[0].importmulti(
 709              [{
 710                  'desc' : descsum_create("wpkh([" + priv_fpr + priv_keypath[1:] + "]" + priv + ")"),
 711                  "timestamp": "now",
 712              }]
 713          )
 714          assert result[0]['success']
 715          priv_import_info = self.nodes[0].getaddressinfo(priv_addr)
 716          assert_equal(priv_import_info['hdmasterfingerprint'], priv_fpr)
 717          assert_equal(priv_import_info['hdkeypath'], priv_keypath)
 718  
 719          # Make sure the key origin info are still there after a restart
 720          self.stop_nodes()
 721          self.start_nodes()
 722          import_info = self.nodes[0].getaddressinfo(pub_addr)
 723          assert_equal(import_info['hdmasterfingerprint'], pub_fpr)
 724          assert_equal(import_info['hdkeypath'], pub_keypath)
 725          import_info = self.nodes[0].getaddressinfo(priv_addr)
 726          assert_equal(import_info['hdmasterfingerprint'], priv_fpr)
 727          assert_equal(import_info['hdkeypath'], priv_keypath)
 728  
 729          # Check legacy import does not import key origin info
 730          self.log.info("Legacy imports don't have key origin info")
 731          pub_addr = self.nodes[1].getnewaddress()
 732          info = self.nodes[1].getaddressinfo(pub_addr)
 733          pub = info['pubkey']
 734          result = self.nodes[0].importmulti(
 735              [{
 736                  'scriptPubKey': {'address': pub_addr},
 737                  'pubkeys': [pub],
 738                  "timestamp": "now",
 739              }]
 740          )
 741          assert result[0]['success']
 742          pub_import_info = self.nodes[0].getaddressinfo(pub_addr)
 743          assert_equal(pub_import_info['pubkey'], pub)
 744          assert 'hdmasterfingerprint' not in pub_import_info
 745          assert 'hdkeypath' not in pub_import_info
 746  
 747          # Bech32m addresses and descriptors cannot be imported
 748          self.log.info("Bech32m addresses and descriptors cannot be imported")
 749          self.test_importmulti(
 750              {
 751                  "scriptPubKey": {"address": "bcrt1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqc8gma6"},
 752                  "timestamp": "now",
 753              },
 754              success=False,
 755              error_code=-5,
 756              error_message="Bech32m addresses cannot be imported into legacy wallets",
 757          )
 758          self.test_importmulti(
 759              {
 760                  "desc": descsum_create("tr({})".format(pub)),
 761                  "timestamp": "now",
 762              },
 763              success=False,
 764              error_code=-5,
 765              error_message="Bech32m descriptors cannot be imported into legacy wallets",
 766          )
 767  
 768          # Import some public keys to the keypool of a no privkey wallet
 769          self.log.info("Adding pubkey to keypool of disableprivkey wallet")
 770          self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True)
 771          wrpc = self.nodes[1].get_wallet_rpc("noprivkeys")
 772  
 773          addr1 = self.nodes[0].getnewaddress(address_type="bech32")
 774          addr2 = self.nodes[0].getnewaddress(address_type="bech32")
 775          pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
 776          pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
 777          result = wrpc.importmulti(
 778              [{
 779                  'desc': descsum_create('wpkh(' + pub1 + ')'),
 780                  'keypool': True,
 781                  "timestamp": "now",
 782              },
 783              {
 784                  'desc': descsum_create('wpkh(' + pub2 + ')'),
 785                  'keypool': True,
 786                  "timestamp": "now",
 787              }]
 788          )
 789          assert result[0]['success']
 790          assert result[1]['success']
 791          assert_equal(wrpc.getwalletinfo()["keypoolsize"], 2)
 792          newaddr1 = wrpc.getnewaddress(address_type="bech32")
 793          assert_equal(addr1, newaddr1)
 794          newaddr2 = wrpc.getnewaddress(address_type="bech32")
 795          assert_equal(addr2, newaddr2)
 796  
 797          # Import some public keys to the internal keypool of a no privkey wallet
 798          self.log.info("Adding pubkey to internal keypool of disableprivkey wallet")
 799          addr1 = self.nodes[0].getnewaddress(address_type="bech32")
 800          addr2 = self.nodes[0].getnewaddress(address_type="bech32")
 801          pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
 802          pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
 803          result = wrpc.importmulti(
 804              [{
 805                  'desc': descsum_create('wpkh(' + pub1 + ')'),
 806                  'keypool': True,
 807                  'internal': True,
 808                  "timestamp": "now",
 809              },
 810              {
 811                  'desc': descsum_create('wpkh(' + pub2 + ')'),
 812                  'keypool': True,
 813                  'internal': True,
 814                  "timestamp": "now",
 815              }]
 816          )
 817          assert result[0]['success']
 818          assert result[1]['success']
 819          assert_equal(wrpc.getwalletinfo()["keypoolsize_hd_internal"], 2)
 820          newaddr1 = wrpc.getrawchangeaddress(address_type="bech32")
 821          assert_equal(addr1, newaddr1)
 822          newaddr2 = wrpc.getrawchangeaddress(address_type="bech32")
 823          assert_equal(addr2, newaddr2)
 824  
 825          # Import a multisig and make sure the keys don't go into the keypool
 826          self.log.info('Imported scripts with pubkeys should not have their pubkeys go into the keypool')
 827          addr1 = self.nodes[0].getnewaddress(address_type="bech32")
 828          addr2 = self.nodes[0].getnewaddress(address_type="bech32")
 829          pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
 830          pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
 831          result = wrpc.importmulti(
 832              [{
 833                  'desc': descsum_create('wsh(multi(2,' + pub1 + ',' + pub2 + '))'),
 834                  'keypool': True,
 835                  "timestamp": "now",
 836              }]
 837          )
 838          assert result[0]['success']
 839          assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0)
 840  
 841          # Cannot import those pubkeys to keypool of wallet with privkeys
 842          self.log.info("Pubkeys cannot be added to the keypool of a wallet with private keys")
 843          wrpc = self.nodes[1].get_wallet_rpc(self.default_wallet_name)
 844          assert wrpc.getwalletinfo()['private_keys_enabled']
 845          result = wrpc.importmulti(
 846              [{
 847                  'desc': descsum_create('wpkh(' + pub1 + ')'),
 848                  'keypool': True,
 849                  "timestamp": "now",
 850              }]
 851          )
 852          assert_equal(result[0]['error']['code'], -8)
 853          assert_equal(result[0]['error']['message'], "Keys can only be imported to the keypool when private keys are disabled")
 854  
 855          # Make sure ranged imports import keys in order
 856          self.log.info('Key ranges should be imported in order')
 857          wrpc = self.nodes[1].get_wallet_rpc("noprivkeys")
 858          assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0)
 859          assert_equal(wrpc.getwalletinfo()["private_keys_enabled"], False)
 860          xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY"
 861          addresses = [
 862              'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv', # m/0'/0'/0
 863              'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8', # m/0'/0'/1
 864              'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu', # m/0'/0'/2
 865              'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640', # m/0'/0'/3
 866              'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0', # m/0'/0'/4
 867          ]
 868          result = wrpc.importmulti(
 869              [{
 870                  'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'),
 871                  'keypool': True,
 872                  'timestamp': 'now',
 873                  'range' : [0, 4],
 874              }]
 875          )
 876          for i in range(0, 5):
 877              addr = wrpc.getnewaddress('', 'bech32')
 878              assert_equal(addr, addresses[i])
 879  
 880          # Create wallet with passphrase
 881          self.log.info('Test watchonly imports on a wallet with a passphrase, without unlocking')
 882          self.nodes[1].createwallet(wallet_name='w1', blank=True, passphrase='pass')
 883          wrpc = self.nodes[1].get_wallet_rpc('w1')
 884          assert_raises_rpc_error(-13, "Please enter the wallet passphrase with walletpassphrase first.",
 885                                  wrpc.importmulti, [{
 886                                      'desc': descsum_create('wpkh(' + pub1 + ')'),
 887                                      "timestamp": "now",
 888                                  }])
 889  
 890          result = wrpc.importmulti(
 891              [{
 892                  'desc': descsum_create('wpkh(' + pub1 + ')'),
 893                  "timestamp": "now",
 894                  "watchonly": True,
 895              }]
 896          )
 897          assert result[0]['success']
 898  
 899          self.log.info("Multipath descriptors")
 900          self.nodes[1].createwallet(wallet_name="multipath", blank=True, disable_private_keys=True)
 901          w_multipath = self.nodes[1].get_wallet_rpc("multipath")
 902          self.nodes[1].createwallet(wallet_name="multipath_split", blank=True, disable_private_keys=True)
 903          w_multisplit = self.nodes[1].get_wallet_rpc("multipath_split")
 904  
 905          res = w_multipath.importmulti([{"desc": descsum_create(f"wpkh({xpub}/<10;20>/0/*)"),
 906                                "keypool": True,
 907                                "range": 10,
 908                                "timestamp": "now",
 909                                "internal": True}])
 910          assert_equal(res[0]["success"], False)
 911          assert_equal(res[0]["error"]["code"], -5)
 912          assert_equal(res[0]["error"]["message"], "Cannot have multipath descriptor while also specifying 'internal'")
 913  
 914          res = w_multipath.importmulti([{"desc": descsum_create(f"wpkh({xpub}/<10;20>/0/*)"),
 915                                "keypool": True,
 916                                "range": 10,
 917                                "timestamp": "now"}])
 918          assert_equal(res[0]["success"], True)
 919  
 920          res = w_multisplit.importmulti([{"desc": descsum_create(f"wpkh({xpub}/10/0/*)"),
 921                                "keypool": True,
 922                                "range": 10,
 923                                "timestamp": "now"}])
 924          assert_equal(res[0]["success"], True)
 925          res = w_multisplit.importmulti([{"desc": descsum_create(f"wpkh({xpub}/20/0/*)"),
 926                                "keypool": True,
 927                                "range": 10,
 928                                "internal": True,
 929                                "timestamp": timestamp}])
 930          assert_equal(res[0]["success"], True)
 931  
 932          for _ in range(0, 9):
 933              assert_equal(w_multipath.getnewaddress(address_type="bech32"), w_multisplit.getnewaddress(address_type="bech32"))
 934              assert_equal(w_multipath.getrawchangeaddress(address_type="bech32"), w_multisplit.getrawchangeaddress(address_type="bech32"))
 935  
 936  
 937  if __name__ == '__main__':
 938      ImportMultiTest(__file__).main()
 939