diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -107,41 +107,6 @@ class Lock { public: virtual ~Lock() {} - - //! 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 and height equal or greater than the - //! given height, or nullopt if there is no block with a high enough - //! timestamp and height. Also return the block hash as an optional - //! output parameter (to avoid the cost of a second lookup in case this - //! information is needed.) - virtual Optional - findFirstBlockWithTimeAndHeight(int64_t time, int height, - BlockHash *hash) = 0; - - //! Return height of the highest block on the chain that is an ancestor - //! of the specified block, or nullopt if no common ancestor is found. - //! Also return the height of the specified block as an optional output - //! parameter (to avoid the cost of a second hash lookup in case this - //! information is desired). - virtual Optional findFork(const BlockHash &hash, - Optional *height) = 0; - - //! Get locator for the current chain tip. - virtual CBlockLocator getTipLocator() = 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 findLocatorFork(const CBlockLocator &locator) = 0; - - //! Check if transaction will be final given chain height current time. - virtual bool contextualCheckTransactionForCurrentBlock( - const Consensus::Params ¶ms, const CTransaction &tx, - TxValidationState &state) = 0; }; //! Return Lock interface. Chain is locked when this is called, and @@ -161,6 +126,33 @@ //! Get block hash. Height must be valid or this function will abort. virtual BlockHash getBlockHash(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 and height equal or greater than the + //! given height, or nullopt if there is no block with a high enough + //! timestamp and height. Also return the block hash as an optional output + //! parameter (to avoid the cost of a second lookup in case this information + //! is needed.) + virtual Optional findFirstBlockWithTimeAndHeight(int64_t time, + int height, + BlockHash *hash) = 0; + + //! Get locator for the current chain tip. + virtual CBlockLocator getTipLocator() = 0; + + //! Return height of the highest block on chain in common with the locator, + //! which will either be the original block used to create the locator, + //! or one of its ancestors. + virtual Optional findLocatorFork(const CBlockLocator &locator) = 0; + + //! Check if transaction will be final given chain height current time. + virtual bool + contextualCheckTransactionForCurrentBlock(const CTransaction &tx, + TxValidationState &state) = 0; + //! Return whether node has the block and optionally return block metadata //! or contents. virtual bool findBlock(const BlockHash &hash, diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -66,62 +66,6 @@ } class LockImpl : public Chain::Lock, public UniqueLock { - bool haveBlockOnDisk(int height) override { - LockAssertion lock(::cs_main); - CBlockIndex *block = ::ChainActive()[height]; - return block && (block->nStatus.hasData() != 0) && block->nTx > 0; - } - Optional - findFirstBlockWithTimeAndHeight(int64_t time, int height, - BlockHash *hash) override { - LockAssertion lock(::cs_main); - CBlockIndex *block = - ::ChainActive().FindEarliestAtLeast(time, height); - if (block) { - if (hash) { - *hash = block->GetBlockHash(); - } - return block->nHeight; - } - return nullopt; - } - Optional findFork(const BlockHash &hash, - Optional *height) override { - LockAssertion lock(::cs_main); - const CBlockIndex *block = LookupBlockIndex(hash); - const CBlockIndex *fork = - block ? ::ChainActive().FindFork(block) : nullptr; - if (height) { - if (block) { - *height = block->nHeight; - } else { - height->reset(); - } - } - if (fork) { - return fork->nHeight; - } - return nullopt; - } - CBlockLocator getTipLocator() override { - LockAssertion lock(::cs_main); - return ::ChainActive().GetLocator(); - } - Optional findLocatorFork(const CBlockLocator &locator) override { - LockAssertion lock(::cs_main); - if (CBlockIndex *fork = - FindForkInGlobalIndex(::ChainActive(), locator)) { - return fork->nHeight; - } - return nullopt; - } - bool contextualCheckTransactionForCurrentBlock( - const Consensus::Params ¶ms, const CTransaction &tx, - TxValidationState &state) override { - LockAssertion lock(::cs_main); - return ContextualCheckTransactionForCurrentBlock(params, tx, state); - } - using UniqueLock::UniqueLock; }; // namespace interfaces @@ -257,6 +201,43 @@ assert(block); return block->GetBlockHash(); } + bool haveBlockOnDisk(int height) override { + LOCK(cs_main); + CBlockIndex *block = ::ChainActive()[height]; + return block && (block->nStatus.hasData() != 0) && block->nTx > 0; + } + Optional + findFirstBlockWithTimeAndHeight(int64_t time, int height, + BlockHash *hash) override { + LOCK(cs_main); + CBlockIndex *block = + ::ChainActive().FindEarliestAtLeast(time, height); + if (block) { + if (hash) { + *hash = block->GetBlockHash(); + } + return block->nHeight; + } + return nullopt; + } + CBlockLocator getTipLocator() override { + LOCK(cs_main); + return ::ChainActive().GetLocator(); + } + bool contextualCheckTransactionForCurrentBlock( + const CTransaction &tx, TxValidationState &state) override { + LockAssertion lock(::cs_main); + return ContextualCheckTransactionForCurrentBlock( + m_params.GetConsensus(), tx, state); + } + Optional findLocatorFork(const CBlockLocator &locator) override { + LOCK(cs_main); + if (CBlockIndex *fork = + FindForkInGlobalIndex(::ChainActive(), locator)) { + return fork->nHeight; + } + return nullopt; + } bool findBlock(const BlockHash &hash, const FoundBlock &block) override { WAIT_LOCK(cs_main, lock); diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -57,8 +57,7 @@ } //! Construct wallet tx status struct. - WalletTxStatus MakeWalletTxStatus(interfaces::Chain::Lock &locked_chain, - const CWalletTx &wtx) { + WalletTxStatus MakeWalletTxStatus(CWallet &wallet, const CWalletTx &wtx) { WalletTxStatus result; result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height @@ -69,9 +68,9 @@ result.lock_time = wtx.tx->nLockTime; TxValidationState state; result.is_final = - locked_chain.contextualCheckTransactionForCurrentBlock( - Params().GetConsensus(), *wtx.tx, state); - result.is_trusted = wtx.IsTrusted(locked_chain); + wallet.chain().contextualCheckTransactionForCurrentBlock(*wtx.tx, + state); + result.is_trusted = wtx.IsTrusted(); result.is_abandoned = wtx.isAbandoned(); result.is_coinbase = wtx.IsCoinBase(); result.is_in_main_chain = wtx.IsInMainChain(); @@ -307,7 +306,7 @@ block_time = -1; CHECK_NONFATAL(m_wallet->chain().findBlock( m_wallet->GetLastBlockHash(), FoundBlock().time(block_time))); - tx_status = MakeWalletTxStatus(*locked_chain, mi->second); + tx_status = MakeWalletTxStatus(*m_wallet, mi->second); return true; } WalletTx getWalletTxDetails(const TxId &txid, WalletTxStatus &tx_status, @@ -321,7 +320,7 @@ num_blocks = m_wallet->GetLastBlockHeight(); in_mempool = mi->second.InMempool(); order_form = mi->second.vOrderForm; - tx_status = MakeWalletTxStatus(*locked_chain, mi->second); + tx_status = MakeWalletTxStatus(*m_wallet, mi->second); return MakeWalletTx(*m_wallet, mi->second); } return {}; @@ -393,7 +392,7 @@ auto locked_chain = m_wallet->chain().lock(); LOCK(m_wallet->cs_wallet); CoinsList result; - for (const auto &entry : m_wallet->ListCoins(*locked_chain)) { + for (const auto &entry : m_wallet->ListCoins()) { auto &group = result[entry.first]; for (const auto &coin : entry.second) { group.emplace_back(COutPoint(coin.tx->GetId(), coin.i), diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -178,7 +178,7 @@ FoundBlock().time(block_time))); entry.pushKV("blocktime", block_time); } else { - entry.pushKV("trusted", wtx.IsTrusted(locked_chain)); + entry.pushKV("trusted", wtx.IsTrusted()); } uint256 hash = wtx.GetId(); entry.pushKV("txid", hash.GetHex()); @@ -652,8 +652,7 @@ return EncodeBase64(vchSig.data(), vchSig.size()); } -static Amount GetReceived(interfaces::Chain::Lock &locked_chain, - const CWallet &wallet, const UniValue ¶ms, +static Amount GetReceived(const CWallet &wallet, const UniValue ¶ms, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { std::set address_set; @@ -689,8 +688,8 @@ const CWalletTx &wtx = wtx_pair.second; TxValidationState txState; if (wtx.IsCoinBase() || - !locked_chain.contextualCheckTransactionForCurrentBlock( - wallet.chainParams.GetConsensus(), *wtx.tx, txState) || + !wallet.chain().contextualCheckTransactionForCurrentBlock( + *wtx.tx, txState) || wtx.GetDepthInMainChain() < min_depth) { continue; } @@ -752,7 +751,7 @@ auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - return ValueFromAmount(GetReceived(*locked_chain, *pwallet, request.params, + return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ false)); } @@ -797,7 +796,7 @@ auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - return ValueFromAmount(GetReceived(*locked_chain, *pwallet, request.params, + return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ true)); } @@ -1208,8 +1207,8 @@ TxValidationState state; if (wtx.IsCoinBase() || - !locked_chain.contextualCheckTransactionForCurrentBlock( - pwallet->chainParams.GetConsensus(), *wtx.tx, state)) { + !pwallet->chain().contextualCheckTransactionForCurrentBlock( + *wtx.tx, state)) { continue; } @@ -3508,8 +3507,8 @@ cctl.m_max_depth = nMaxDepth; auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); - pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, - &cctl, nMinimumAmount, nMaximumAmount, + pwallet->AvailableCoins(vecOutputs, !include_unsafe, &cctl, + nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount); } diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -579,7 +579,7 @@ { auto locked_chain = m_chain->lock(); LOCK(wallet->cs_wallet); - list = wallet->ListCoins(*locked_chain); + list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), @@ -598,7 +598,7 @@ { auto locked_chain = m_chain->lock(); LOCK(wallet->cs_wallet); - list = wallet->ListCoins(*locked_chain); + list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), @@ -610,7 +610,7 @@ auto locked_chain = m_chain->lock(); LOCK(wallet->cs_wallet); std::vector available; - wallet->AvailableCoins(*locked_chain, available); + wallet->AvailableCoins(available); BOOST_CHECK_EQUAL(available.size(), 2U); } for (const auto &group : list) { @@ -623,7 +623,7 @@ auto locked_chain = m_chain->lock(); LOCK(wallet->cs_wallet); std::vector available; - wallet->AvailableCoins(*locked_chain, available); + wallet->AvailableCoins(available); BOOST_CHECK_EQUAL(available.size(), 0U); } // Confirm ListCoins still returns same result as before, despite coins @@ -631,7 +631,7 @@ { auto locked_chain = m_chain->lock(); LOCK(wallet->cs_wallet); - list = wallet->ListCoins(*locked_chain); + list = wallet->ListCoins(); } BOOST_CHECK_EQUAL(list.size(), 1U); BOOST_CHECK_EQUAL(boost::get(list.begin()->first).ToString(), diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -524,9 +524,8 @@ bool IsEquivalentTo(const CWalletTx &tx) const; bool InMempool() const; - bool IsTrusted(interfaces::Chain::Lock &locked_chain) const; - bool IsTrusted(interfaces::Chain::Lock &locked_chain, - std::set &trusted_parents) const; + bool IsTrusted() const; + bool IsTrusted(std::set &trusted_parents) const; int64_t GetTxTime() const; @@ -908,8 +907,7 @@ /** * populate vCoins with vector of available COutputs. */ - void AvailableCoins(interfaces::Chain::Lock &locked_chain, - std::vector &vCoins, bool fOnlySafe = true, + void AvailableCoins(std::vector &vCoins, bool fOnlySafe = true, const CCoinControl *coinControl = nullptr, const Amount nMinimumAmount = SATOSHI, const Amount nMaximumAmount = MAX_MONEY, @@ -921,8 +919,7 @@ * Return list of available coins and locked coins grouped by non-change * output address. */ - std::map> - ListCoins(interfaces::Chain::Lock &locked_chain) const + std::map> ListCoins() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2087,17 +2087,16 @@ return fInMempool; } -bool CWalletTx::IsTrusted(interfaces::Chain::Lock &locked_chain) const { +bool CWalletTx::IsTrusted() const { std::set s; - return IsTrusted(locked_chain, s); + return IsTrusted(s); } -bool CWalletTx::IsTrusted(interfaces::Chain::Lock &locked_chain, - std::set &trusted_parents) const { +bool CWalletTx::IsTrusted(std::set &trusted_parents) const { // Quick answer in most cases TxValidationState state; - if (!locked_chain.contextualCheckTransactionForCurrentBlock( - this->pwallet->chainParams.GetConsensus(), *tx, state)) { + if (!pwallet->chain().contextualCheckTransactionForCurrentBlock(*tx, + state)) { return false; } @@ -2139,7 +2138,7 @@ continue; } // Recurse to check that the parent is also trusted - if (!parent->IsTrusted(locked_chain, trusted_parents)) { + if (!parent->IsTrusted(trusted_parents)) { return false; } trusted_parents.insert(parent->GetId()); @@ -2247,7 +2246,7 @@ std::set trusted_parents; for (const auto &entry : mapWallet) { const CWalletTx &wtx = entry.second; - const bool is_trusted{wtx.IsTrusted(*locked_chain, trusted_parents)}; + const bool is_trusted{wtx.IsTrusted(trusted_parents)}; const int tx_depth{wtx.GetDepthInMainChain()}; const Amount tx_credit_mine{wtx.GetAvailableCredit( /* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)}; @@ -2273,7 +2272,7 @@ Amount balance = Amount::zero(); std::vector vCoins; - AvailableCoins(*locked_chain, vCoins, true, coinControl); + AvailableCoins(vCoins, true, coinControl); for (const COutput &out : vCoins) { if (out.fSpendable) { balance += out.tx->tx->vout[out.i].nValue; @@ -2282,8 +2281,7 @@ return balance; } -void CWallet::AvailableCoins(interfaces::Chain::Lock &locked_chain, - std::vector &vCoins, bool fOnlySafe, +void CWallet::AvailableCoins(std::vector &vCoins, bool fOnlySafe, const CCoinControl *coinControl, const Amount nMinimumAmount, const Amount nMaximumAmount, @@ -2305,16 +2303,14 @@ const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH}; - const Consensus::Params params = this->chainParams.GetConsensus(); - std::set trusted_parents; for (const auto &entry : mapWallet) { const TxId &wtxid = entry.first; const CWalletTx &wtx = entry.second; TxValidationState state; - if (!locked_chain.contextualCheckTransactionForCurrentBlock( - params, *wtx.tx, state)) { + if (!chain().contextualCheckTransactionForCurrentBlock(*wtx.tx, + state)) { continue; } @@ -2334,7 +2330,7 @@ continue; } - bool safeTx = wtx.IsTrusted(locked_chain, trusted_parents); + bool safeTx = wtx.IsTrusted(trusted_parents); // Bitcoin-ABC: Removed check that prevents consideration of coins from // transactions that are replacing other transactions. This check based @@ -2428,14 +2424,13 @@ } } -std::map> -CWallet::ListCoins(interfaces::Chain::Lock &locked_chain) const { +std::map> CWallet::ListCoins() const { AssertLockHeld(cs_wallet); std::map> result; std::vector availableCoins; - AvailableCoins(locked_chain, availableCoins); + AvailableCoins(availableCoins); for (const auto &coin : availableCoins) { CTxDestination address; @@ -2927,7 +2922,7 @@ txNew.nLockTime = GetLocktimeForNewTransaction( chain(), GetLastBlockHash(), GetLastBlockHeight()); std::vector vAvailableCoins; - AvailableCoins(*locked_chain, vAvailableCoins, true, &coin_control); + AvailableCoins(vAvailableCoins, true, &coin_control); // Parameters for coin selection, init with dummy CoinSelectionParams coin_selection_params; @@ -3591,7 +3586,7 @@ for (const auto &walletEntry : mapWallet) { const CWalletTx &wtx = walletEntry.second; - if (!wtx.IsTrusted(locked_chain, trusted_parents)) { + if (!wtx.IsTrusted(trusted_parents)) { continue; } @@ -4164,7 +4159,7 @@ } auto locked_chain = chain.lock(); - walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); + walletInstance->ChainStateFlushed(chain.getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation error = strprintf(_("Error loading %s: Private keys can only be " @@ -4304,7 +4299,7 @@ CBlockLocator locator; if (batch.ReadBestBlock(locator)) { if (const Optional fork_height = - locked_chain->findLocatorFork(locator)) { + chain.findLocatorFork(locator)) { rescan_height = *fork_height; } } @@ -4331,7 +4326,7 @@ // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && - locked_chain->haveBlockOnDisk(block_height - 1) && + chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) { --block_height; } @@ -4362,7 +4357,7 @@ } if (time_first_key) { if (Optional first_block = - locked_chain->findFirstBlockWithTimeAndHeight( + chain.findFirstBlockWithTimeAndHeight( *time_first_key - TIMESTAMP_WINDOW, rescan_height, nullptr)) { rescan_height = *first_block; @@ -4382,7 +4377,7 @@ return nullptr; } } - walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); + walletInstance->ChainStateFlushed(chain.getTipLocator()); walletInstance->database->IncrementUpdateCounter(); // Restore wallet transaction metadata after -zapwallettxes=1