Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
Show First 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | const CWalletTx *CWallet::GetWalletTx(const TxId &txid) const { | ||||
if (it == mapWallet.end()) { | 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)); | |||||
// 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 | ||||
▲ Show 20 Lines • Show All 1,371 Lines • ▼ Show 20 Lines | for (const CTxOut &txout : tx.vout) { | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
return nChange; | return nChange; | ||||
} | } | ||||
CPubKey CWallet::GenerateNewSeed() { | CPubKey CWallet::GenerateNewSeed() { | ||||
assert(!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 CWallet::DeriveNewSeed(const CKey &key) { | ||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | CKeyMetadata metadata(nCreationTime); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | void CWallet::SetHDChain(const CHDChain &chain, bool memonly) { | ||||
hdChain = chain; | hdChain = chain; | ||||
} | } | ||||
bool CWallet::IsHDEnabled() const { | bool CWallet::IsHDEnabled() const { | ||||
return !hdChain.seed_id.IsNull(); | return !hdChain.seed_id.IsNull(); | ||||
} | } | ||||
void CWallet::SetWalletFlag(uint64_t flags) { | |||||
LOCK(cs_wallet); | |||||
m_wallet_flags |= flags; | |||||
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); | |||||
} | |||||
bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly) { | |||||
LOCK(cs_wallet); | |||||
m_wallet_flags = overwriteFlags; | |||||
if (((overwriteFlags & g_known_wallet_flags) >> 32) ^ | |||||
(overwriteFlags >> 32)) { | |||||
// contains unknown non-tolerable wallet flags | |||||
return false; | |||||
} | |||||
if (!memonly && !WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) { | |||||
throw std::runtime_error(std::string(__func__) + | |||||
": writing wallet flags failed"); | |||||
} | |||||
return true; | |||||
} | |||||
int64_t CWalletTx::GetTxTime() const { | int64_t CWalletTx::GetTxTime() const { | ||||
int64_t n = nTimeSmart; | int64_t n = nTimeSmart; | ||||
return n ? n : nTimeReceived; | return n ? n : nTimeReceived; | ||||
} | } | ||||
// Helper for producing a max-sized low-S low-R signature (eg 71 bytes) | // Helper for producing a max-sized low-S low-R signature (eg 71 bytes) | ||||
// or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true | // or a max-sized low-S signature (e.g. 72 bytes) if use_max_sig is true | ||||
bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, | bool CWallet::DummySignInput(CTxIn &tx_in, const CTxOut &txout, | ||||
▲ Show 20 Lines • Show All 1,378 Lines • ▼ Show 20 Lines | assert(txNew.nLockTime < LOCKTIME_THRESHOLD); | ||||
// The drawback is that by not reusing a previous key, the | // The drawback is that by not reusing a previous key, the | ||||
// change may be lost if a backup is restored, if the backup | // change may be lost if a backup is restored, if the backup | ||||
// doesn't have the new private key for the change. If we | // doesn't have the new private key for the change. If we | ||||
// reused the old key, it would be possible to add code to look | // reused the old key, it would be possible to add code to look | ||||
// for and rediscover unknown transactions that were written | // for and rediscover unknown transactions that were written | ||||
// with keys of ours to recover post-backup change. | // with keys of ours to recover post-backup change. | ||||
// Reserve a new key pair from key pool | // 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."); | |||||
return false; | |||||
} | |||||
CPubKey vchPubKey; | CPubKey vchPubKey; | ||||
bool ret; | bool ret; | ||||
ret = reservekey.GetReservedKey(vchPubKey, true); | ret = reservekey.GetReservedKey(vchPubKey, true); | ||||
if (!ret) { | if (!ret) { | ||||
strFailReason = | strFailReason = | ||||
_("Keypool ran out, please call keypoolrefill first"); | _("Keypool ran out, please call keypoolrefill first"); | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 415 Lines • ▼ Show 20 Lines | if (nLoadWalletRet == DBErrors::NEED_REWRITE) { | ||||
} | } | ||||
} | } | ||||
{ | { | ||||
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); | |||||
} | } | ||||
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 112 Lines • ▼ Show 20 Lines | const std::string &CWallet::GetLabelName(const CScript &scriptPubKey) const { | ||||
const static std::string DEFAULT_LABEL_NAME; | const static std::string DEFAULT_LABEL_NAME; | ||||
return DEFAULT_LABEL_NAME; | return DEFAULT_LABEL_NAME; | ||||
} | } | ||||
/** | /** | ||||
* 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 CWallet::NewKeyPool() { | ||||
if (IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | |||||
return false; | |||||
} | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
for (const int64_t nIndex : setInternalKeyPool) { | for (const int64_t nIndex : setInternalKeyPool) { | ||||
batch.ErasePool(nIndex); | batch.ErasePool(nIndex); | ||||
} | } | ||||
setInternalKeyPool.clear(); | setInternalKeyPool.clear(); | ||||
Show All 40 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)) { | |||||
return false; | |||||
} | |||||
LOCK(cs_wallet); | LOCK(cs_wallet); | ||||
if (IsLocked()) { | if (IsLocked()) { | ||||
return false; | return false; | ||||
} | } | ||||
// Top up key pool | // Top up key pool | ||||
unsigned int nTargetSize; | unsigned int nTargetSize; | ||||
▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | // Return to key pool | ||||
} | } | ||||
m_pool_key_to_index[pubkey.GetID()] = nIndex; | m_pool_key_to_index[pubkey.GetID()] = nIndex; | ||||
} | } | ||||
LogPrintf("keypool return %d\n", nIndex); | LogPrintf("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)) { | |||||
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()) { | ||||
return false; | return false; | ||||
} | } | ||||
WalletBatch batch(*database); | WalletBatch batch(*database); | ||||
▲ Show 20 Lines • Show All 593 Lines • ▼ Show 20 Lines | for (auto it = setExternalKeyPool.begin(); | ||||
} | } | ||||
set_pre_split_keypool.insert(index); | set_pre_split_keypool.insert(index); | ||||
it = setExternalKeyPool.erase(it); | it = setExternalKeyPool.erase(it); | ||||
} | } | ||||
} | } | ||||
std::shared_ptr<CWallet> | std::shared_ptr<CWallet> | ||||
CWallet::CreateWalletFromFile(const CChainParams &chainParams, | CWallet::CreateWalletFromFile(const CChainParams &chainParams, | ||||
const std::string &name, const fs::path &path) { | const std::string &name, const fs::path &path, | ||||
uint64_t wallet_creation_flags) { | |||||
const std::string &walletFile = name; | const std::string &walletFile = name; | ||||
// Needed to restore wallet transaction meta data after -zapwallettxes | // Needed to restore wallet transaction meta data after -zapwallettxes | ||||
std::vector<CWalletTx> vWtx; | std::vector<CWalletTx> vWtx; | ||||
if (gArgs.GetBoolArg("-zapwallettxes", false)) { | if (gArgs.GetBoolArg("-zapwallettxes", false)) { | ||||
uiInterface.InitMessage(_("Zapping all transactions from wallet...")); | uiInterface.InitMessage(_("Zapping all transactions from wallet...")); | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | if (fFirstRun) { | ||||
if (!gArgs.GetBoolArg("-usehd", true)) { | if (!gArgs.GetBoolArg("-usehd", true)) { | ||||
InitError(strprintf(_("Error creating %s: You can't create non-HD " | InitError(strprintf(_("Error creating %s: You can't create non-HD " | ||||
"wallets with this version."), | "wallets with this version."), | ||||
walletFile)); | walletFile)); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->SetMinVersion(FEATURE_LATEST); | walletInstance->SetMinVersion(FEATURE_LATEST); | ||||
// Generate a new seed | if ((wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
// selective allow to set flags | |||||
walletInstance->SetWalletFlag(WALLET_FLAG_DISABLE_PRIVATE_KEYS); | |||||
} else { | |||||
// generate a new seed | |||||
CPubKey seed = walletInstance->GenerateNewSeed(); | CPubKey seed = walletInstance->GenerateNewSeed(); | ||||
walletInstance->SetHDSeed(seed); | walletInstance->SetHDSeed(seed); | ||||
} | |||||
// Top up the keypool | // Top up the keypool | ||||
if (!walletInstance->TopUpKeyPool()) { | if (!walletInstance->IsWalletFlagSet( | ||||
WALLET_FLAG_DISABLE_PRIVATE_KEYS) && | |||||
!walletInstance->TopUpKeyPool()) { | |||||
InitError(_("Unable to generate initial keys") += "\n"); | InitError(_("Unable to generate initial keys") += "\n"); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
walletInstance->ChainStateFlushed(chainActive.GetLocator()); | walletInstance->ChainStateFlushed(chainActive.GetLocator()); | ||||
} else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { | |||||
// Make it impossible to disable private keys after creation | |||||
InitError(strprintf(_("Error loading %s: Private keys can only be " | |||||
"disabled during creation"), | |||||
walletFile)); | |||||
return nullptr; | |||||
} else if (walletInstance->IsWalletFlagSet( | |||||
WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | |||||
LOCK(walletInstance->cs_KeyStore); | |||||
if (!walletInstance->mapKeys.empty() || | |||||
!walletInstance->mapCryptedKeys.empty()) { | |||||
InitWarning(strprintf(_("Warning: Private keys detected in wallet " | |||||
"{%s} with disabled private keys"), | |||||
walletFile)); | |||||
} | |||||
} else if (gArgs.IsArgSet("-usehd")) { | } else if (gArgs.IsArgSet("-usehd")) { | ||||
bool useHD = gArgs.GetBoolArg("-usehd", true); | bool useHD = gArgs.GetBoolArg("-usehd", true); | ||||
if (walletInstance->IsHDEnabled() && !useHD) { | if (walletInstance->IsHDEnabled() && !useHD) { | ||||
InitError( | InitError( | ||||
strprintf(_("Error loading %s: You can't disable HD on an " | strprintf(_("Error loading %s: You can't disable HD on an " | ||||
"already existing HD wallet"), | "already existing HD wallet"), | ||||
walletFile)); | walletFile)); | ||||
return nullptr; | return nullptr; | ||||
▲ Show 20 Lines • Show All 312 Lines • Show Last 20 Lines |