aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wallet/rpcdump.cpp77
-rw-r--r--src/wallet/rpcwallet.cpp13
-rw-r--r--src/wallet/wallet.cpp49
-rw-r--r--src/wallet/wallet.h2
-rwxr-xr-xtest/functional/wallet_createwallet.py16
-rwxr-xr-xtest/functional/wallet_importmulti.py113
6 files changed, 202 insertions, 68 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 5ceba39704..930274f8a1 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -967,7 +967,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
}
}
-static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data)
+static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
{
UniValue warnings(UniValue::VARR);
@@ -1038,6 +1038,7 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
}
pubkey_map.emplace(pubkey.GetID(), pubkey);
+ ordered_pubkeys.push_back(pubkey.GetID());
}
for (size_t i = 0; i < keys.size(); ++i) {
const auto& str = keys[i].get_str();
@@ -1110,7 +1111,7 @@ static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CP
return warnings;
}
-static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data)
+static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
{
UniValue warnings(UniValue::VARR);
@@ -1144,22 +1145,25 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
- FlatSigningProvider out_keys;
-
// Expand all descriptors to get public keys and scripts.
// TODO: get private keys from descriptors too
for (int i = range_start; i <= range_end; ++i) {
+ FlatSigningProvider out_keys;
std::vector<CScript> scripts_temp;
parsed_desc->Expand(i, keys, scripts_temp, out_keys);
std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
- }
+ for (const auto& key_pair : out_keys.pubkeys) {
+ ordered_pubkeys.push_back(key_pair.first);
+ }
+
+ for (const auto& x : out_keys.scripts) {
+ import_data.import_scripts.emplace(x.second);
+ }
- for (const auto& x : out_keys.scripts) {
- import_data.import_scripts.emplace(x.second);
+ std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
+ import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
}
- std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
- import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
for (size_t i = 0; i < priv_keys.size(); ++i) {
const auto& str = priv_keys[i].get_str();
CKey key = DecodeSecret(str);
@@ -1207,19 +1211,26 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
}
const std::string& label = data.exists("label") ? data["label"].get_str() : "";
+ const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
+
+ // Add to keypool only works with privkeys disabled
+ if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled");
+ }
ImportData import_data;
std::map<CKeyID, CPubKey> pubkey_map;
std::map<CKeyID, CKey> privkey_map;
std::set<CScript> script_pub_keys;
+ std::vector<CKeyID> ordered_pubkeys;
bool have_solving_data;
if (data.exists("scriptPubKey") && data.exists("desc")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided.");
} else if (data.exists("scriptPubKey")) {
- warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data);
+ warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
} else if (data.exists("desc")) {
- warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data);
+ warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided.");
}
@@ -1241,25 +1252,28 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
for (const auto& entry : import_data.import_scripts) {
if (!pwallet->HaveCScript(CScriptID(entry)) && !pwallet->AddCScript(entry)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
+ }
+ }
+ for (const auto& entry : privkey_map) {
+ const CKey& key = entry.second;
+ CPubKey pubkey = key.GetPubKey();
+ const CKeyID& id = entry.first;
+ assert(key.VerifyPubKey(pubkey));
+ pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
+ // If the private key is not present in the wallet, insert it.
+ if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
+ }
+ pwallet->UpdateTimeFirstKey(timestamp);
+ }
+ for (const CKeyID& id : ordered_pubkeys) {
+ auto entry = pubkey_map.find(id);
+ if (entry == pubkey_map.end()) {
+ continue;
}
- }
- for (const auto& entry : privkey_map) {
- const CKey& key = entry.second;
- CPubKey pubkey = key.GetPubKey();
- const CKeyID& id = entry.first;
- assert(key.VerifyPubKey(pubkey));
- pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
- // If the private key is not present in the wallet, insert it.
- if (!pwallet->HaveKey(id) && !pwallet->AddKeyPubKey(key, pubkey)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
- }
- pwallet->UpdateTimeFirstKey(timestamp);
- }
- for (const auto& entry : pubkey_map) {
- const CPubKey& pubkey = entry.second;
- const CKeyID& id = entry.first;
- CPubKey temp;
- if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) {
+ const CPubKey& pubkey = entry->second;
+ CPubKey temp;
+ if (!pwallet->GetPubKey(id, temp) && !pwallet->AddWatchOnly(GetScriptForRawPubKey(pubkey), timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
const auto& key_orig_it = import_data.key_origins.find(id);
@@ -1267,6 +1281,11 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
pwallet->AddKeyOrigin(pubkey, key_orig_it->second);
}
pwallet->mapKeyMetadata[id].nCreateTime = timestamp;
+
+ // Add to keypool only works with pubkeys
+ if (add_keypool) {
+ pwallet->AddKeypoolPubkey(pubkey, internal);
+ }
}
for (const CScript& script : script_pub_keys) {
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 9b303cf239..22ea592738 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -173,18 +173,12 @@ static UniValue getnewaddress(const JSONRPCRequest& request)
},
}.ToString());
- // Belt and suspenders check for disabled private keys
- if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
- }
-
LOCK(pwallet->cs_wallet);
if (!pwallet->CanGetAddresses()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
}
-
// Parse the label first so we don't generate a key if there's an error
std::string label;
if (!request.params[0].isNull())
@@ -240,11 +234,6 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request)
},
}.ToString());
- // Belt and suspenders check for disabled private keys
- if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
- }
-
LOCK(pwallet->cs_wallet);
if (!pwallet->CanGetAddresses(true)) {
@@ -2447,7 +2436,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
CKeyID seed_id = pwallet->GetHDChain().seed_id;
- if (!seed_id.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
+ if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
}
if (pwallet->IsCrypted()) {
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 4df4e0981e..d174e308f0 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2833,8 +2833,8 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
// post-backup change.
// Reserve a new key pair from key pool
- if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
- strFailReason = _("Can't generate a change-address key. Private keys are disabled for this wallet.");
+ if (!CanGetAddresses(true)) {
+ strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.");
return false;
}
CPubKey vchPubKey;
@@ -3443,20 +3443,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
internal = true;
}
- assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys?
- int64_t index = ++m_max_keypool_index;
-
CPubKey pubkey(GenerateNewKey(batch, internal));
- if (!batch.WritePool(index, CKeyPool(pubkey, internal))) {
- throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
- }
-
- if (internal) {
- setInternalKeyPool.insert(index);
- } else {
- setExternalKeyPool.insert(index);
- }
- m_pool_key_to_index[pubkey.GetID()] = index;
+ AddKeypoolPubkeyWithDB(pubkey, internal, batch);
}
if (missingInternal + missingExternal > 0) {
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
@@ -3466,6 +3454,29 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
return true;
}
+void CWallet::AddKeypoolPubkey(const CPubKey& pubkey, const bool internal)
+{
+ WalletBatch batch(*database);
+ AddKeypoolPubkeyWithDB(pubkey, internal, batch);
+ NotifyCanGetAddressesChanged();
+}
+
+void CWallet::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch)
+{
+ LOCK(cs_wallet);
+ assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); // How in the hell did you use so many keys?
+ int64_t index = ++m_max_keypool_index;
+ if (!batch.WritePool(index, CKeyPool(pubkey, internal))) {
+ throw std::runtime_error(std::string(__func__) + ": writing imported pubkey failed");
+ }
+ if (internal) {
+ setInternalKeyPool.insert(index);
+ } else {
+ setExternalKeyPool.insert(index);
+ }
+ m_pool_key_to_index[pubkey.GetID()] = index;
+}
+
bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
{
nIndex = -1;
@@ -3476,7 +3487,8 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
if (!IsLocked())
TopUpKeyPool();
- bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
+ bool fReturningInternal = fRequestedInternal;
+ fReturningInternal &= (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) || IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
bool use_split_keypool = set_pre_split_keypool.empty();
std::set<int64_t>& setKeyPool = use_split_keypool ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool;
@@ -3493,7 +3505,8 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
if (!batch.ReadPool(nIndex, keypool)) {
throw std::runtime_error(std::string(__func__) + ": read failed");
}
- if (!HaveKey(keypool.vchPubKey.GetID())) {
+ CPubKey pk;
+ if (!GetPubKey(keypool.vchPubKey.GetID(), pk)) {
throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
}
// If the key was pre-split keypool, we don't care about what type it is
@@ -3547,7 +3560,7 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
{
LOCK(cs_wallet);
int64_t nIndex;
- if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) {
+ if (!ReserveKeyFromKeyPool(nIndex, keypool, internal) && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
if (IsLocked()) return false;
WalletBatch batch(*database);
result = GenerateNewKey(batch, internal);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 3c5e475bd9..2a5d6caaf8 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -1001,6 +1001,8 @@ public:
bool NewKeyPool();
size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool TopUpKeyPool(unsigned int kpSize = 0);
+ void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal);
+ void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch);
/**
* Reserves a key from the keypool and sets nIndex to its index
diff --git a/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py
index 9fd2650d78..7ec72b8649 100755
--- a/test/functional/wallet_createwallet.py
+++ b/test/functional/wallet_createwallet.py
@@ -31,8 +31,8 @@ class CreateWalletTest(BitcoinTestFramework):
self.log.info("Test disableprivatekeys creation.")
self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True)
w1 = node.get_wallet_rpc('w1')
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w1.getnewaddress)
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w1.getrawchangeaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress)
w1.importpubkey(w0.getaddressinfo(address1)['pubkey'])
self.log.info('Test that private keys cannot be imported')
@@ -48,8 +48,8 @@ class CreateWalletTest(BitcoinTestFramework):
self.log.info("Test blank creation with private keys disabled.")
self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True)
w2 = node.get_wallet_rpc('w2')
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w2.getnewaddress)
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w2.getrawchangeaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getrawchangeaddress)
w2.importpubkey(w0.getaddressinfo(address1)['pubkey'])
self.log.info("Test blank creation with private keys enabled.")
@@ -89,12 +89,12 @@ class CreateWalletTest(BitcoinTestFramework):
self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True)
w5 = node.get_wallet_rpc('w5')
assert_equal(w5.getwalletinfo()['keypoolsize'], 0)
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getnewaddress)
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getrawchangeaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)
# Encrypt the wallet
w5.encryptwallet('pass')
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getnewaddress)
- assert_raises_rpc_error(-4, "Error: Private keys are disabled for this wallet", w5.getrawchangeaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)
+ assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)
if __name__ == '__main__':
CreateWalletTest().main()
diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py
index ee59ef0966..46e3ab77c8 100755
--- a/test/functional/wallet_importmulti.py
+++ b/test/functional/wallet_importmulti.py
@@ -625,7 +625,6 @@ class ImportMultiTest(BitcoinTestFramework):
ismine=False,
iswatchonly=False)
-
# Import pubkeys with key origin info
self.log.info("Addresses should have hd keypath and master key id after import with key origin")
pub_addr = self.nodes[1].getnewaddress()
@@ -691,5 +690,117 @@ class ImportMultiTest(BitcoinTestFramework):
assert 'hdmasterfingerprint' not in pub_import_info
assert 'hdkeypath' not in pub_import_info
+ # Import some public keys to the keypool of a no privkey wallet
+ self.log.info("Adding pubkey to keypool of disableprivkey wallet")
+ self.nodes[1].createwallet(wallet_name="noprivkeys", disable_private_keys=True)
+ wrpc = self.nodes[1].get_wallet_rpc("noprivkeys")
+
+ addr1 = self.nodes[0].getnewaddress()
+ addr2 = self.nodes[0].getnewaddress()
+ pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
+ pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
+ result = wrpc.importmulti(
+ [{
+ 'desc': 'wpkh(' + pub1 + ')',
+ 'keypool': True,
+ "timestamp": "now",
+ },
+ {
+ 'desc': 'wpkh(' + pub2 + ')',
+ 'keypool': True,
+ "timestamp": "now",
+ }]
+ )
+ assert result[0]['success']
+ assert result[1]['success']
+ assert_equal(wrpc.getwalletinfo()["keypoolsize"], 2)
+ newaddr1 = wrpc.getnewaddress()
+ assert_equal(addr1, newaddr1)
+ newaddr2 = wrpc.getnewaddress()
+ assert_equal(addr2, newaddr2)
+
+ # Import some public keys to the internal keypool of a no privkey wallet
+ self.log.info("Adding pubkey to internal keypool of disableprivkey wallet")
+ addr1 = self.nodes[0].getnewaddress()
+ addr2 = self.nodes[0].getnewaddress()
+ pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
+ pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
+ result = wrpc.importmulti(
+ [{
+ 'desc': 'wpkh(' + pub1 + ')',
+ 'keypool': True,
+ 'internal': True,
+ "timestamp": "now",
+ },
+ {
+ 'desc': 'wpkh(' + pub2 + ')',
+ 'keypool': True,
+ 'internal': True,
+ "timestamp": "now",
+ }]
+ )
+ assert result[0]['success']
+ assert result[1]['success']
+ assert_equal(wrpc.getwalletinfo()["keypoolsize_hd_internal"], 2)
+ newaddr1 = wrpc.getrawchangeaddress()
+ assert_equal(addr1, newaddr1)
+ newaddr2 = wrpc.getrawchangeaddress()
+ assert_equal(addr2, newaddr2)
+
+ # Import a multisig and make sure the keys don't go into the keypool
+ self.log.info('Imported scripts with pubkeys shoud not have their pubkeys go into the keypool')
+ addr1 = self.nodes[0].getnewaddress()
+ addr2 = self.nodes[0].getnewaddress()
+ pub1 = self.nodes[0].getaddressinfo(addr1)['pubkey']
+ pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
+ result = wrpc.importmulti(
+ [{
+ 'desc': 'wsh(multi(2,' + pub1 + ',' + pub2 + '))',
+ 'keypool': True,
+ "timestamp": "now",
+ }]
+ )
+ assert result[0]['success']
+ assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0)
+
+ # Cannot import those pubkeys to keypool of wallet with privkeys
+ self.log.info("Pubkeys cannot be added to the keypool of a wallet with private keys")
+ wrpc = self.nodes[1].get_wallet_rpc("")
+ assert wrpc.getwalletinfo()['private_keys_enabled']
+ result = wrpc.importmulti(
+ [{
+ 'desc': 'wpkh(' + pub1 + ')',
+ 'keypool': True,
+ "timestamp": "now",
+ }]
+ )
+ assert_equal(result[0]['error']['code'], -8)
+ assert_equal(result[0]['error']['message'], "Keys can only be imported to the keypool when private keys are disabled")
+
+ # Make sure ranged imports import keys in order
+ self.log.info('Key ranges should be imported in order')
+ wrpc = self.nodes[1].get_wallet_rpc("noprivkeys")
+ assert_equal(wrpc.getwalletinfo()["keypoolsize"], 0)
+ assert_equal(wrpc.getwalletinfo()["private_keys_enabled"], False)
+ xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY"
+ addresses = [
+ 'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv', # m/0'/0'/0
+ 'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8', # m/0'/0'/1
+ 'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu', # m/0'/0'/2
+ 'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640', # m/0'/0'/3
+ 'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0', # m/0'/0'/4
+ ]
+ result = wrpc.importmulti(
+ [{
+ 'desc': 'wpkh([80002067/0h/0h]' + xpub + '/*)',
+ 'keypool': True,
+ 'timestamp': 'now',
+ 'range' : {'start': 0, 'end': 4}
+ }]
+ )
+ for i in range(0, 5):
+ addr = wrpc.getnewaddress('', 'bech32')
+ assert_equal(addr, addresses[i])
+
if __name__ == '__main__':
ImportMultiTest().main()