diff options
author | MeshCollider <dobsonsa68@gmail.com> | 2019-02-11 08:07:17 +1300 |
---|---|---|
committer | MeshCollider <dobsonsa68@gmail.com> | 2019-02-11 08:08:33 +1300 |
commit | 6f4e0d154256c2041f15f0c4acba5707e985d649 (patch) | |
tree | 4f3c21dbb0520a4a0e5718d4da8f387378de547a /src/wallet/wallet.cpp | |
parent | 2945492424934fa360f86b116184ee8e34f19d0a (diff) | |
parent | 7687f7873b75c3cbdfa15ab570211dc39d24ab80 (diff) |
Merge #15226: Allow creating blank (empty) wallets (alternative)
7687f7873 [wallet] Support creating a blank wallet (Andrew Chow)
Pull request description:
Alternative (kind of) to #14938
This PR adds a `blank` parameter to the `createwallet` RPC to create a wallet that has no private keys initially. `sethdseed` can then be used to make a clean wallet with a custom seed. `encryptwallet` can also be used to make a wallet that is born encrypted.
Instead of changing the version number as done in #14938, a wallet flag is used to indicate that the wallet should be blank. This flag is set at creation, and then unset when the wallet is no longer blank. A wallet becomes non-blank when a HD seed is set or anything is imported. The main change to create a blank wallet is primarily taken from #14938.
Also with this, the term "blank wallet" is used instead of "empty wallet" to avoid confusion with wallets that have balance which would also be referred to as "empty".
This is built on top of #15225 in order to fix GUI issues.
Tree-SHA512: 824d685e11ac2259a26b5ece99c67a7bda94a570cd921472c464243ee356b7734595ad35cc439b34357135df041ed9cba951e6edac194935c3a55a1dc4fcbdea
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 66 |
1 files changed, 58 insertions, 8 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index af93653375..d38c15220f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -168,6 +168,7 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) { assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); + assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)); AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets @@ -177,7 +178,7 @@ CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); - // use HD key derivation if HD was enabled during wallet creation + // use HD key derivation if HD was enabled during wallet creation and a seed is present if (IsHDEnabled()) { DeriveNewChildKey(batch, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); } else { @@ -283,6 +284,7 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); } + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); return true; } @@ -349,7 +351,11 @@ bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) return false; - return WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript); + if (WalletBatch(*database).WriteCScript(Hash160(redeemScript), redeemScript)) { + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); + return true; + } + return false; } bool CWallet::LoadCScript(const CScript& redeemScript) @@ -374,7 +380,11 @@ bool CWallet::AddWatchOnly(const CScript& dest) const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; UpdateTimeFirstKey(meta.nCreateTime); NotifyWatchonlyChanged(true); - return WalletBatch(*database).WriteWatchOnly(dest, meta); + if (WalletBatch(*database).WriteWatchOnly(dest, meta)) { + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); + return true; + } + return false; } bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) @@ -1402,6 +1412,7 @@ void CWallet::SetHDSeed(const CPubKey& seed) newHdChain.seed_id = seed.GetID(); SetHDChain(newHdChain, false); NotifyCanGetAddressesChanged(); + UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); } void CWallet::SetHDChain(const CHDChain& chain, bool memonly) @@ -1418,6 +1429,30 @@ bool CWallet::IsHDEnabled() const return !hdChain.seed_id.IsNull(); } +bool CWallet::CanGenerateKeys() +{ + // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a non-HD wallet (pre FEATURE_HD) + LOCK(cs_wallet); + return IsHDEnabled() || !CanSupportFeature(FEATURE_HD); +} + +bool CWallet::CanGetAddresses(bool internal) +{ + LOCK(cs_wallet); + // Check if the keypool has keys + bool keypool_has_keys; + if (internal && CanSupportFeature(FEATURE_HD_SPLIT)) { + keypool_has_keys = setInternalKeyPool.size() > 0; + } else { + keypool_has_keys = KeypoolCountExternalKeys() > 0; + } + // If the keypool doesn't have keys, check if we can generate them + if (!keypool_has_keys) { + return CanGenerateKeys(); + } + return keypool_has_keys; +} + void CWallet::SetWalletFlag(uint64_t flags) { LOCK(cs_wallet); @@ -1426,6 +1461,14 @@ void CWallet::SetWalletFlag(uint64_t flags) throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); } +void CWallet::UnsetWalletFlag(uint64_t flag) +{ + LOCK(cs_wallet); + m_wallet_flags &= ~flag; + if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) + throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); +} + bool CWallet::IsWalletFlagSet(uint64_t flag) { return (m_wallet_flags & flag); @@ -3103,7 +3146,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { LOCK(cs_KeyStore); // This wallet is in its first run if all of these are empty - fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty() + && !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); } if (nLoadWalletRet != DBErrors::LOAD_OK) @@ -3288,7 +3332,7 @@ void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) bool CWallet::TopUpKeyPool(unsigned int kpSize) { - if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!CanGenerateKeys()) { return false; } { @@ -3418,7 +3462,7 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey) bool CWallet::GetKeyFromPool(CPubKey& result, bool internal) { - if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + if (!CanGetAddresses(internal)) { return false; } @@ -3619,6 +3663,10 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal) { + if (!pwallet->CanGetAddresses(internal)) { + return false; + } + if (nIndex == -1) { CKeyPool keypool; @@ -4072,14 +4120,16 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { //selective allow to set flags walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); + } else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) { + walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET); } else { // generate a new seed CPubKey seed = walletInstance->GenerateNewSeed(); walletInstance->SetHDSeed(seed); - } + } // Otherwise, do not generate a new seed // Top up the keypool - if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !walletInstance->TopUpKeyPool()) { + if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) { InitError(_("Unable to generate initial keys")); return nullptr; } |