Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove uses of chainActive and mapBlockIndex in wallet code #14711

Merged
merged 5 commits into from
Jan 30, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/interfaces/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ class LockImpl : public Chain::Lock
assert(block != nullptr);
return block->GetMedianTimePast();
}
bool haveBlockOnDisk(int height) override
{
CBlockIndex* block = ::chainActive[height];
return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0;
}
Optional<int> findFirstBlockWithTime(int64_t time, uint256* hash) override
{
CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time);
Expand Down Expand Up @@ -112,6 +117,21 @@ class LockImpl : public Chain::Lock
}
return nullopt;
}
bool isPotentialTip(const uint256& hash) override
{
if (::chainActive.Tip()->GetBlockHash() == hash) return true;
CBlockIndex* block = LookupBlockIndex(hash);
return block && block->GetAncestor(::chainActive.Height()) == ::chainActive.Tip();
}
CBlockLocator getLocator() override { return ::chainActive.GetLocator(); }
maflcko marked this conversation as resolved.
Show resolved Hide resolved
Optional<int> findLocatorFork(const CBlockLocator& locator) override
{
LockAnnotation lock(::cs_main);
if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) {
return fork->nHeight;
}
return nullopt;
}
};

class LockingStateImpl : public LockImpl, public UniqueLock<CCriticalSection>
Expand Down
18 changes: 18 additions & 0 deletions src/interfaces/chain.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
class CBlock;
class CScheduler;
class uint256;
struct CBlockLocator;

namespace interfaces {

Expand Down Expand Up @@ -58,6 +59,10 @@ class Chain
//! will abort.
virtual int64_t getBlockMedianTimePast(int height) = 0;

//! Check that the block is available on disk (i.e. has not been
//! pruned), and contains transactions.
virtual bool haveBlockOnDisk(int height) = 0;

//! Return height of the first block in the chain with timestamp equal
//! or greater than the given time, or nullopt if there is no block with
//! a high enough timestamp. Also return the block hash as an optional
Expand All @@ -84,6 +89,19 @@ class Chain
//! parameter (to avoid the cost of a second hash lookup in case this
//! information is desired).
virtual Optional<int> findFork(const uint256& hash, Optional<int>* height) = 0;

//! Return true if block hash points to the current chain tip, or to a
//! possible descendant of the current chain tip that isn't currently
//! connected.
virtual bool isPotentialTip(const uint256& hash) = 0;

//! Get locator for the current chain tip.
virtual CBlockLocator getLocator() = 0;

//! Return height of the latest block common to locator and chain, which
//! is guaranteed to be an ancestor of the block used to create the
//! locator.
virtual Optional<int> findLocatorFork(const CBlockLocator& locator) = 0;
};

//! Return Lock interface. Chain is locked when this is called, and
Expand Down
47 changes: 28 additions & 19 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
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) {
Expand All @@ -1191,9 +1191,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;
}
}
Expand Down Expand Up @@ -4074,7 +4073,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));
Expand Down Expand Up @@ -4161,57 +4160,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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use findPruned(rescan_height, *tip_height)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #14711 (comment)

Why not use findPruned

I used haveBlockOnDisk here because I was doing a very literal translation and findPruned doesn't have the block->pprev->nTx > 0 condition. If can drop that condition or add it to findPruned, though, if it would be an improvement.

--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());
if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(pindexRescan->GetBlockHash(), {} /* stop block */, reserver, true /* update */).status)) {
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
Expand Down
5 changes: 1 addition & 4 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ static const bool DEFAULT_DISABLE_WALLET = false;
//! Pre-calculated constants for input size estimation in *virtual size*
static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;

class CBlockIndex;
class CCoinControl;
class COutput;
class CReserveKey;
Expand Down Expand Up @@ -723,10 +722,8 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
* Note that this is *not* how far we've processed, we may need some rescan
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
*
* Protected by cs_main (see BlockUntilSyncedToCurrentChain)
*/
const CBlockIndex* m_last_block_processed = nullptr;
uint256 m_last_block_processed;

public:
/*
Expand Down