From 9b81fd19ac7ff9f34cc32cc221f057d9c3cd7218 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 6 Nov 2018 09:44:51 -0500 Subject: [PATCH] Fetch keys from keypool when private keys are disabled When private keys are disabled, still fetch keys from the keypool if the keypool has keys. Those keys come from importing them and adding them to the keypool. --- src/wallet/rpcwallet.cpp | 13 +------------ src/wallet/wallet.cpp | 12 +++++++----- test/functional/wallet_createwallet.py | 16 ++++++++-------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9b303cf23..22ea59273 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 186c136ee..d174e308f 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; @@ -3487,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& setKeyPool = use_split_keypool ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) : set_pre_split_keypool; @@ -3504,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 @@ -3558,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/test/functional/wallet_createwallet.py b/test/functional/wallet_createwallet.py index 9fd2650d7..7ec72b864 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()