Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/wallet.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 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 "wallet/wallet.h" | #include "wallet/wallet.h" | ||||
#include "base58.h" | |||||
#include "cashaddr.h" | |||||
#include "chain.h" | #include "chain.h" | ||||
#include "checkpoints.h" | #include "checkpoints.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "consensus/consensus.h" | #include "consensus/consensus.h" | ||||
#include "consensus/validation.h" | #include "consensus/validation.h" | ||||
#include "dstencode.h" | #include "dstencode.h" | ||||
#include "fs.h" | #include "fs.h" | ||||
#include "init.h" | #include "init.h" | ||||
▲ Show 20 Lines • Show All 188 Lines • ▼ Show 20 Lines | void CWallet::DeriveNewChildKey(CWalletDB &walletdb, CKeyMetadata &metadata, | ||||
// 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 | ||||
// example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 | // example: 1 | BIP32_HARDENED_KEY_LIMIT == 0x80000001 == 2147483649 | ||||
if (internal) { | if (internal) { | ||||
chainChildKey.Derive(childKey, | chainChildKey.Derive(childKey, hdChain.nInternalChainCounter | | ||||
hdChain.nInternalChainCounter | | |||||
BIP32_HARDENED_KEY_LIMIT); | BIP32_HARDENED_KEY_LIMIT); | ||||
metadata.hdKeypath = "m/0'/1'/" + | metadata.hdKeypath = "m/0'/1'/" + | ||||
std::to_string(hdChain.nInternalChainCounter) + | std::to_string(hdChain.nInternalChainCounter) + | ||||
"'"; | "'"; | ||||
hdChain.nInternalChainCounter++; | hdChain.nInternalChainCounter++; | ||||
} else { | } else { | ||||
chainChildKey.Derive(childKey, | chainChildKey.Derive(childKey, hdChain.nExternalChainCounter | | ||||
hdChain.nExternalChainCounter | | |||||
BIP32_HARDENED_KEY_LIMIT); | BIP32_HARDENED_KEY_LIMIT); | ||||
metadata.hdKeypath = "m/0'/0'/" + | metadata.hdKeypath = "m/0'/0'/" + | ||||
std::to_string(hdChain.nExternalChainCounter) + | std::to_string(hdChain.nExternalChainCounter) + | ||||
"'"; | "'"; | ||||
hdChain.nExternalChainCounter++; | hdChain.nExternalChainCounter++; | ||||
} | } | ||||
} while (HaveKey(childKey.key.GetPubKey().GetID())); | } while (HaveKey(childKey.key.GetPubKey().GetID())); | ||||
secret = childKey.key; | secret = childKey.key; | ||||
metadata.hdMasterKeyID = hdChain.masterKeyID; | metadata.hdMasterKeyID = hdChain.masterKeyID; | ||||
▲ Show 20 Lines • Show All 495 Lines • ▼ Show 20 Lines | if (thisTx.IsCoinBase()) { | ||||
return; | return; | ||||
} | } | ||||
for (const CTxIn &txin : thisTx.tx->vin) { | for (const CTxIn &txin : thisTx.tx->vin) { | ||||
AddToSpends(txin.prevout, wtxid); | AddToSpends(txin.prevout, wtxid); | ||||
} | } | ||||
} | } | ||||
bool CWallet::EncryptWallet(const SecureString &strWalletPassphrase) { | bool CWallet::EncryptWallet(const SecureString &strWalletPassphrase, | ||||
CKey *newSeed) { | |||||
if (IsCrypted()) { | if (IsCrypted()) { | ||||
return false; | return false; | ||||
} | } | ||||
CKeyingMaterial vMasterKey; | CKeyingMaterial vMasterKey; | ||||
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); | vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); | ||||
GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); | GetStrongRandBytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey)) { | ||||
pwalletdbEncryption = nullptr; | pwalletdbEncryption = nullptr; | ||||
Lock(); | Lock(); | ||||
Unlock(strWalletPassphrase); | Unlock(strWalletPassphrase); | ||||
// If we are using HD, replace the HD master key (seed) with a new one. | // If we are using HD, replace the HD master key (seed) with a new one. | ||||
if (IsHDEnabled()) { | if (IsHDEnabled()) { | ||||
CKey key; | CKey key; | ||||
CPubKey masterPubKey = GenerateNewHDMasterKey(); | CPubKey masterPubKey = GenerateNewHDMasterKey(newSeed); | ||||
// preserve the old chains version to not break backward | // preserve the old chains version to not break backward | ||||
// compatibility | // compatibility | ||||
CHDChain oldChain = GetHDChain(); | CHDChain oldChain = GetHDChain(); | ||||
if (!SetHDMasterKey(masterPubKey, &oldChain)) { | if (!SetHDMasterKey(masterPubKey, &oldChain)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 696 Lines • ▼ Show 20 Lines | for (const CTxOut &txout : tx.vout) { | ||||
throw std::runtime_error(std::string(__func__) + | throw std::runtime_error(std::string(__func__) + | ||||
": value out of range"); | ": value out of range"); | ||||
} | } | ||||
} | } | ||||
return nChange; | return nChange; | ||||
} | } | ||||
CPubKey CWallet::GenerateNewHDMasterKey() { | CPubKey CWallet::GenerateNewHDMasterKey(CKey *newSeed) { | ||||
CKey key; | CKey key; | ||||
if (newSeed == nullptr) { | |||||
// Standard path, no CKey was provided so generate a new one | |||||
key.MakeNewKey(true); | |||||
} else { | |||||
if (newSeed->IsValid()) { | |||||
// A CKey was provided and is valid, use it | |||||
LogPrintf("CWallet::GenerateNewHDMasterKey - Using given key\n"); | |||||
key = *newSeed; | |||||
} else { | |||||
// A CKey was passed down but empty | |||||
// Generate a new key and send back to the dialog box for backup | |||||
LogPrintf("CWallet::GenerateNewHDMasterKey - Generating new key\n"); | |||||
key.MakeNewKey(true); | key.MakeNewKey(true); | ||||
*newSeed = key; | |||||
} | |||||
} | |||||
int64_t nCreationTime = GetTime(); | int64_t nCreationTime = GetTime(); | ||||
CKeyMetadata metadata(nCreationTime); | CKeyMetadata metadata(nCreationTime); | ||||
// Calculate the pubkey. | // Calculate the pubkey. | ||||
CPubKey pubkey = key.GetPubKey(); | CPubKey pubkey = key.GetPubKey(); | ||||
assert(key.VerifyPubKey(pubkey)); | assert(key.VerifyPubKey(pubkey)); | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | |||||
* will be updated. | * will be updated. | ||||
* | * | ||||
* Returns pointer to the first block in the last contiguous range that was | * Returns pointer to the first block in the last contiguous range that was | ||||
* successfully scanned or elided (elided if pIndexStart points at a block | * successfully scanned or elided (elided if pIndexStart points at a block | ||||
* before CWallet::nTimeFirstKey). Returns null if there is no such range, or | * before CWallet::nTimeFirstKey). Returns null if there is no such range, or | ||||
* the range doesn't include chainActive.Tip(). | * the range doesn't include chainActive.Tip(). | ||||
*/ | */ | ||||
CBlockIndex *CWallet::ScanForWalletTransactions(CBlockIndex *pindexStart, | CBlockIndex *CWallet::ScanForWalletTransactions(CBlockIndex *pindexStart, | ||||
bool fUpdate) { | bool fUpdate, | ||||
int64_t forceAll) { | |||||
LOCK2(cs_main, cs_wallet); | LOCK2(cs_main, cs_wallet); | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
CBlockIndex *pindex = pindexStart; | CBlockIndex *pindex = pindexStart; | ||||
CBlockIndex *ret = pindexStart; | CBlockIndex *ret = pindexStart; | ||||
// No need to read and scan block, if block was created before our wallet | // No need to read and scan block, if block was created before our wallet | ||||
// birthday (as adjusted for block time variability) | // birthday (as adjusted for block time variability) | ||||
// Skip this adjustment if user requested a complete scan with -rescan=1 | |||||
if (forceAll == 0) { | |||||
while (pindex && nTimeFirstKey && | while (pindex && nTimeFirstKey && | ||||
(pindex->GetBlockTime() < (nTimeFirstKey - 7200))) { | (pindex->GetBlockTime() < (nTimeFirstKey - 7200))) { | ||||
pindex = chainActive.Next(pindex); | pindex = chainActive.Next(pindex); | ||||
} | } | ||||
} | |||||
// Show rescan progress in GUI as dialog or on splashscreen, if -rescan on | // Show rescan progress in GUI as dialog or on splashscreen, if -rescan on | ||||
// startup. | // startup. | ||||
ShowProgress(_("Rescanning..."), 0); | ShowProgress(_("Rescanning..."), 0); | ||||
double dProgressStart = | double dProgressStart = | ||||
GuessVerificationProgress(chainParams.TxData(), pindex); | GuessVerificationProgress(chainParams.TxData(), pindex); | ||||
double dProgressTip = | double dProgressTip = | ||||
GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()); | GuessVerificationProgress(chainParams.TxData(), chainActive.Tip()); | ||||
▲ Show 20 Lines • Show All 2,299 Lines • ▼ Show 20 Lines | strUsage += HelpMessageOpt( | ||||
"for transaction creation (default: %s)"), | "for transaction creation (default: %s)"), | ||||
CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); | CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE))); | ||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-paytxfee=<amt>", | "-paytxfee=<amt>", | ||||
strprintf( | strprintf( | ||||
_("Fee (in %s/kB) to add to transactions you send (default: %s)"), | _("Fee (in %s/kB) to add to transactions you send (default: %s)"), | ||||
CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); | CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); | ||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-rescan", | "-rescan", _("Rescan the block chain for missing wallet transactions " | ||||
_("Rescan the block chain for missing wallet transactions on startup")); | "on startup, use " | ||||
"-rescan=1 to force rescanning from the genesis block")); | |||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-salvagewallet", | "-salvagewallet", | ||||
_("Attempt to recover private keys from a corrupt wallet on startup")); | _("Attempt to recover private keys from a corrupt wallet on startup")); | ||||
if (showDebug) { | if (showDebug) { | ||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-sendfreetransactions", | "-sendfreetransactions", | ||||
strprintf(_("Send transactions as zero-fee transactions if " | strprintf(_("Send transactions as zero-fee transactions if " | ||||
"possible (default: %d)"), | "possible (default: %d)"), | ||||
Show All 28 Lines | strUsage += HelpMessageOpt( | ||||
strprintf(_("(default: %d)"), DEFAULT_WALLETBROADCAST)); | strprintf(_("(default: %d)"), DEFAULT_WALLETBROADCAST)); | ||||
strUsage += HelpMessageOpt("-walletnotify=<cmd>", | strUsage += HelpMessageOpt("-walletnotify=<cmd>", | ||||
_("Execute command when a wallet transaction " | _("Execute command when a wallet transaction " | ||||
"changes (%s in cmd is replaced by TxID)")); | "changes (%s in cmd is replaced by TxID)")); | ||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-zapwallettxes=<mode>", | "-zapwallettxes=<mode>", | ||||
_("Delete all wallet transactions and only recover those parts of the " | _("Delete all wallet transactions and only recover those parts of the " | ||||
"blockchain through -rescan on startup") + | "blockchain through -rescan on startup") + | ||||
" " + _("(1 = keep tx meta data e.g. account owner and payment " | " " + | ||||
_("(1 = keep tx meta data e.g. account owner and payment " | |||||
"request information, 2 = drop tx meta data)")); | "request information, 2 = drop tx meta data)")); | ||||
if (showDebug) { | if (showDebug) { | ||||
strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); | strUsage += HelpMessageGroup(_("Wallet debugging/testing options:")); | ||||
strUsage += HelpMessageOpt( | strUsage += HelpMessageOpt( | ||||
"-dblogsize=<n>", | "-dblogsize=<n>", | ||||
strprintf("Flush wallet database activity from memory to disk log " | strprintf("Flush wallet database activity from memory to disk log " | ||||
"every <n> megabytes (default: %u)", | "every <n> megabytes (default: %u)", | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | if (chainActive.Tip() && chainActive.Tip() != pindexRescan) { | ||||
} | } | ||||
} | } | ||||
uiInterface.InitMessage(_("Rescanning...")); | uiInterface.InitMessage(_("Rescanning...")); | ||||
LogPrintf("Rescanning last %i blocks (from block %i)...\n", | LogPrintf("Rescanning last %i blocks (from block %i)...\n", | ||||
chainActive.Height() - pindexRescan->nHeight, | chainActive.Height() - pindexRescan->nHeight, | ||||
pindexRescan->nHeight); | pindexRescan->nHeight); | ||||
nStart = GetTimeMillis(); | nStart = GetTimeMillis(); | ||||
walletInstance->ScanForWalletTransactions(pindexRescan, true); | walletInstance->ScanForWalletTransactions(pindexRescan, true, | ||||
gArgs.GetArg("-rescan", 0)); | |||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); | LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); | ||||
walletInstance->SetBestChain(chainActive.GetLocator()); | walletInstance->SetBestChain(chainActive.GetLocator()); | ||||
walletInstance->dbw->IncrementUpdateCounter(); | walletInstance->dbw->IncrementUpdateCounter(); | ||||
// Restore wallet transaction metadata after -zapwallettxes=1 | // Restore wallet transaction metadata after -zapwallettxes=1 | ||||
if (gArgs.GetBoolArg("-zapwallettxes", false) && | if (gArgs.GetBoolArg("-zapwallettxes", false) && | ||||
gArgs.GetArg("-zapwallettxes", "1") != "2") { | gArgs.GetArg("-zapwallettxes", "1") != "2") { | ||||
CWalletDB walletdb(*walletInstance->dbw); | CWalletDB walletdb(*walletInstance->dbw); | ||||
▲ Show 20 Lines • Show All 299 Lines • Show Last 20 Lines |