Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/scriptpubkeyman.cpp
// Copyright (c) 2019 The Bitcoin Core developers | // Copyright (c) 2019 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <config.h> | #include <config.h> | ||||
#include <key_io.h> | #include <key_io.h> | ||||
#include <outputtype.h> | #include <outputtype.h> | ||||
#include <script/descriptor.h> | #include <script/descriptor.h> | ||||
#include <util/bip32.h> | #include <util/bip32.h> | ||||
#include <util/strencodings.h> | #include <util/strencodings.h> | ||||
#include <util/translation.h> | #include <util/translation.h> | ||||
#include <wallet/scriptpubkeyman.h> | #include <wallet/scriptpubkeyman.h> | ||||
#include <wallet/wallet.h> | #include <wallet/wallet.h> | ||||
bool CWallet::GetNewDestination(const OutputType type, const std::string label, | bool LegacyScriptPubKeyMan::GetNewDestination(const OutputType type, | ||||
CTxDestination &dest, std::string &error) { | const std::string label, | ||||
CTxDestination &dest, | |||||
std::string &error) { | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
error.clear(); | error.clear(); | ||||
TopUpKeyPool(); | TopUpKeyPool(); | ||||
// Generate a new key that is added to wallet | // Generate a new key that is added to wallet | ||||
CPubKey new_key; | CPubKey new_key; | ||||
if (!GetKeyFromPool(new_key)) { | if (!GetKeyFromPool(new_key)) { | ||||
error = "Error: Keypool ran out, please call keypoolrefill first"; | error = "Error: Keypool ran out, please call keypoolrefill first"; | ||||
return false; | return false; | ||||
} | } | ||||
LearnRelatedScripts(new_key, type); | LearnRelatedScripts(new_key, type); | ||||
dest = GetDestinationForKey(new_key, type); | dest = GetDestinationForKey(new_key, type); | ||||
SetAddressBook(dest, label, "receive"); | m_wallet.SetAddressBook(dest, label, "receive"); | ||||
return true; | return true; | ||||
} | } | ||||
typedef std::vector<uint8_t> valtype; | typedef std::vector<uint8_t> valtype; | ||||
namespace { | namespace { | ||||
/** | /** | ||||
Show All 14 Lines | |||||
*/ | */ | ||||
enum class IsMineResult { | enum class IsMineResult { | ||||
NO = 0, //! Not ours | NO = 0, //! Not ours | ||||
WATCH_ONLY = 1, //! Included in watch-only balance | WATCH_ONLY = 1, //! Included in watch-only balance | ||||
SPENDABLE = 2, //! Included in all balances | SPENDABLE = 2, //! Included in all balances | ||||
INVALID = 3, //! Not spendable by anyone (P2SH inside P2SH) | INVALID = 3, //! Not spendable by anyone (P2SH inside P2SH) | ||||
}; | }; | ||||
bool HaveKeys(const std::vector<valtype> &pubkeys, const CWallet &keystore) { | bool HaveKeys(const std::vector<valtype> &pubkeys, | ||||
const LegacyScriptPubKeyMan &keystore) { | |||||
for (const valtype &pubkey : pubkeys) { | for (const valtype &pubkey : pubkeys) { | ||||
CKeyID keyID = CPubKey(pubkey).GetID(); | CKeyID keyID = CPubKey(pubkey).GetID(); | ||||
if (!keystore.HaveKey(keyID)) { | if (!keystore.HaveKey(keyID)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
IsMineResult IsMineInner(const CWallet &keystore, const CScript &scriptPubKey, | IsMineResult IsMineInner(const LegacyScriptPubKeyMan &keystore, | ||||
const CScript &scriptPubKey, | |||||
IsMineSigVersion sigversion) { | IsMineSigVersion sigversion) { | ||||
IsMineResult ret = IsMineResult::NO; | IsMineResult ret = IsMineResult::NO; | ||||
std::vector<valtype> vSolutions; | std::vector<valtype> vSolutions; | ||||
txnouttype whichType = Solver(scriptPubKey, vSolutions); | txnouttype whichType = Solver(scriptPubKey, vSolutions); | ||||
CKeyID keyID; | CKeyID keyID; | ||||
switch (whichType) { | switch (whichType) { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | IsMineResult IsMineInner(const LegacyScriptPubKeyMan &keystore, | ||||
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) { | if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) { | ||||
ret = std::max(ret, IsMineResult::WATCH_ONLY); | ret = std::max(ret, IsMineResult::WATCH_ONLY); | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
} // namespace | } // namespace | ||||
isminetype IsMine(const CWallet &keystore, const CScript &scriptPubKey) { | isminetype LegacyScriptPubKeyMan::IsMine(const CScript &script) const { | ||||
switch (IsMineInner(keystore, scriptPubKey, IsMineSigVersion::TOP)) { | switch (IsMineInner(*this, script, IsMineSigVersion::TOP)) { | ||||
case IsMineResult::INVALID: | case IsMineResult::INVALID: | ||||
case IsMineResult::NO: | case IsMineResult::NO: | ||||
return ISMINE_NO; | return ISMINE_NO; | ||||
case IsMineResult::WATCH_ONLY: | case IsMineResult::WATCH_ONLY: | ||||
return ISMINE_WATCH_ONLY; | return ISMINE_WATCH_ONLY; | ||||
case IsMineResult::SPENDABLE: | case IsMineResult::SPENDABLE: | ||||
return ISMINE_SPENDABLE; | return ISMINE_SPENDABLE; | ||||
} | } | ||||
Show All 34 Lines | bool CWallet::Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys) { | ||||
} | } | ||||
vMasterKey = vMasterKeyIn; | vMasterKey = vMasterKeyIn; | ||||
fDecryptionThoroughlyChecked = true; | fDecryptionThoroughlyChecked = true; | ||||
} | } | ||||
NotifyStatusChanged(this); | NotifyStatusChanged(this); | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::EncryptKeys(CKeyingMaterial &vMasterKeyIn) { | bool LegacyScriptPubKeyMan::EncryptKeys(CKeyingMaterial &vMasterKeyIn) { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!mapCryptedKeys.empty() || IsCrypted()) { | if (!mapCryptedKeys.empty() || IsCrypted()) { | ||||
return false; | return false; | ||||
} | } | ||||
fUseCrypto = true; | fUseCrypto = true; | ||||
for (const KeyMap::value_type &mKey : mapKeys) { | for (const KeyMap::value_type &mKey : mapKeys) { | ||||
const CKey &key = mKey.second; | const CKey &key = mKey.second; | ||||
CPubKey vchPubKey = key.GetPubKey(); | CPubKey vchPubKey = key.GetPubKey(); | ||||
CKeyingMaterial vchSecret(key.begin(), key.end()); | CKeyingMaterial vchSecret(key.begin(), key.end()); | ||||
std::vector<uint8_t> vchCryptedSecret; | std::vector<uint8_t> vchCryptedSecret; | ||||
if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), | if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), | ||||
vchCryptedSecret)) { | vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) { | if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
mapKeys.clear(); | mapKeys.clear(); | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::UpgradeKeyMetadata() { | void LegacyScriptPubKeyMan::UpgradeKeyMetadata() { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) { | if (m_storage.IsLocked() || | ||||
m_storage.IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) { | |||||
return; | return; | ||||
} | } | ||||
auto batch = std::make_unique<WalletBatch>(*database); | auto batch = std::make_unique<WalletBatch>(m_storage.GetDatabase()); | ||||
for (auto &meta_pair : mapKeyMetadata) { | for (auto &meta_pair : mapKeyMetadata) { | ||||
CKeyMetadata &meta = meta_pair.second; | CKeyMetadata &meta = meta_pair.second; | ||||
// If the hdKeypath is "s", that's the seed and it doesn't have a key | // If the hdKeypath is "s", that's the seed and it doesn't have a key | ||||
// origin | // origin | ||||
if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && | if (!meta.hd_seed_id.IsNull() && !meta.has_key_origin && | ||||
meta.hdKeypath != "s") { | meta.hdKeypath != "s") { | ||||
CKey key; | CKey key; | ||||
GetKey(meta.hd_seed_id, key); | GetKey(meta.hd_seed_id, key); | ||||
Show All 16 Lines | for (auto &meta_pair : mapKeyMetadata) { | ||||
if (GetPubKey(meta_pair.first, pubkey)) { | if (GetPubKey(meta_pair.first, pubkey)) { | ||||
batch->WriteKeyMetadata(meta, pubkey, true); | batch->WriteKeyMetadata(meta, pubkey, true); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// write before setting the flag | // write before setting the flag | ||||
batch.reset(); | batch.reset(); | ||||
SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA); | m_storage.SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA); | ||||
} | } | ||||
bool CWallet::IsHDEnabled() const { | bool LegacyScriptPubKeyMan::IsHDEnabled() const { | ||||
return !hdChain.seed_id.IsNull(); | return !hdChain.seed_id.IsNull(); | ||||
} | } | ||||
bool CWallet::CanGetAddresses(bool internal) { | bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Check if the keypool has keys | // Check if the keypool has keys | ||||
bool keypool_has_keys; | bool keypool_has_keys; | ||||
if (internal && CanSupportFeature(FEATURE_HD_SPLIT)) { | if (internal && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
keypool_has_keys = setInternalKeyPool.size() > 0; | keypool_has_keys = setInternalKeyPool.size() > 0; | ||||
} else { | } else { | ||||
keypool_has_keys = KeypoolCountExternalKeys() > 0; | keypool_has_keys = KeypoolCountExternalKeys() > 0; | ||||
} | } | ||||
// If the keypool doesn't have keys, check if we can generate them | // If the keypool doesn't have keys, check if we can generate them | ||||
if (!keypool_has_keys) { | if (!keypool_has_keys) { | ||||
return CanGenerateKeys(); | return CanGenerateKeys(); | ||||
} | } | ||||
Show All 12 Lines | if (!batch.ReadPool(nIndex, keypool)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": read oldest key in keypool failed"); | ": read oldest key in keypool failed"); | ||||
} | } | ||||
assert(keypool.vchPubKey.IsValid()); | assert(keypool.vchPubKey.IsValid()); | ||||
return keypool.nTime; | return keypool.nTime; | ||||
} | } | ||||
int64_t CWallet::GetOldestKeyPoolTime() { | int64_t LegacyScriptPubKeyMan::GetOldestKeyPoolTime() { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
// load oldest key from keypool, get time and return | // load oldest key from keypool, get time and return | ||||
int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch); | int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch); | ||||
if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) { | if (IsHDEnabled() && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), | oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), | ||||
oldestKey); | oldestKey); | ||||
if (!set_pre_split_keypool.empty()) { | if (!set_pre_split_keypool.empty()) { | ||||
oldestKey = | oldestKey = | ||||
std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), | std::max(GetOldestKeyTimeInPool(set_pre_split_keypool, batch), | ||||
oldestKey); | oldestKey); | ||||
} | } | ||||
} | } | ||||
return oldestKey; | return oldestKey; | ||||
} | } | ||||
size_t CWallet::KeypoolCountExternalKeys() { | size_t LegacyScriptPubKeyMan::KeypoolCountExternalKeys() { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
return setExternalKeyPool.size() + set_pre_split_keypool.size(); | return setExternalKeyPool.size() + set_pre_split_keypool.size(); | ||||
} | } | ||||
/** | /** | ||||
* Update wallet first key creation time. This should be called whenever keys | * Update wallet first key creation time. This should be called whenever keys | ||||
* are added to the wallet, with the oldest key creation time. | * are added to the wallet, with the oldest key creation time. | ||||
*/ | */ | ||||
void CWallet::UpdateTimeFirstKey(int64_t nCreateTime) { | void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime) { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
if (nCreateTime <= 1) { | if (nCreateTime <= 1) { | ||||
// Cannot determine birthday information, so set the wallet birthday to | // Cannot determine birthday information, so set the wallet birthday to | ||||
// the beginning of time. | // the beginning of time. | ||||
nTimeFirstKey = 1; | nTimeFirstKey = 1; | ||||
} else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) { | } else if (!nTimeFirstKey || nCreateTime < nTimeFirstKey) { | ||||
nTimeFirstKey = nCreateTime; | nTimeFirstKey = nCreateTime; | ||||
} | } | ||||
} | } | ||||
bool CWallet::AddKeyPubKey(const CKey &secret, const CPubKey &pubkey) { | bool LegacyScriptPubKeyMan::AddKeyPubKey(const CKey &secret, | ||||
WalletBatch batch(*database); | const CPubKey &pubkey) { | ||||
return CWallet::AddKeyPubKeyWithDB(batch, secret, pubkey); | WalletBatch batch(m_storage.GetDatabase()); | ||||
return LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(batch, secret, pubkey); | |||||
} | } | ||||
bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &secret, | bool LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch &batch, | ||||
const CKey &secret, | |||||
const CPubKey &pubkey) { | const CPubKey &pubkey) { | ||||
AssertLockHeld(cs_wallet); | |||||
// Make sure we aren't adding private keys to private key disabled wallets | // Make sure we aren't adding private keys to private key disabled wallets | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | ||||
// FillableSigningProvider has no concept of wallet databases, but calls | // FillableSigningProvider has no concept of wallet databases, but calls | ||||
// AddCryptedKey which is overridden below. To avoid flushes, the database | // AddCryptedKey which is overridden below. To avoid flushes, the database | ||||
// handle is tunneled through to it. | // handle is tunneled through to it. | ||||
bool needsDB = !encrypted_batch; | bool needsDB = !encrypted_batch; | ||||
if (needsDB) { | if (needsDB) { | ||||
encrypted_batch = &batch; | encrypted_batch = &batch; | ||||
} | } | ||||
Show All 20 Lines | if (HaveWatchOnly(script)) { | ||||
RemoveWatchOnly(script); | RemoveWatchOnly(script); | ||||
} | } | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
return batch.WriteKey(pubkey, secret.GetPrivKey(), | return batch.WriteKey(pubkey, secret.GetPrivKey(), | ||||
mapKeyMetadata[pubkey.GetID()]); | mapKeyMetadata[pubkey.GetID()]); | ||||
} | } | ||||
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | m_storage.UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::LoadCScript(const CScript &redeemScript) { | bool LegacyScriptPubKeyMan::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. | ||||
*/ | */ | ||||
if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { | if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
std::string strAddr = | std::string strAddr = | ||||
EncodeDestination(ScriptHash(redeemScript), GetConfig()); | EncodeDestination(ScriptHash(redeemScript), GetConfig()); | ||||
WalletLogPrintf("%s: Warning: This wallet contains a redeemScript " | WalletLogPrintf("%s: Warning: This wallet contains a redeemScript " | ||||
"of size %i which exceeds maximum size %i thus can " | "of size %i which exceeds maximum size %i thus can " | ||||
"never be redeemed. Do not use address %s.\n", | "never be redeemed. Do not use address %s.\n", | ||||
__func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, | __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, | ||||
strAddr); | strAddr); | ||||
return true; | return true; | ||||
} | } | ||||
return FillableSigningProvider::AddCScript(redeemScript); | return FillableSigningProvider::AddCScript(redeemScript); | ||||
} | } | ||||
void CWallet::LoadKeyMetadata(const CKeyID &keyID, const CKeyMetadata &meta) { | void LegacyScriptPubKeyMan::LoadKeyMetadata(const CKeyID &keyID, | ||||
const CKeyMetadata &meta) { | |||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
UpdateTimeFirstKey(meta.nCreateTime); | UpdateTimeFirstKey(meta.nCreateTime); | ||||
mapKeyMetadata[keyID] = meta; | mapKeyMetadata[keyID] = meta; | ||||
} | } | ||||
void CWallet::LoadScriptMetadata(const CScriptID &script_id, | void LegacyScriptPubKeyMan::LoadScriptMetadata(const CScriptID &script_id, | ||||
const CKeyMetadata &meta) { | const CKeyMetadata &meta) { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
UpdateTimeFirstKey(meta.nCreateTime); | UpdateTimeFirstKey(meta.nCreateTime); | ||||
m_script_metadata[script_id] = meta; | m_script_metadata[script_id] = meta; | ||||
} | } | ||||
bool CWallet::AddKeyPubKeyInner(const CKey &key, const CPubKey &pubkey) { | bool LegacyScriptPubKeyMan::AddKeyPubKeyInner(const CKey &key, | ||||
const CPubKey &pubkey) { | |||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
return FillableSigningProvider::AddKeyPubKey(key, pubkey); | return FillableSigningProvider::AddKeyPubKey(key, pubkey); | ||||
} | } | ||||
if (IsLocked()) { | if (m_storage.IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
std::vector<uint8_t> vchCryptedSecret; | std::vector<uint8_t> vchCryptedSecret; | ||||
CKeyingMaterial vchSecret(key.begin(), key.end()); | CKeyingMaterial vchSecret(key.begin(), key.end()); | ||||
if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), | if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), | ||||
vchCryptedSecret)) { | vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (!AddCryptedKey(pubkey, vchCryptedSecret)) { | if (!AddCryptedKey(pubkey, vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, | bool LegacyScriptPubKeyMan::LoadCryptedKey( | ||||
const std::vector<uint8_t> &vchCryptedSecret) { | const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret) { | ||||
return AddCryptedKeyInner(vchPubKey, vchCryptedSecret); | return AddCryptedKeyInner(vchPubKey, vchCryptedSecret); | ||||
} | } | ||||
bool CWallet::AddCryptedKeyInner(const CPubKey &vchPubKey, | bool LegacyScriptPubKeyMan::AddCryptedKeyInner( | ||||
const std::vector<uint8_t> &vchCryptedSecret) { | const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret) { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!SetCrypted()) { | if (!SetCrypted()) { | ||||
return false; | return false; | ||||
} | } | ||||
mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); | mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, | bool LegacyScriptPubKeyMan::AddCryptedKey( | ||||
const std::vector<uint8_t> &vchCryptedSecret) { | const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret) { | ||||
if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret)) { | if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret)) { | ||||
return false; | return false; | ||||
} | } | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (encrypted_batch) { | if (encrypted_batch) { | ||||
return encrypted_batch->WriteCryptedKey( | return encrypted_batch->WriteCryptedKey( | ||||
vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); | vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); | ||||
} | } | ||||
return WalletBatch(*database).WriteCryptedKey( | return WalletBatch(m_storage.GetDatabase()) | ||||
vchPubKey, vchCryptedSecret, mapKeyMetadata[vchPubKey.GetID()]); | .WriteCryptedKey(vchPubKey, vchCryptedSecret, | ||||
mapKeyMetadata[vchPubKey.GetID()]); | |||||
} | } | ||||
bool CWallet::HaveWatchOnly(const CScript &dest) const { | bool LegacyScriptPubKeyMan::HaveWatchOnly(const CScript &dest) const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
return setWatchOnly.count(dest) > 0; | return setWatchOnly.count(dest) > 0; | ||||
} | } | ||||
bool CWallet::HaveWatchOnly() const { | bool LegacyScriptPubKeyMan::HaveWatchOnly() const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
return (!setWatchOnly.empty()); | return (!setWatchOnly.empty()); | ||||
} | } | ||||
static bool ExtractPubKey(const CScript &dest, CPubKey &pubKeyOut) { | static bool ExtractPubKey(const CScript &dest, CPubKey &pubKeyOut) { | ||||
std::vector<std::vector<uint8_t>> solutions; | std::vector<std::vector<uint8_t>> solutions; | ||||
return Solver(dest, solutions) == TX_PUBKEY && | return Solver(dest, solutions) == TX_PUBKEY && | ||||
(pubKeyOut = CPubKey(solutions[0])).IsFullyValid(); | (pubKeyOut = CPubKey(solutions[0])).IsFullyValid(); | ||||
} | } | ||||
bool CWallet::RemoveWatchOnly(const CScript &dest) { | bool LegacyScriptPubKeyMan::RemoveWatchOnly(const CScript &dest) { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
{ | { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
setWatchOnly.erase(dest); | setWatchOnly.erase(dest); | ||||
CPubKey pubKey; | CPubKey pubKey; | ||||
if (ExtractPubKey(dest, pubKey)) { | if (ExtractPubKey(dest, pubKey)) { | ||||
mapWatchKeys.erase(pubKey.GetID()); | mapWatchKeys.erase(pubKey.GetID()); | ||||
} | } | ||||
} | } | ||||
if (!HaveWatchOnly()) { | if (!HaveWatchOnly()) { | ||||
NotifyWatchonlyChanged(false); | NotifyWatchonlyChanged(false); | ||||
} | } | ||||
return WalletBatch(*database).EraseWatchOnly(dest); | return WalletBatch(m_storage.GetDatabase()).EraseWatchOnly(dest); | ||||
} | } | ||||
bool CWallet::LoadWatchOnly(const CScript &dest) { | bool LegacyScriptPubKeyMan::LoadWatchOnly(const CScript &dest) { | ||||
return AddWatchOnlyInMem(dest); | return AddWatchOnlyInMem(dest); | ||||
} | } | ||||
bool CWallet::AddWatchOnlyInMem(const CScript &dest) { | bool LegacyScriptPubKeyMan::AddWatchOnlyInMem(const CScript &dest) { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
setWatchOnly.insert(dest); | setWatchOnly.insert(dest); | ||||
CPubKey pubKey; | CPubKey pubKey; | ||||
if (ExtractPubKey(dest, pubKey)) { | if (ExtractPubKey(dest, pubKey)) { | ||||
mapWatchKeys[pubKey.GetID()] = pubKey; | mapWatchKeys[pubKey.GetID()] = pubKey; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest) { | bool LegacyScriptPubKeyMan::AddWatchOnlyWithDB(WalletBatch &batch, | ||||
const CScript &dest) { | |||||
if (!AddWatchOnlyInMem(dest)) { | if (!AddWatchOnlyInMem(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); | ||||
if (batch.WriteWatchOnly(dest, meta)) { | if (batch.WriteWatchOnly(dest, meta)) { | ||||
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | m_storage.UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest, | bool LegacyScriptPubKeyMan::AddWatchOnlyWithDB(WalletBatch &batch, | ||||
const CScript &dest, | |||||
int64_t create_time) { | int64_t create_time) { | ||||
m_script_metadata[CScriptID(dest)].nCreateTime = create_time; | m_script_metadata[CScriptID(dest)].nCreateTime = create_time; | ||||
return AddWatchOnlyWithDB(batch, dest); | return AddWatchOnlyWithDB(batch, dest); | ||||
} | } | ||||
bool CWallet::AddWatchOnly(const CScript &dest) { | bool LegacyScriptPubKeyMan::AddWatchOnly(const CScript &dest) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
return AddWatchOnlyWithDB(batch, dest); | return AddWatchOnlyWithDB(batch, dest); | ||||
} | } | ||||
bool CWallet::AddWatchOnly(const CScript &dest, int64_t nCreateTime) { | bool LegacyScriptPubKeyMan::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); | ||||
} | } | ||||
void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | void LegacyScriptPubKeyMan::SetHDChain(const CHDChain &chain, bool memonly) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (!memonly && !WalletBatch(*database).WriteHDChain(chain)) { | if (!memonly && !WalletBatch(m_storage.GetDatabase()).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::HaveKey(const CKeyID &address) const { | bool LegacyScriptPubKeyMan::HaveKey(const CKeyID &address) const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
return FillableSigningProvider::HaveKey(address); | return FillableSigningProvider::HaveKey(address); | ||||
} | } | ||||
return mapCryptedKeys.count(address) > 0; | return mapCryptedKeys.count(address) > 0; | ||||
} | } | ||||
bool CWallet::GetKey(const CKeyID &address, CKey &keyOut) const { | bool LegacyScriptPubKeyMan::GetKey(const CKeyID &address, CKey &keyOut) const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
return FillableSigningProvider::GetKey(address, keyOut); | return FillableSigningProvider::GetKey(address, keyOut); | ||||
} | } | ||||
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); | CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); | ||||
if (mi != mapCryptedKeys.end()) { | if (mi != mapCryptedKeys.end()) { | ||||
const CPubKey &vchPubKey = (*mi).second.first; | const CPubKey &vchPubKey = (*mi).second.first; | ||||
const std::vector<uint8_t> &vchCryptedSecret = (*mi).second.second; | const std::vector<uint8_t> &vchCryptedSecret = (*mi).second.second; | ||||
return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut); | return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut); | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::GetKeyOrigin(const CKeyID &keyID, KeyOriginInfo &info) const { | bool LegacyScriptPubKeyMan::GetKeyOrigin(const CKeyID &keyID, | ||||
KeyOriginInfo &info) const { | |||||
CKeyMetadata meta; | CKeyMetadata meta; | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
auto it = mapKeyMetadata.find(keyID); | auto it = mapKeyMetadata.find(keyID); | ||||
if (it != mapKeyMetadata.end()) { | if (it != mapKeyMetadata.end()) { | ||||
meta = it->second; | meta = it->second; | ||||
} | } | ||||
} | } | ||||
if (meta.has_key_origin) { | if (meta.has_key_origin) { | ||||
std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, | std::copy(meta.key_origin.fingerprint, meta.key_origin.fingerprint + 4, | ||||
info.fingerprint); | info.fingerprint); | ||||
info.path = meta.key_origin.path; | info.path = meta.key_origin.path; | ||||
} else { | } else { | ||||
// Single pubkeys get the master fingerprint of themselves | // Single pubkeys get the master fingerprint of themselves | ||||
std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); | std::copy(keyID.begin(), keyID.begin() + 4, info.fingerprint); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const { | bool LegacyScriptPubKeyMan::GetWatchPubKey(const CKeyID &address, | ||||
CPubKey &pubkey_out) const { | |||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
WatchKeyMap::const_iterator it = mapWatchKeys.find(address); | WatchKeyMap::const_iterator it = mapWatchKeys.find(address); | ||||
if (it != mapWatchKeys.end()) { | if (it != mapWatchKeys.end()) { | ||||
pubkey_out = it->second; | pubkey_out = it->second; | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const { | bool LegacyScriptPubKeyMan::GetPubKey(const CKeyID &address, | ||||
CPubKey &vchPubKeyOut) const { | |||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) { | if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) { | ||||
return GetWatchPubKey(address, vchPubKeyOut); | return GetWatchPubKey(address, vchPubKeyOut); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); | CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); | ||||
if (mi != mapCryptedKeys.end()) { | if (mi != mapCryptedKeys.end()) { | ||||
vchPubKeyOut = (*mi).second.first; | vchPubKeyOut = (*mi).second.first; | ||||
return true; | return true; | ||||
} | } | ||||
// Check for watch-only pubkeys | // Check for watch-only pubkeys | ||||
return GetWatchPubKey(address, vchPubKeyOut); | return GetWatchPubKey(address, vchPubKeyOut); | ||||
} | } | ||||
CPubKey CWallet::GenerateNewKey(WalletBatch &batch, bool internal) { | CPubKey LegacyScriptPubKeyMan::GenerateNewKey(WalletBatch &batch, | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | bool internal) { | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)); | assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | ||||
assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET)); | |||||
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 = m_storage.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 and a seed | // use HD key derivation if HD was enabled during wallet creation and a seed | ||||
// is present | // is present | ||||
if (IsHDEnabled()) { | if (IsHDEnabled()) { | ||||
DeriveNewChildKey( | DeriveNewChildKey( | ||||
batch, metadata, secret, | batch, metadata, secret, | ||||
(CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | (m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false)); | ||||
} else { | } else { | ||||
secret.MakeNewKey(fCompressed); | secret.MakeNewKey(fCompressed); | ||||
} | } | ||||
// Compressed public keys were introduced in version 0.6.0 | // Compressed public keys were introduced in version 0.6.0 | ||||
if (fCompressed) { | if (fCompressed) { | ||||
SetMinVersion(FEATURE_COMPRPUBKEY); | m_storage.SetMinVersion(FEATURE_COMPRPUBKEY); | ||||
} | } | ||||
CPubKey pubkey = secret.GetPubKey(); | CPubKey pubkey = secret.GetPubKey(); | ||||
assert(secret.VerifyPubKey(pubkey)); | assert(secret.VerifyPubKey(pubkey)); | ||||
mapKeyMetadata[pubkey.GetID()] = metadata; | mapKeyMetadata[pubkey.GetID()] = metadata; | ||||
UpdateTimeFirstKey(nCreationTime); | UpdateTimeFirstKey(nCreationTime); | ||||
if (!AddKeyPubKeyWithDB(batch, secret, pubkey)) { | if (!AddKeyPubKeyWithDB(batch, secret, pubkey)) { | ||||
throw std::runtime_error(std::string(__func__) + ": AddKey failed"); | throw std::runtime_error(std::string(__func__) + ": AddKey failed"); | ||||
} | } | ||||
return pubkey; | return pubkey; | ||||
} | } | ||||
const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; | const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; | ||||
void CWallet::DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, | void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, | ||||
CKeyMetadata &metadata, | |||||
CKey &secret, bool internal) { | CKey &secret, bool internal) { | ||||
// for now we use a fixed keypath scheme of m/0'/0'/k | // for now we use a fixed keypath scheme of m/0'/0'/k | ||||
// seed (256bit) | // seed (256bit) | ||||
CKey seed; | CKey seed; | ||||
// hd master key | // hd master key | ||||
CExtKey masterKey; | CExtKey masterKey; | ||||
// key at m/0' | // key at m/0' | ||||
CExtKey accountKey; | CExtKey accountKey; | ||||
// key at m/0'/0' (external) or m/0'/1' (internal) | // key at m/0'/0' (external) or m/0'/1' (internal) | ||||
Show All 9 Lines | void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, | ||||
masterKey.SetSeed(seed.begin(), seed.size()); | masterKey.SetSeed(seed.begin(), seed.size()); | ||||
// derive m/0' | // derive m/0' | ||||
// use hardened derivation (child keys >= 0x80000000 are hardened after | // use hardened derivation (child keys >= 0x80000000 are hardened after | ||||
// bip32) | // bip32) | ||||
masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); | masterKey.Derive(accountKey, BIP32_HARDENED_KEY_LIMIT); | ||||
// derive m/0'/0' (external chain) OR m/0'/1' (internal chain) | // derive m/0'/0' (external chain) OR m/0'/1' (internal chain) | ||||
assert(internal ? CanSupportFeature(FEATURE_HD_SPLIT) : true); | assert(internal ? m_storage.CanSupportFeature(FEATURE_HD_SPLIT) : true); | ||||
accountKey.Derive(chainChildKey, | accountKey.Derive(chainChildKey, | ||||
BIP32_HARDENED_KEY_LIMIT + (internal ? 1 : 0)); | BIP32_HARDENED_KEY_LIMIT + (internal ? 1 : 0)); | ||||
// derive child key at next index, skip keys already known to the wallet | // derive child key at next index, skip keys already known to the wallet | ||||
do { | do { | ||||
// always derive hardened keys | // always derive hardened keys | ||||
// childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened | // childIndex | BIP32_HARDENED_KEY_LIMIT = derive childIndex in hardened | ||||
// child-index-range | // child-index-range | ||||
Show All 30 Lines | void LegacyScriptPubKeyMan::DeriveNewChildKey(WalletBatch &batch, | ||||
metadata.has_key_origin = true; | metadata.has_key_origin = true; | ||||
// update the chain model in the database | // update the chain model in the database | ||||
if (!batch.WriteHDChain(hdChain)) { | if (!batch.WriteHDChain(hdChain)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": Writing HD chain model failed"); | ": Writing HD chain model failed"); | ||||
} | } | ||||
} | } | ||||
void CWallet::LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) { | void LegacyScriptPubKeyMan::LoadKeyPool(int64_t nIndex, | ||||
const CKeyPool &keypool) { | |||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
if (keypool.m_pre_split) { | if (keypool.m_pre_split) { | ||||
set_pre_split_keypool.insert(nIndex); | set_pre_split_keypool.insert(nIndex); | ||||
} else if (keypool.fInternal) { | } else if (keypool.fInternal) { | ||||
setInternalKeyPool.insert(nIndex); | setInternalKeyPool.insert(nIndex); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(nIndex); | setExternalKeyPool.insert(nIndex); | ||||
} | } | ||||
m_max_keypool_index = std::max(m_max_keypool_index, nIndex); | m_max_keypool_index = std::max(m_max_keypool_index, nIndex); | ||||
m_pool_key_to_index[keypool.vchPubKey.GetID()] = nIndex; | m_pool_key_to_index[keypool.vchPubKey.GetID()] = nIndex; | ||||
// If no metadata exists yet, create a default with the pool key's | // If no metadata exists yet, create a default with the pool key's | ||||
// creation time. Note that this may be overwritten by actually | // creation time. Note that this may be overwritten by actually | ||||
// 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::CanGenerateKeys() { | bool LegacyScriptPubKeyMan::CanGenerateKeys() { | ||||
// A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a | // A wallet can generate keys if it has an HD seed (IsHDEnabled) or it is a | ||||
// non-HD wallet (pre FEATURE_HD) | // non-HD wallet (pre FEATURE_HD) | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
return IsHDEnabled() || !CanSupportFeature(FEATURE_HD); | return IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD); | ||||
} | } | ||||
CPubKey CWallet::GenerateNewSeed() { | CPubKey LegacyScriptPubKeyMan::GenerateNewSeed() { | ||||
assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); | ||||
CKey key; | CKey key; | ||||
key.MakeNewKey(true); | key.MakeNewKey(true); | ||||
return DeriveNewSeed(key); | return DeriveNewSeed(key); | ||||
} | } | ||||
CPubKey CWallet::DeriveNewSeed(const CKey &key) { | CPubKey LegacyScriptPubKeyMan::DeriveNewSeed(const CKey &key) { | ||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | CKeyMetadata metadata(nCreationTime); | ||||
// Calculate the seed | // Calculate the seed | ||||
CPubKey seed = key.GetPubKey(); | CPubKey seed = key.GetPubKey(); | ||||
assert(key.VerifyPubKey(seed)); | assert(key.VerifyPubKey(seed)); | ||||
// Set the hd keypath to "s" -> Seed, refers the seed to itself | // Set the hd keypath to "s" -> Seed, refers the seed to itself | ||||
Show All 10 Lines | CPubKey LegacyScriptPubKeyMan::DeriveNewSeed(const CKey &key) { | ||||
if (!AddKeyPubKey(key, seed)) { | if (!AddKeyPubKey(key, seed)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": AddKeyPubKey failed"); | ": AddKeyPubKey failed"); | ||||
} | } | ||||
return seed; | return seed; | ||||
} | } | ||||
void CWallet::SetHDSeed(const CPubKey &seed) { | void LegacyScriptPubKeyMan::SetHDSeed(const CPubKey &seed) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// Store the keyid (hash160) together with the child index counter in the | // Store the keyid (hash160) together with the child index counter in the | ||||
// database as a hdchain object. | // database as a hdchain object. | ||||
CHDChain newHdChain; | CHDChain newHdChain; | ||||
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) | newHdChain.nVersion = m_storage.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); | m_wallet.UnsetWalletFlag(WALLET_FLAG_BLANK_WALLET); | ||||
} | } | ||||
/** | /** | ||||
* Mark old keypool keys as used, and generate all new keys. | * Mark old keypool keys as used, and generate all new keys. | ||||
*/ | */ | ||||
bool CWallet::NewKeyPool() { | bool LegacyScriptPubKeyMan::NewKeyPool() { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
return false; | return false; | ||||
} | } | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (const int64_t nIndex : setInternalKeyPool) { | for (const int64_t nIndex : setInternalKeyPool) { | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
} | } | ||||
setInternalKeyPool.clear(); | setInternalKeyPool.clear(); | ||||
for (const int64_t nIndex : setExternalKeyPool) { | for (const int64_t nIndex : setExternalKeyPool) { | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
} | } | ||||
setExternalKeyPool.clear(); | setExternalKeyPool.clear(); | ||||
for (int64_t nIndex : set_pre_split_keypool) { | for (int64_t nIndex : set_pre_split_keypool) { | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
} | } | ||||
set_pre_split_keypool.clear(); | set_pre_split_keypool.clear(); | ||||
m_pool_key_to_index.clear(); | m_pool_key_to_index.clear(); | ||||
if (!TopUpKeyPool()) { | if (!TopUpKeyPool()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletLogPrintf("CWallet::NewKeyPool rewrote keypool\n"); | WalletLogPrintf("LegacyScriptPubKeyMan::NewKeyPool rewrote keypool\n"); | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::TopUpKeyPool(unsigned int kpSize) { | bool LegacyScriptPubKeyMan::TopUpKeyPool(unsigned int kpSize) { | ||||
if (!CanGenerateKeys()) { | if (!CanGenerateKeys()) { | ||||
return false; | return false; | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (IsLocked()) { | if (m_storage.IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Top up key pool | // Top up key pool | ||||
unsigned int nTargetSize; | unsigned int nTargetSize; | ||||
if (kpSize > 0) { | if (kpSize > 0) { | ||||
nTargetSize = kpSize; | nTargetSize = kpSize; | ||||
} else { | } else { | ||||
nTargetSize = std::max<int64_t>( | nTargetSize = std::max<int64_t>( | ||||
gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), 0); | gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE), 0); | ||||
} | } | ||||
// count amount of available keys (internal, external) | // count amount of available keys (internal, external) | ||||
// make sure the keypool of external and internal keys fits the user | // make sure the keypool of external and internal keys fits the user | ||||
// selected target (-keypool) | // selected target (-keypool) | ||||
int64_t missingExternal = std::max<int64_t>( | int64_t missingExternal = std::max<int64_t>( | ||||
std::max<int64_t>(nTargetSize, 1) - setExternalKeyPool.size(), 0); | std::max<int64_t>(nTargetSize, 1) - setExternalKeyPool.size(), 0); | ||||
int64_t missingInternal = std::max<int64_t>( | int64_t missingInternal = std::max<int64_t>( | ||||
std::max<int64_t>(nTargetSize, 1) - setInternalKeyPool.size(), 0); | std::max<int64_t>(nTargetSize, 1) - setInternalKeyPool.size(), 0); | ||||
if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT)) { | if (!IsHDEnabled() || !m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) { | ||||
// don't create extra internal keys | // don't create extra internal keys | ||||
missingInternal = 0; | missingInternal = 0; | ||||
} | } | ||||
bool internal = false; | bool internal = false; | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (int64_t i = missingInternal + missingExternal; i--;) { | for (int64_t i = missingInternal + missingExternal; i--;) { | ||||
if (i < missingInternal) { | if (i < missingInternal) { | ||||
internal = true; | internal = true; | ||||
} | } | ||||
CPubKey pubkey(GenerateNewKey(batch, internal)); | CPubKey pubkey(GenerateNewKey(batch, internal)); | ||||
AddKeypoolPubkeyWithDB(pubkey, internal, batch); | AddKeypoolPubkeyWithDB(pubkey, internal, batch); | ||||
} | } | ||||
if (missingInternal + missingExternal > 0) { | if (missingInternal + missingExternal > 0) { | ||||
WalletLogPrintf( | WalletLogPrintf( | ||||
"keypool added %d keys (%d internal), size=%u (%u internal)\n", | "keypool added %d keys (%d internal), size=%u (%u internal)\n", | ||||
missingInternal + missingExternal, missingInternal, | missingInternal + missingExternal, missingInternal, | ||||
setInternalKeyPool.size() + setExternalKeyPool.size() + | setInternalKeyPool.size() + setExternalKeyPool.size() + | ||||
set_pre_split_keypool.size(), | set_pre_split_keypool.size(), | ||||
setInternalKeyPool.size()); | setInternalKeyPool.size()); | ||||
} | } | ||||
} | } | ||||
NotifyCanGetAddressesChanged(); | NotifyCanGetAddressesChanged(); | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::AddKeypoolPubkeyWithDB(const CPubKey &pubkey, const bool internal, | void LegacyScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey &pubkey, | ||||
const bool internal, | |||||
WalletBatch &batch) { | WalletBatch &batch) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
// How in the hell did you use so many keys? | // How in the hell did you use so many keys? | ||||
assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | assert(m_max_keypool_index < std::numeric_limits<int64_t>::max()); | ||||
int64_t index = ++m_max_keypool_index; | int64_t index = ++m_max_keypool_index; | ||||
if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | if (!batch.WritePool(index, CKeyPool(pubkey, internal))) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing imported pubkey failed"); | ": writing imported pubkey failed"); | ||||
} | } | ||||
if (internal) { | if (internal) { | ||||
setInternalKeyPool.insert(index); | setInternalKeyPool.insert(index); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(index); | setExternalKeyPool.insert(index); | ||||
} | } | ||||
m_pool_key_to_index[pubkey.GetID()] = index; | m_pool_key_to_index[pubkey.GetID()] = index; | ||||
} | } | ||||
void CWallet::KeepKey(int64_t nIndex) { | void LegacyScriptPubKeyMan::KeepKey(int64_t nIndex) { | ||||
// Remove from key pool. | // Remove from key pool. | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
WalletLogPrintf("keypool keep %d\n", nIndex); | WalletLogPrintf("keypool keep %d\n", nIndex); | ||||
} | } | ||||
void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey &pubkey) { | void LegacyScriptPubKeyMan::ReturnKey(int64_t nIndex, bool fInternal, | ||||
const CPubKey &pubkey) { | |||||
// Return to key pool | // Return to key pool | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (fInternal) { | if (fInternal) { | ||||
setInternalKeyPool.insert(nIndex); | setInternalKeyPool.insert(nIndex); | ||||
} else if (!set_pre_split_keypool.empty()) { | } else if (!set_pre_split_keypool.empty()) { | ||||
set_pre_split_keypool.insert(nIndex); | set_pre_split_keypool.insert(nIndex); | ||||
} else { | } else { | ||||
setExternalKeyPool.insert(nIndex); | setExternalKeyPool.insert(nIndex); | ||||
} | } | ||||
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 LegacyScriptPubKeyMan::GetKeyFromPool(CPubKey &result, bool internal) { | ||||
if (!CanGetAddresses(internal)) { | 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) && | ||||
!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | !m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
if (IsLocked()) { | if (m_storage.IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
result = GenerateNewKey(batch, internal); | result = GenerateNewKey(batch, internal); | ||||
return true; | return true; | ||||
} | } | ||||
KeepKey(nIndex); | KeepKey(nIndex); | ||||
result = keypool.vchPubKey; | result = keypool.vchPubKey; | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, | bool LegacyScriptPubKeyMan::ReserveKeyFromKeyPool(int64_t &nIndex, | ||||
CKeyPool &keypool, | |||||
bool fRequestedInternal) { | bool fRequestedInternal) { | ||||
nIndex = -1; | nIndex = -1; | ||||
keypool.vchPubKey = CPubKey(); | keypool.vchPubKey = CPubKey(); | ||||
{ | { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
TopUpKeyPool(); | TopUpKeyPool(); | ||||
bool fReturningInternal = fRequestedInternal; | bool fReturningInternal = fRequestedInternal; | ||||
fReturningInternal &= | fReturningInternal &= | ||||
(IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) || | (IsHDEnabled() && m_storage.CanSupportFeature(FEATURE_HD_SPLIT)) || | ||||
IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | ||||
bool use_split_keypool = set_pre_split_keypool.empty(); | bool use_split_keypool = set_pre_split_keypool.empty(); | ||||
std::set<int64_t> &setKeyPool = | std::set<int64_t> &setKeyPool = | ||||
use_split_keypool | use_split_keypool | ||||
? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) | ? (fReturningInternal ? setInternalKeyPool : setExternalKeyPool) | ||||
: set_pre_split_keypool; | : set_pre_split_keypool; | ||||
// Get the oldest key | // Get the oldest key | ||||
if (setKeyPool.empty()) { | if (setKeyPool.empty()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
auto it = setKeyPool.begin(); | auto it = setKeyPool.begin(); | ||||
nIndex = *it; | nIndex = *it; | ||||
setKeyPool.erase(it); | setKeyPool.erase(it); | ||||
if (!batch.ReadPool(nIndex, keypool)) { | if (!batch.ReadPool(nIndex, keypool)) { | ||||
throw std::runtime_error(std::string(__func__) + ": read failed"); | throw std::runtime_error(std::string(__func__) + ": read failed"); | ||||
} | } | ||||
CPubKey pk; | CPubKey pk; | ||||
Show All 13 Lines | keypool.vchPubKey = CPubKey(); | ||||
m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); | m_pool_key_to_index.erase(keypool.vchPubKey.GetID()); | ||||
WalletLogPrintf("keypool reserve %d\n", nIndex); | WalletLogPrintf("keypool reserve %d\n", nIndex); | ||||
} | } | ||||
NotifyCanGetAddressesChanged(); | NotifyCanGetAddressesChanged(); | ||||
return true; | return true; | ||||
} | } | ||||
void CWallet::LearnRelatedScripts(const CPubKey &key, OutputType type) { | void LegacyScriptPubKeyMan::LearnRelatedScripts(const CPubKey &key, | ||||
OutputType type) { | |||||
// Nothing to do... | // Nothing to do... | ||||
} | } | ||||
void CWallet::LearnAllRelatedScripts(const CPubKey &key) { | void LegacyScriptPubKeyMan::LearnAllRelatedScripts(const CPubKey &key) { | ||||
// Nothing to do... | // Nothing to do... | ||||
} | } | ||||
void CWallet::MarkReserveKeysAsUsed(int64_t keypool_id) { | void LegacyScriptPubKeyMan::MarkReserveKeysAsUsed(int64_t keypool_id) { | ||||
AssertLockHeld(cs_wallet); | AssertLockHeld(cs_wallet); | ||||
bool internal = setInternalKeyPool.count(keypool_id); | bool internal = setInternalKeyPool.count(keypool_id); | ||||
if (!internal) { | if (!internal) { | ||||
assert(setExternalKeyPool.count(keypool_id) || | assert(setExternalKeyPool.count(keypool_id) || | ||||
set_pre_split_keypool.count(keypool_id)); | set_pre_split_keypool.count(keypool_id)); | ||||
} | } | ||||
std::set<int64_t> *setKeyPool = | std::set<int64_t> *setKeyPool = | ||||
internal ? &setInternalKeyPool | internal ? &setInternalKeyPool | ||||
: (set_pre_split_keypool.empty() ? &setExternalKeyPool | : (set_pre_split_keypool.empty() ? &setExternalKeyPool | ||||
: &set_pre_split_keypool); | : &set_pre_split_keypool); | ||||
auto it = setKeyPool->begin(); | auto it = setKeyPool->begin(); | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
while (it != std::end(*setKeyPool)) { | while (it != std::end(*setKeyPool)) { | ||||
const int64_t &index = *(it); | const int64_t &index = *(it); | ||||
if (index > keypool_id) { | if (index > keypool_id) { | ||||
// set*KeyPool is ordered | // set*KeyPool is ordered | ||||
break; | break; | ||||
} | } | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
Show All 16 Lines | InferDescriptor(spk, provider) | ||||
->Expand(0, DUMMY_SIGNING_PROVIDER, dummy, out); | ->Expand(0, DUMMY_SIGNING_PROVIDER, dummy, out); | ||||
std::vector<CKeyID> ret; | std::vector<CKeyID> ret; | ||||
for (const auto &entry : out.pubkeys) { | for (const auto &entry : out.pubkeys) { | ||||
ret.push_back(entry.first); | ret.push_back(entry.first); | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
void CWallet::MarkPreSplitKeys() { | void LegacyScriptPubKeyMan::MarkPreSplitKeys() { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (auto it = setExternalKeyPool.begin(); | for (auto it = setExternalKeyPool.begin(); | ||||
it != setExternalKeyPool.end();) { | it != setExternalKeyPool.end();) { | ||||
int64_t index = *it; | int64_t index = *it; | ||||
CKeyPool keypool; | CKeyPool keypool; | ||||
if (!batch.ReadPool(index, keypool)) { | if (!batch.ReadPool(index, keypool)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": read keypool entry failed"); | ": read keypool entry failed"); | ||||
} | } | ||||
keypool.m_pre_split = true; | keypool.m_pre_split = true; | ||||
if (!batch.WritePool(index, keypool)) { | if (!batch.WritePool(index, keypool)) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": writing modified keypool entry failed"); | ": writing modified keypool entry failed"); | ||||
} | } | ||||
set_pre_split_keypool.insert(index); | set_pre_split_keypool.insert(index); | ||||
it = setExternalKeyPool.erase(it); | it = setExternalKeyPool.erase(it); | ||||
} | } | ||||
} | } | ||||
bool CWallet::AddCScript(const CScript &redeemScript) { | bool LegacyScriptPubKeyMan::AddCScript(const CScript &redeemScript) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
return AddCScriptWithDB(batch, redeemScript); | return AddCScriptWithDB(batch, redeemScript); | ||||
} | } | ||||
bool CWallet::AddCScriptWithDB(WalletBatch &batch, | bool LegacyScriptPubKeyMan::AddCScriptWithDB(WalletBatch &batch, | ||||
const CScript &redeemScript) { | const CScript &redeemScript) { | ||||
if (!FillableSigningProvider::AddCScript(redeemScript)) { | if (!FillableSigningProvider::AddCScript(redeemScript)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { | if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { | ||||
UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | m_storage.UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
bool CWallet::AddKeyOriginWithDB(WalletBatch &batch, const CPubKey &pubkey, | bool LegacyScriptPubKeyMan::AddKeyOriginWithDB(WalletBatch &batch, | ||||
const CPubKey &pubkey, | |||||
const KeyOriginInfo &info) { | const KeyOriginInfo &info) { | ||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
std::copy(info.fingerprint, info.fingerprint + 4, | std::copy(info.fingerprint, info.fingerprint + 4, | ||||
mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint); | mapKeyMetadata[pubkey.GetID()].key_origin.fingerprint); | ||||
mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path; | mapKeyMetadata[pubkey.GetID()].key_origin.path = info.path; | ||||
mapKeyMetadata[pubkey.GetID()].has_key_origin = true; | mapKeyMetadata[pubkey.GetID()].has_key_origin = true; | ||||
mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); | mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); | ||||
return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); | return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); | ||||
} | } | ||||
bool CWallet::ImportScripts(const std::set<CScript> scripts, | bool LegacyScriptPubKeyMan::ImportScripts(const std::set<CScript> scripts, | ||||
int64_t timestamp) { | int64_t timestamp) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (const auto &entry : scripts) { | for (const auto &entry : scripts) { | ||||
CScriptID id(entry); | CScriptID id(entry); | ||||
if (HaveCScript(id)) { | if (HaveCScript(id)) { | ||||
WalletLogPrintf("Already have script %s, skipping\n", | WalletLogPrintf("Already have script %s, skipping\n", | ||||
HexStr(entry)); | HexStr(entry)); | ||||
continue; | continue; | ||||
} | } | ||||
if (!AddCScriptWithDB(batch, entry)) { | if (!AddCScriptWithDB(batch, entry)) { | ||||
return false; | return false; | ||||
} | } | ||||
if (timestamp > 0) { | if (timestamp > 0) { | ||||
m_script_metadata[CScriptID(entry)].nCreateTime = timestamp; | m_script_metadata[CScriptID(entry)].nCreateTime = timestamp; | ||||
} | } | ||||
} | } | ||||
if (timestamp > 0) { | if (timestamp > 0) { | ||||
UpdateTimeFirstKey(timestamp); | UpdateTimeFirstKey(timestamp); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey> &privkey_map, | bool LegacyScriptPubKeyMan::ImportPrivKeys( | ||||
const int64_t timestamp) { | const std::map<CKeyID, CKey> &privkey_map, const int64_t timestamp) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (const auto &entry : privkey_map) { | for (const auto &entry : privkey_map) { | ||||
const CKey &key = entry.second; | const CKey &key = entry.second; | ||||
CPubKey pubkey = key.GetPubKey(); | CPubKey pubkey = key.GetPubKey(); | ||||
const CKeyID &id = entry.first; | const CKeyID &id = entry.first; | ||||
assert(key.VerifyPubKey(pubkey)); | assert(key.VerifyPubKey(pubkey)); | ||||
// Skip if we already have the key | // Skip if we already have the key | ||||
if (HaveKey(id)) { | if (HaveKey(id)) { | ||||
WalletLogPrintf("Already have key with pubkey %s, skipping\n", | WalletLogPrintf("Already have key with pubkey %s, skipping\n", | ||||
HexStr(pubkey)); | HexStr(pubkey)); | ||||
continue; | continue; | ||||
} | } | ||||
mapKeyMetadata[id].nCreateTime = timestamp; | mapKeyMetadata[id].nCreateTime = timestamp; | ||||
// If the private key is not present in the wallet, insert it. | // If the private key is not present in the wallet, insert it. | ||||
if (!AddKeyPubKeyWithDB(batch, key, pubkey)) { | if (!AddKeyPubKeyWithDB(batch, key, pubkey)) { | ||||
return false; | return false; | ||||
} | } | ||||
UpdateTimeFirstKey(timestamp); | UpdateTimeFirstKey(timestamp); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::ImportPubKeys( | bool LegacyScriptPubKeyMan::ImportPubKeys( | ||||
const std::vector<CKeyID> &ordered_pubkeys, | const std::vector<CKeyID> &ordered_pubkeys, | ||||
const std::map<CKeyID, CPubKey> &pubkey_map, | const std::map<CKeyID, CPubKey> &pubkey_map, | ||||
const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> &key_origins, | const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> &key_origins, | ||||
const bool add_keypool, const bool internal, const int64_t timestamp) { | const bool add_keypool, const bool internal, const int64_t timestamp) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (const auto &entry : key_origins) { | for (const auto &entry : key_origins) { | ||||
AddKeyOriginWithDB(batch, entry.second.first, entry.second.second); | AddKeyOriginWithDB(batch, entry.second.first, entry.second.second); | ||||
} | } | ||||
for (const CKeyID &id : ordered_pubkeys) { | for (const CKeyID &id : ordered_pubkeys) { | ||||
auto entry = pubkey_map.find(id); | auto entry = pubkey_map.find(id); | ||||
if (entry == pubkey_map.end()) { | if (entry == pubkey_map.end()) { | ||||
continue; | continue; | ||||
} | } | ||||
Show All 14 Lines | for (const CKeyID &id : ordered_pubkeys) { | ||||
if (add_keypool) { | if (add_keypool) { | ||||
AddKeypoolPubkeyWithDB(pubkey, internal, batch); | AddKeypoolPubkeyWithDB(pubkey, internal, batch); | ||||
NotifyCanGetAddressesChanged(); | NotifyCanGetAddressesChanged(); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CWallet::ImportScriptPubKeys(const std::string &label, | bool LegacyScriptPubKeyMan::ImportScriptPubKeys( | ||||
const std::set<CScript> &script_pub_keys, | const std::string &label, const std::set<CScript> &script_pub_keys, | ||||
const bool have_solving_data, | const bool have_solving_data, const bool apply_label, | ||||
const bool apply_label, | |||||
const int64_t timestamp) { | const int64_t timestamp) { | ||||
WalletBatch batch(*database); | WalletBatch batch(m_storage.GetDatabase()); | ||||
for (const CScript &script : script_pub_keys) { | for (const CScript &script : script_pub_keys) { | ||||
if (!have_solving_data || !::IsMine(*this, script)) { | if (!have_solving_data || !IsMine(script)) { | ||||
// Always call AddWatchOnly for non-solvable watch-only, so that | // Always call AddWatchOnly for non-solvable watch-only, so that | ||||
// watch timestamp gets updated | // watch timestamp gets updated | ||||
if (!AddWatchOnlyWithDB(batch, script, timestamp)) { | if (!AddWatchOnlyWithDB(batch, script, timestamp)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
CTxDestination dest; | CTxDestination dest; | ||||
ExtractDestination(script, dest); | ExtractDestination(script, dest); | ||||
if (apply_label && IsValidDestination(dest)) { | if (apply_label && IsValidDestination(dest)) { | ||||
SetAddressBookWithDB(batch, dest, label, "receive"); | m_wallet.SetAddressBookWithDB(batch, dest, label, "receive"); | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
std::set<CKeyID> CWallet::GetKeys() const { | std::set<CKeyID> LegacyScriptPubKeyMan::GetKeys() const { | ||||
LOCK(cs_KeyStore); | LOCK(cs_KeyStore); | ||||
if (!IsCrypted()) { | if (!IsCrypted()) { | ||||
return FillableSigningProvider::GetKeys(); | return FillableSigningProvider::GetKeys(); | ||||
} | } | ||||
std::set<CKeyID> set_address; | std::set<CKeyID> set_address; | ||||
for (const auto &mi : mapCryptedKeys) { | for (const auto &mi : mapCryptedKeys) { | ||||
set_address.insert(mi.first); | set_address.insert(mi.first); | ||||
} | } | ||||
return set_address; | return set_address; | ||||
} | } | ||||
// Temporary CWallet accessors and aliases. | |||||
LegacyScriptPubKeyMan::LegacyScriptPubKeyMan(CWallet &wallet) | |||||
: ScriptPubKeyMan(wallet), m_wallet(wallet), cs_wallet(wallet.cs_wallet), | |||||
vMasterKey(wallet.vMasterKey), fUseCrypto(wallet.fUseCrypto), | |||||
fDecryptionThoroughlyChecked(wallet.fDecryptionThoroughlyChecked) {} | |||||
bool LegacyScriptPubKeyMan::SetCrypted() { | |||||
return m_wallet.SetCrypted(); | |||||
} | |||||
bool LegacyScriptPubKeyMan::IsCrypted() const { | |||||
return m_wallet.IsCrypted(); | |||||
} | |||||
void LegacyScriptPubKeyMan::NotifyWatchonlyChanged(bool fHaveWatchOnly) const { | |||||
return m_wallet.NotifyWatchonlyChanged(fHaveWatchOnly); | |||||
} | |||||
void LegacyScriptPubKeyMan::NotifyCanGetAddressesChanged() const { | |||||
return m_wallet.NotifyCanGetAddressesChanged(); | |||||
} | |||||
template <typename... Params> | |||||
void LegacyScriptPubKeyMan::WalletLogPrintf( | |||||
const std::string &fmt, const Params &... parameters) const { | |||||
return m_wallet.WalletLogPrintf(fmt, parameters...); | |||||
} |