Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | if (it == mapWallet.end()) { | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
return &(it->second); | return &(it->second); | ||||
} | } | ||||
CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) { | CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) { | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)); | |||||
// mapKeyMetadata | // mapKeyMetadata | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
// default to compressed public keys if we want 0.6.0 wallets | // default to compressed public keys if we want 0.6.0 wallets | ||||
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); | bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); | ||||
CKey secret; | CKey secret; | ||||
// Create new metadata | // Create new metadata | ||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | 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()) { | if (IsHDEnabled()) { | ||||
DeriveNewChildKey( | DeriveNewChildKey( | ||||
batch, metadata, secret, | batch, metadata, secret, | ||||
(CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | ||||
} else { | } else { | ||||
secret.MakeNewKey(fCompressed); | secret.MakeNewKey(fCompressed); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | if (HaveWatchOnly(script)) { | ||||
RemoveWatchOnly(script); | RemoveWatchOnly(script); | ||||
} | } | ||||
script = GetScriptForRawPubKey(pubkey); | script = GetScriptForRawPubKey(pubkey); | ||||
if (HaveWatchOnly(script)) { | if (HaveWatchOnly(script)) { | ||||
RemoveWatchOnly(script); | RemoveWatchOnly(script); | ||||
} | } | ||||
if (IsCrypted()) { | if (!IsCrypted()) { | ||||
return true; | |||||
} | |||||
return batch.WriteKey(pubkey, secret.GetPrivKey(), | return batch.WriteKey(pubkey, secret.GetPrivKey(), | ||||
mapKeyMetadata[pubkey.GetID()]); | mapKeyMetadata[pubkey.GetID()]); | ||||
} | } | ||||
UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); | |||||
return true; | |||||
} | |||||
bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { | bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
return CWallet::AddKeyPubKeyWithDB(batch, secret, pubkey); | return CWallet::AddKeyPubKeyWithDB(batch, secret, pubkey); | ||||
} | } | ||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, | bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, | ||||
const std::vector<uint8_t> &vchCryptedSecret) { | const std::vector<uint8_t> &vchCryptedSecret) { | ||||
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) { | if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) { | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (nCreateTime <= 1) { | ||||
nTimeFirstKey = nCreateTime; | nTimeFirstKey = nCreateTime; | ||||
} | } | ||||
} | } | ||||
bool CWallet::AddCScript(const CScript &redeemScript) { | bool CWallet::AddCScript(const CScript &redeemScript) { | ||||
if (!CCryptoKeyStore::AddCScript(redeemScript)) { | if (!CCryptoKeyStore::AddCScript(redeemScript)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (WalletBatch(*database).WriteCScript(Hash160(redeemScript), | |||||
return WalletBatch(*database).WriteCScript(Hash160(redeemScript), | redeemScript)) { | ||||
redeemScript); | UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); | ||||
return true; | |||||
} | |||||
return false; | |||||
} | } | ||||
bool CWallet::LoadCScript(const CScript &redeemScript) { | bool CWallet::LoadCScript(const CScript &redeemScript) { | ||||
/** | /** | ||||
* A sanity check was added in pull #3843 to avoid adding redeemScripts that | * A sanity check was added in pull #3843 to avoid adding redeemScripts that | ||||
* never can be redeemed. However, old wallets may still contain these. Do | * never can be redeemed. However, old wallets may still contain these. Do | ||||
* not add them to the wallet and warn. | * not add them to the wallet and warn. | ||||
*/ | */ | ||||
Show All 14 Lines | |||||
bool CWallet::AddWatchOnly(const CScript &dest) { | bool CWallet::AddWatchOnly(const CScript &dest) { | ||||
if (!CCryptoKeyStore::AddWatchOnly(dest)) { | if (!CCryptoKeyStore::AddWatchOnly(dest)) { | ||||
return false; | return false; | ||||
} | } | ||||
const CKeyMetadata &meta = m_script_metadata[CScriptID(dest)]; | const CKeyMetadata &meta = m_script_metadata[CScriptID(dest)]; | ||||
UpdateTimeFirstKey(meta.nCreateTime); | UpdateTimeFirstKey(meta.nCreateTime); | ||||
NotifyWatchonlyChanged(true); | 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) { | bool CWallet::AddWatchOnly(const CScript &dest, int64_t nCreateTime) { | ||||
m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime; | m_script_metadata[CScriptID(dest)].nCreateTime = nCreateTime; | ||||
return AddWatchOnly(dest); | return AddWatchOnly(dest); | ||||
} | } | ||||
bool CWallet::RemoveWatchOnly(const CScript &dest) { | bool CWallet::RemoveWatchOnly(const CScript &dest) { | ||||
▲ Show 20 Lines • Show All 1,168 Lines • ▼ Show 20 Lines | void CWallet::SetHDSeed(const CPubKey &seed) { | ||||
// database as a hdchain object. | // database as a hdchain object. | ||||
CHDChain newHdChain; | CHDChain newHdChain; | ||||
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | ||||
? CHDChain::VERSION_HD_CHAIN_SPLIT | ? CHDChain::VERSION_HD_CHAIN_SPLIT | ||||
: CHDChain::VERSION_HD_BASE; | : CHDChain::VERSION_HD_BASE; | ||||
newHdChain.seed_id = seed.GetID(); | newHdChain.seed_id = seed.GetID(); | ||||
SetHDChain(newHdChain, false); | SetHDChain(newHdChain, false); | ||||
NotifyCanGetAddressesChanged(); | NotifyCanGetAddressesChanged(); | ||||
UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); | |||||
} | } | ||||
void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing chain failed"); | ": writing chain failed"); | ||||
} | } | ||||
hdChain = chain; | hdChain = chain; | ||||
} | } | ||||
bool CWallet::IsHDEnabled() const { | bool CWallet::IsHDEnabled() const { | ||||
return !hdChain.seed_id.IsNull(); | 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) { | void CWallet::SetWalletFlag(uint64_t flags) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
m_wallet_flags |= flags; | m_wallet_flags |= flags; | ||||
if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) { | if (!WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing wallet flags failed"); | ": 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) { | bool CWallet::IsWalletFlagSet(uint64_t flag) { | ||||
return (m_wallet_flags & flag); | return (m_wallet_flags & flag); | ||||
} | } | ||||
bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly) { | bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
m_wallet_flags = overwriteFlags; | m_wallet_flags = overwriteFlags; | ||||
if (((overwriteFlags & g_known_wallet_flags) >> 32) ^ | if (((overwriteFlags & g_known_wallet_flags) >> 32) ^ | ||||
▲ Show 20 Lines • Show All 1,804 Lines • ▼ Show 20 Lines | DBErrors CWallet::LoadWallet(bool &fFirstRunRet) { | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
// This wallet is in its first run if all of these are empty | // This wallet is in its first run if all of these are empty | ||||
fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && | fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && | ||||
mapWatchKeys.empty() && setWatchOnly.empty() && | mapWatchKeys.empty() && setWatchOnly.empty() && | ||||
mapScripts.empty() && | mapScripts.empty() && | ||||
!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | !IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && | ||||
!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET); | |||||
} | } | ||||
if (nLoadWalletRet != DBErrors::LOAD_OK) { | if (nLoadWalletRet != DBErrors::LOAD_OK) { | ||||
return nLoadWalletRet; | return nLoadWalletRet; | ||||
} | } | ||||
return DBErrors::LOAD_OK; | return DBErrors::LOAD_OK; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) { | ||||
// stored metadata for that key later, which is fine. | // stored metadata for that key later, which is fine. | ||||
CKeyID keyid = keypool.vchPubKey.GetID(); | CKeyID keyid = keypool.vchPubKey.GetID(); | ||||
if (mapKeyMetadata.count(keyid) == 0) { | if (mapKeyMetadata.count(keyid) == 0) { | ||||
mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); | mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); | ||||
} | } | ||||
} | } | ||||
bool CWallet::TopUpKeyPool(unsigned int kpSize) { | bool CWallet::TopUpKeyPool(unsigned int kpSize) { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (!CanGenerateKeys()) { | ||||
return false; | return false; | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (IsLocked()) { | if (IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 131 Lines • ▼ Show 20 Lines | // Return to key pool | ||||
m_pool_key_to_index[pubkey.GetID()] = nIndex; | m_pool_key_to_index[pubkey.GetID()] = nIndex; | ||||
NotifyCanGetAddressesChanged(); | NotifyCanGetAddressesChanged(); | ||||
} | } | ||||
WalletLogPrintf("keypool return %d\n", nIndex); | WalletLogPrintf("keypool return %d\n", nIndex); | ||||
} | } | ||||
bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | bool CWallet::GetKeyFromPool(CPubKey &result, bool internal) { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (!CanGetAddresses(internal)) { | ||||
return false; | return false; | ||||
} | } | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
int64_t nIndex; | int64_t nIndex; | ||||
if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) { | if (!ReserveKeyFromKeyPool(nIndex, keypool, internal)) { | ||||
if (IsLocked()) { | if (IsLocked()) { | ||||
▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void CWallet::DeleteLabel(const std::string &label) { | void CWallet::DeleteLabel(const std::string &label) { | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
batch.EraseAccount(label); | batch.EraseAccount(label); | ||||
} | } | ||||
bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) { | bool CReserveKey::GetReservedKey(CPubKey &pubkey, bool internal) { | ||||
if (!pwallet->CanGetAddresses(internal)) { | |||||
return false; | |||||
} | |||||
if (nIndex == -1) { | if (nIndex == -1) { | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
if (!pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal)) { | if (!pwallet->ReserveKeyFromKeyPool(nIndex, keypool, internal)) { | ||||
return false; | return false; | ||||
} | } | ||||
vchPubKey = keypool.vchPubKey; | vchPubKey = keypool.vchPubKey; | ||||
fInternal = keypool.fInternal; | fInternal = keypool.fInternal; | ||||
▲ Show 20 Lines • Show All 516 Lines • ▼ Show 20 Lines | if (fFirstRun) { | ||||
walletFile)); | walletFile)); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->SetMinVersion(FEATURE_LATEST); | walletInstance->SetMinVersion(FEATURE_LATEST); | ||||
if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
// selective allow to set flags | // selective allow to set flags | ||||
walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | ||||
} else if (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET) { | |||||
walletInstance->SetWalletFlag(WALLET_FLAG_BLANK_WALLET); | |||||
} else { | } else { | ||||
// generate a new seed | // generate a new seed | ||||
CPubKey seed = walletInstance->GenerateNewSeed(); | CPubKey seed = walletInstance->GenerateNewSeed(); | ||||
walletInstance->SetHDSeed(seed); | walletInstance->SetHDSeed(seed); | ||||
} | } // Otherwise, do not generate a new seed | ||||
// Top up the keypool | // Top up the keypool | ||||
if (!walletInstance->IsWalletFlagSet( | if (walletInstance->CanGenerateKeys() && | ||||
WALLET_FLAG_DISABLE_PRIVATE_KEYS) && | |||||
!walletInstance->TopUpKeyPool()) { | !walletInstance->TopUpKeyPool()) { | ||||
InitError(_("Unable to generate initial keys")); | InitError(_("Unable to generate initial keys")); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->ChainStateFlushed(chainActive.GetLocator()); | walletInstance->ChainStateFlushed(chainActive.GetLocator()); | ||||
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { | } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { | ||||
// Make it impossible to disable private keys after creation | // Make it impossible to disable private keys after creation | ||||
▲ Show 20 Lines • Show All 360 Lines • Show Last 20 Lines |