aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp255
1 files changed, 138 insertions, 117 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 74deb2dddc..9b643be69a 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -251,6 +251,9 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch &batch, const CKey& secret, const C
{
AssertLockHeld(cs_wallet); // mapKeyMetadata
+ // Make sure we aren't adding private keys to private key disabled wallets
+ assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+
// CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey
// which is overridden below. To avoid flushes, the database handle is
// tunneled through to it.
@@ -398,7 +401,7 @@ bool CWallet::LoadWatchOnly(const CScript &dest)
return CCryptoKeyStore::AddWatchOnly(dest);
}
-bool CWallet::Unlock(const SecureString& strWalletPassphrase)
+bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
{
CCrypter crypter;
CKeyingMaterial _vMasterKey;
@@ -411,7 +414,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey))
continue; // try another master key
- if (CCryptoKeyStore::Unlock(_vMasterKey))
+ if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys))
return true;
}
}
@@ -935,19 +938,19 @@ void CWallet::LoadToWallet(const CWalletTx& wtxIn)
}
}
-bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool fUpdate)
{
const CTransaction& tx = *ptx;
{
AssertLockHeld(cs_wallet);
- if (pIndex != nullptr) {
+ if (!block_hash.IsNull()) {
for (const CTxIn& txin : tx.vin) {
std::pair<TxSpends::const_iterator, TxSpends::const_iterator> range = mapTxSpends.equal_range(txin.prevout);
while (range.first != range.second) {
if (range.first->second != tx.GetHash()) {
- WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), pIndex->GetBlockHash().ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
- MarkConflicted(pIndex->GetBlockHash(), range.first->second);
+ WalletLogPrintf("Transaction %s (in block %s) conflicts with wallet transaction %s (both spend %s:%i)\n", tx.GetHash().ToString(), block_hash.ToString(), range.first->second.ToString(), range.first->first.hash.ToString(), range.first->first.n);
+ MarkConflicted(block_hash, range.first->second);
}
range.first++;
}
@@ -983,8 +986,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const CBlockI
CWalletTx wtx(this, ptx);
// Get merkle branch if transaction was found in a block
- if (pIndex != nullptr)
- wtx.SetMerkleBranch(pIndex, posInBlock);
+ if (!block_hash.IsNull())
+ wtx.SetMerkleBranch(block_hash, posInBlock);
return AddToWallet(wtx, false);
}
@@ -1071,11 +1074,7 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- int conflictconfirms = 0;
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
- conflictconfirms = -(chainActive.Height() - pindex->nHeight + 1);
- }
+ int conflictconfirms = -locked_chain->getBlockDepth(hashBlock);
// If number of conflict confirms cannot be determined, this means
// that the block is still unknown or not yet part of the main chain,
// for example when loading the wallet during a reindex. Do nothing in that
@@ -1121,8 +1120,8 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
}
-void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pindex, int posInBlock, bool update_tx) {
- if (!AddToWalletIfInvolvingMe(ptx, pindex, posInBlock, update_tx))
+void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_hash, int posInBlock, bool update_tx) {
+ if (!AddToWalletIfInvolvingMe(ptx, block_hash, posInBlock, update_tx))
return; // Not one of ours
// If a transaction changes 'conflicted' state, that changes the balance
@@ -1134,7 +1133,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const CBlockIndex *pin
void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
auto it = mapWallet.find(ptx->GetHash());
if (it != mapWallet.end()) {
@@ -1162,15 +1161,15 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
// the notification that the conflicted transaction was evicted.
for (const CTransactionRef& ptx : vtxConflicted) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
TransactionRemovedFromMempool(ptx);
}
for (size_t i = 0; i < pblock->vtx.size(); i++) {
- SyncTransaction(pblock->vtx[i], pindex, i);
+ SyncTransaction(pblock->vtx[i], pindex->GetBlockHash(), i);
TransactionRemovedFromMempool(pblock->vtx[i]);
}
- m_last_block_processed = pindex;
+ m_last_block_processed = pindex->GetBlockHash();
}
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@@ -1178,7 +1177,7 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
LOCK(cs_wallet);
for (const CTransactionRef& ptx : pblock->vtx) {
- SyncTransaction(ptx);
+ SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */);
}
}
@@ -1195,9 +1194,8 @@ void CWallet::BlockUntilSyncedToCurrentChain() {
// protected by cs_wallet instead of cs_main, but as long as we need
// cs_main here anyway, it's easier to just call it cs_main-protected.
auto locked_chain = chain().lock();
- const CBlockIndex* initialChainTip = chainActive.Tip();
- if (m_last_block_processed && m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
+ if (!m_last_block_processed.IsNull() && locked_chain->isPotentialTip(m_last_block_processed)) {
return;
}
}
@@ -1403,6 +1401,7 @@ void CWallet::SetHDSeed(const CPubKey& seed)
newHdChain.nVersion = CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false);
+ NotifyCanGetAddressesChanged();
}
void CWallet::SetHDChain(const CHDChain& chain, bool memonly)
@@ -1591,132 +1590,144 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r
// Find starting block. May be null if nCreateTime is greater than the
// highest blockchain timestamp, in which case there is nothing that needs
// to be scanned.
- CBlockIndex* startBlock = nullptr;
+ uint256 start_block;
{
auto locked_chain = chain().lock();
- startBlock = chainActive.FindEarliestAtLeast(startTime - TIMESTAMP_WINDOW);
- WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
+ const Optional<int> start_height = locked_chain->findFirstBlockWithTime(startTime - TIMESTAMP_WINDOW, &start_block);
+ const Optional<int> tip_height = locked_chain->getHeight();
+ WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0);
}
- if (startBlock) {
- const CBlockIndex *failedBlock, *stop_block;
+ if (!start_block.IsNull()) {
// TODO: this should take into account failure by ScanResult::USER_ABORT
- if (ScanResult::FAILURE == ScanForWalletTransactions(startBlock, nullptr, reserver, failedBlock, stop_block, update)) {
- return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
+ ScanResult result = ScanForWalletTransactions(start_block, {} /* stop_block */, reserver, update);
+ if (result.status == ScanResult::FAILURE) {
+ int64_t time_max;
+ if (!chain().findBlock(result.failed_block, nullptr /* block */, nullptr /* time */, &time_max)) {
+ throw std::logic_error("ScanForWalletTransactions returned invalid block hash");
+ }
+ return time_max + TIMESTAMP_WINDOW + 1;
}
}
return startTime;
}
/**
- * Scan the block chain (starting in pindexStart) for transactions
+ * Scan the block chain (starting in start_block) for transactions
* from or to us. If fUpdate is true, found transactions that already
* exist in the wallet will be updated.
*
- * @param[in] pindexStop if not a nullptr, the scan will stop at this block-index
- * @param[out] failed_block if FAILURE is returned, the most recent block
- * that could not be scanned, otherwise nullptr
- * @param[out] stop_block the most recent block that could be scanned,
- * otherwise nullptr if no block could be scanned
+ * @param[in] start_block if not null, the scan will start at this block instead
+ * of the genesis block
+ * @param[in] stop_block if not null, the scan will stop at this block instead
+ * of the chain tip
*
* @return ScanResult indicating success or failure of the scan. SUCCESS if
* scan was successful. FAILURE if a complete rescan was not possible (due to
* pruning or corruption). USER_ABORT if the rescan was aborted before it
* could complete.
*
- * @pre Caller needs to make sure pindexStop (and the optional pindexStart) are on
+ * @pre Caller needs to make sure start_block (and the optional stop_block) are on
* the main chain after to the addition of any new keys you want to detect
* transactions for.
*/
-CWallet::ScanResult CWallet::ScanForWalletTransactions(const CBlockIndex* const pindexStart, const CBlockIndex* const pindexStop, const WalletRescanReserver& reserver, const CBlockIndex*& failed_block, const CBlockIndex*& stop_block, bool fUpdate)
+CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_block, const uint256& stop_block, const WalletRescanReserver& reserver, bool fUpdate)
{
int64_t nNow = GetTime();
- const CChainParams& chainParams = Params();
assert(reserver.isReserved());
- if (pindexStop) {
- assert(pindexStop->nHeight >= pindexStart->nHeight);
- }
- const CBlockIndex* pindex = pindexStart;
- failed_block = nullptr;
- stop_block = nullptr;
+ uint256 block_hash = start_block;
+ ScanResult result;
- if (pindex) WalletLogPrintf("Rescan started from block %d...\n", pindex->nHeight);
+ WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
{
fAbortRescan = false;
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
- CBlockIndex* tip = nullptr;
+ uint256 tip_hash;
+ // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
+ Optional<int> block_height = MakeOptional(false, int());
double progress_begin;
double progress_end;
{
auto locked_chain = chain().lock();
- progress_begin = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr) {
- tip = chainActive.Tip();
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
- } else {
- progress_end = GuessVerificationProgress(chainParams.TxData(), pindexStop);
+ if (Optional<int> tip_height = locked_chain->getHeight()) {
+ tip_hash = locked_chain->getBlockHash(*tip_height);
}
+ block_height = locked_chain->getBlockHeight(block_hash);
+ progress_begin = chain().guessVerificationProgress(block_hash);
+ progress_end = chain().guessVerificationProgress(stop_block.IsNull() ? tip_hash : stop_block);
}
double progress_current = progress_begin;
- while (pindex && !fAbortRescan && !ShutdownRequested()) {
- if (pindex->nHeight % 100 == 0 && progress_end - progress_begin > 0.0) {
+ while (block_height && !fAbortRescan && !ShutdownRequested()) {
+ if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) {
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)((progress_current - progress_begin) / (progress_end - progress_begin) * 100))));
}
if (GetTime() >= nNow + 60) {
nNow = GetTime();
- WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, progress_current);
+ WalletLogPrintf("Still rescanning. At block %d. Progress=%f\n", *block_height, progress_current);
}
CBlock block;
- if (ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
+ if (chain().findBlock(block_hash, &block) && !block.IsNull()) {
auto locked_chain = chain().lock();
LOCK(cs_wallet);
- if (pindex && !chainActive.Contains(pindex)) {
+ if (!locked_chain->getBlockHeight(block_hash)) {
// Abort scan if current block is no longer active, to prevent
// marking transactions as coming from the wrong block.
- failed_block = pindex;
+ // TODO: This should return success instead of failure, see
+ // https://github.com/bitcoin/bitcoin/pull/14711#issuecomment-458342518
+ result.failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
break;
}
for (size_t posInBlock = 0; posInBlock < block.vtx.size(); ++posInBlock) {
- SyncTransaction(block.vtx[posInBlock], pindex, posInBlock, fUpdate);
+ SyncTransaction(block.vtx[posInBlock], block_hash, posInBlock, fUpdate);
}
// scan succeeded, record block as most recent successfully scanned
- stop_block = pindex;
+ result.stop_block = block_hash;
+ result.stop_height = *block_height;
} else {
// could not scan block, keep scanning but record this block as the most recent failure
- failed_block = pindex;
+ result.failed_block = block_hash;
+ result.status = ScanResult::FAILURE;
}
- if (pindex == pindexStop) {
+ if (block_hash == stop_block) {
break;
}
{
auto locked_chain = chain().lock();
- pindex = chainActive.Next(pindex);
- progress_current = GuessVerificationProgress(chainParams.TxData(), pindex);
- if (pindexStop == nullptr && tip != chainActive.Tip()) {
- tip = chainActive.Tip();
+ Optional<int> tip_height = locked_chain->getHeight();
+ if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) {
+ // break successfully when rescan has reached the tip, or
+ // previous block is no longer on the chain due to a reorg
+ break;
+ }
+
+ // increment block and verification progress
+ block_hash = locked_chain->getBlockHash(++*block_height);
+ progress_current = chain().guessVerificationProgress(block_hash);
+
+ // handle updated tip hash
+ const uint256 prev_tip_hash = tip_hash;
+ tip_hash = locked_chain->getBlockHash(*tip_height);
+ if (stop_block.IsNull() && prev_tip_hash != tip_hash) {
// in case the tip has changed, update progress max
- progress_end = GuessVerificationProgress(chainParams.TxData(), tip);
+ progress_end = chain().guessVerificationProgress(tip_hash);
}
}
}
ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI
- if (pindex && fAbortRescan) {
- WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
- } else if (pindex && ShutdownRequested()) {
- WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", pindex->nHeight, progress_current);
- return ScanResult::USER_ABORT;
+ if (block_height && fAbortRescan) {
+ WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", block_height.get_value_or(0), progress_current);
+ result.status = ScanResult::USER_ABORT;
+ } else if (block_height && ShutdownRequested()) {
+ WalletLogPrintf("Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height.get_value_or(0), progress_current);
+ result.status = ScanResult::USER_ABORT;
}
}
- if (failed_block) {
- return ScanResult::FAILURE;
- } else {
- return ScanResult::SUCCESS;
- }
+ return result;
}
void CWallet::ReacceptWalletTransactions()
@@ -2573,6 +2584,7 @@ static bool IsCurrentForAntiFeeSniping(interfaces::Chain::Lock& locked_chain)
*/
static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_chain)
{
+ uint32_t const height = locked_chain.getHeight().get_value_or(-1);
uint32_t locktime;
// Discourage fee sniping.
//
@@ -2595,7 +2607,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// now we ensure code won't be written that makes assumptions about
// nLockTime that preclude a fix later.
if (IsCurrentForAntiFeeSniping(locked_chain)) {
- locktime = chainActive.Height();
+ locktime = height;
// Secondly occasionally randomly pick a nLockTime even further back, so
// that transactions that are delayed after signing for whatever reason,
@@ -2609,7 +2621,7 @@ static uint32_t GetLocktimeForNewTransaction(interfaces::Chain::Lock& locked_cha
// unique "nLockTime fingerprint", set nLockTime to a constant.
locktime = 0;
}
- assert(locktime <= (unsigned int)chainActive.Height());
+ assert(locktime <= height);
assert(locktime < LOCKTIME_THRESHOLD);
return locktime;
}
@@ -3327,6 +3339,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n", missingInternal + missingExternal, missingInternal, setInternalKeyPool.size() + setExternalKeyPool.size() + set_pre_split_keypool.size(), setInternalKeyPool.size());
}
}
+ NotifyCanGetAddressesChanged();
return true;
}
@@ -3371,6 +3384,7 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
m_pool_key_to_index.erase(keypool.vchPubKey.GetID());
WalletLogPrintf("keypool reserve %d\n", nIndex);
}
+ NotifyCanGetAddressesChanged();
return true;
}
@@ -3395,6 +3409,7 @@ void CWallet::ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey)
setExternalKeyPool.insert(nIndex);
}
m_pool_key_to_index[pubkey.GetID()] = nIndex;
+ NotifyCanGetAddressesChanged();
}
WalletLogPrintf("keypool return %d\n", nIndex);
}
@@ -3718,11 +3733,12 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
}
// map in which we'll infer heights of other keys
- CBlockIndex *pindexMax = chainActive[std::max(0, chainActive.Height() - 144)]; // the tip can be reorganized; use a 144-block safety margin
- std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
+ const Optional<int> tip_height = locked_chain.getHeight();
+ const int max_height = tip_height && *tip_height > 144 ? *tip_height - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
+ std::map<CKeyID, int> mapKeyFirstBlock;
for (const CKeyID &keyid : GetKeys()) {
if (mapKeyBirth.count(keyid) == 0)
- mapKeyFirstBlock[keyid] = pindexMax;
+ mapKeyFirstBlock[keyid] = max_height;
}
// if there are no such keys, we're done
@@ -3733,17 +3749,15 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
for (const auto& entry : mapWallet) {
// iterate over all wallet transactions...
const CWalletTx &wtx = entry.second;
- CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock);
- if (pindex && chainActive.Contains(pindex)) {
+ if (Optional<int> height = locked_chain.getBlockHeight(wtx.hashBlock)) {
// ... which are already in a block
- int nHeight = pindex->nHeight;
for (const CTxOut &txout : wtx.tx->vout) {
// iterate over all their outputs
for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *this)) {
// ... and all their affected keys
- std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
- rit->second = pindex;
+ std::map<CKeyID, int>::iterator rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && *height < rit->second)
+ rit->second = *height;
}
}
}
@@ -3751,7 +3765,7 @@ void CWallet::GetKeyBirthTimes(interfaces::Chain::Lock& locked_chain, std::map<C
// Extract block timestamps for those keys
for (const auto& entry : mapKeyFirstBlock)
- mapKeyBirth[entry.first] = entry.second->GetBlockTime() - TIMESTAMP_WINDOW; // block times can be 2h off
+ mapKeyBirth[entry.first] = locked_chain.getBlockTime(entry.second) - TIMESTAMP_WINDOW; // block times can be 2h off
}
/**
@@ -3779,7 +3793,8 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
{
unsigned int nTimeSmart = wtx.nTimeReceived;
if (!wtx.hashUnset()) {
- if (const CBlockIndex* pindex = LookupBlockIndex(wtx.hashBlock)) {
+ int64_t blocktime;
+ if (chain().findBlock(wtx.hashBlock, nullptr /* block */, &blocktime)) {
int64_t latestNow = wtx.nTimeReceived;
int64_t latestEntry = 0;
@@ -3805,7 +3820,6 @@ unsigned int CWallet::ComputeTimeSmart(const CWalletTx& wtx) const
}
}
- int64_t blocktime = pindex->GetBlockTime();
nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow));
} else {
WalletLogPrintf("%s: found %s in block %s not in index\n", __func__, wtx.GetHash().ToString(), wtx.hashBlock.ToString());
@@ -3911,6 +3925,9 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b
return false;
}
+ // Keep same database environment instance across Verify/Recover calls below.
+ std::unique_ptr<WalletDatabase> database = WalletDatabase::Create(wallet_path);
+
try {
if (!WalletBatch::VerifyEnvironment(wallet_path, error_string)) {
return false;
@@ -4067,7 +4084,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
}
auto locked_chain = chain.assumeLocked(); // Temporary. Removed in upcoming lock cleanup
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->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));
@@ -4154,58 +4171,67 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool();
- LockAnnotation lock(::cs_main); // Temporary, for FindForkInGlobalIndex below. Removed in upcoming commit.
auto locked_chain = chain.lock();
LOCK(walletInstance->cs_wallet);
- CBlockIndex *pindexRescan = chainActive.Genesis();
+ int rescan_height = 0;
if (!gArgs.GetBoolArg("-rescan", false))
{
WalletBatch batch(*walletInstance->database);
CBlockLocator locator;
- if (batch.ReadBestBlock(locator))
- pindexRescan = FindForkInGlobalIndex(chainActive, locator);
+ if (batch.ReadBestBlock(locator)) {
+ if (const Optional<int> fork_height = locked_chain->findLocatorFork(locator)) {
+ rescan_height = *fork_height;
+ }
+ }
}
- walletInstance->m_last_block_processed = chainActive.Tip();
+ const Optional<int> tip_height = locked_chain->getHeight();
+ if (tip_height) {
+ walletInstance->m_last_block_processed = locked_chain->getBlockHash(*tip_height);
+ } else {
+ walletInstance->m_last_block_processed.SetNull();
+ }
- if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
+ if (tip_height && *tip_height != rescan_height)
{
//We can't rescan beyond non-pruned blocks, stop and throw an error
//this might happen if a user uses an old wallet within a pruned node
// or if he ran -disablewallet for a longer time, then decided to re-enable
if (fPruneMode)
{
- CBlockIndex *block = chainActive.Tip();
- while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
- block = block->pprev;
+ int block_height = *tip_height;
+ while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
+ --block_height;
+ }
- if (pindexRescan != block) {
+ if (rescan_height != block_height) {
InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
return nullptr;
}
}
uiInterface.InitMessage(_("Rescanning..."));
- walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
+ walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
// No need to read and scan block if block was created before
// our wallet birthday (as adjusted for block time variability)
- while (pindexRescan && walletInstance->nTimeFirstKey && (pindexRescan->GetBlockTime() < (walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW))) {
- pindexRescan = chainActive.Next(pindexRescan);
+ if (walletInstance->nTimeFirstKey) {
+ if (Optional<int> first_block = locked_chain->findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height)) {
+ rescan_height = *first_block;
+ }
}
nStart = GetTimeMillis();
{
WalletRescanReserver reserver(walletInstance.get());
- const CBlockIndex *stop_block, *failed_block;
- if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, failed_block, stop_block, true))) {
+ if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) {
InitError(_("Failed to rescan the wallet during initialization"));
return nullptr;
}
}
walletInstance->WalletLogPrintf("Rescan completed in %15dms\n", GetTimeMillis() - nStart);
- walletInstance->ChainStateFlushed(chainActive.GetLocator());
+ walletInstance->ChainStateFlushed(locked_chain->getLocator());
walletInstance->database->IncrementUpdateCounter();
// Restore wallet transaction metadata after -zapwallettxes=1
@@ -4282,10 +4308,10 @@ CWalletKey::CWalletKey(int64_t nExpires)
nTimeExpires = nExpires;
}
-void CMerkleTx::SetMerkleBranch(const CBlockIndex* pindex, int posInBlock)
+void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock)
{
// Update the tx's hashBlock
- hashBlock = pindex->GetBlockHash();
+ hashBlock = block_hash;
// set the position of the transaction in the block
nIndex = posInBlock;
@@ -4298,12 +4324,7 @@ int CMerkleTx::GetDepthInMainChain(interfaces::Chain::Lock& locked_chain) const
AssertLockHeld(cs_main);
- // Find the block it claims to be in
- CBlockIndex* pindex = LookupBlockIndex(hashBlock);
- if (!pindex || !chainActive.Contains(pindex))
- return 0;
-
- return ((nIndex == -1) ? (-1) : 1) * (chainActive.Height() - pindex->nHeight + 1);
+ return locked_chain.getBlockDepth(hashBlock) * (nIndex == -1 ? -1 : 1);
}
int CMerkleTx::GetBlocksToMaturity(interfaces::Chain::Lock& locked_chain) const