// Copyright (c) 2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace interfaces { namespace { class LockImpl : public Chain::Lock { Optional getHeight() override { int height = ::chainActive.Height(); if (height >= 0) { return height; } return nullopt; } Optional getBlockHeight(const uint256& hash) override { CBlockIndex* block = LookupBlockIndex(hash); if (block && ::chainActive.Contains(block)) { return block->nHeight; } return nullopt; } int getBlockDepth(const uint256& hash) override { const Optional tip_height = getHeight(); const Optional height = getBlockHeight(hash); return tip_height && height ? *tip_height - *height + 1 : 0; } uint256 getBlockHash(int height) override { CBlockIndex* block = ::chainActive[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { CBlockIndex* block = ::chainActive[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { CBlockIndex* block = ::chainActive[height]; 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 findFirstBlockWithTime(int64_t time, uint256* hash) override { CBlockIndex* block = ::chainActive.FindEarliestAtLeast(time); if (block) { if (hash) *hash = block->GetBlockHash(); return block->nHeight; } return nullopt; } Optional findFirstBlockWithTimeAndHeight(int64_t time, int height) override { // TODO: Could update CChain::FindEarliestAtLeast() to take a height // parameter and use it with std::lower_bound() to make this // implementation more efficient and allow combining // findFirstBlockWithTime and findFirstBlockWithTimeAndHeight into one // method. for (CBlockIndex* block = ::chainActive[height]; block; block = ::chainActive.Next(block)) { if (block->GetBlockTime() >= time) { return block->nHeight; } } return nullopt; } Optional findPruned(int start_height, Optional stop_height) override { if (::fPruneMode) { CBlockIndex* block = stop_height ? ::chainActive[*stop_height] : ::chainActive.Tip(); while (block && block->nHeight >= start_height) { if ((block->nStatus & BLOCK_HAVE_DATA) == 0) { return block->nHeight; } block = block->pprev; } } return nullopt; } Optional findFork(const uint256& hash, Optional* height) override { 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; } 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 getTipLocator() override { return ::chainActive.GetLocator(); } Optional findLocatorFork(const CBlockLocator& locator) override { LockAnnotation lock(::cs_main); if (CBlockIndex* fork = FindForkInGlobalIndex(::chainActive, locator)) { return fork->nHeight; } return nullopt; } bool checkFinalTx(const CTransaction& tx) override { LockAnnotation lock(::cs_main); return CheckFinalTx(tx); } bool submitToMemoryPool(CTransactionRef tx, CAmount absurd_fee, CValidationState& state) override { LockAnnotation lock(::cs_main); return AcceptToMemoryPool(::mempool, state, tx, nullptr /* missing inputs */, nullptr /* txn replaced */, false /* bypass limits */, absurd_fee); } }; class LockingStateImpl : public LockImpl, public UniqueLock { using UniqueLock::UniqueLock; }; class ChainImpl : public Chain { public: std::unique_ptr lock(bool try_lock) override { auto result = MakeUnique(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); if (try_lock && result && !*result) return {}; // std::move necessary on some compilers due to conversion from // LockingStateImpl to Lock pointer return std::move(result); } std::unique_ptr assumeLocked() override { return MakeUnique(); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { CBlockIndex* index; { LOCK(cs_main); index = LookupBlockIndex(hash); if (!index) { return false; } if (time) { *time = index->GetBlockTime(); } if (time_max) { *time_max = index->GetBlockTimeMax(); } } if (block && !ReadBlockFromDisk(*block, index, Params().GetConsensus())) { block->SetNull(); } return true; } double guessVerificationProgress(const uint256& block_hash) override { LOCK(cs_main); return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash)); } RBFTransactionState isRBFOptIn(const CTransaction& tx) override { LOCK(::mempool.cs); return IsRBFOptIn(tx, ::mempool); } bool hasDescendantsInMempool(const uint256& txid) override { LOCK(::mempool.cs); auto it_mp = ::mempool.mapTx.find(txid); return it_mp != ::mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1; } void relayTransaction(const uint256& txid) override { CInv inv(MSG_TX, txid); g_connman->ForEachNode([&inv](CNode* node) { node->PushInventory(inv); }); } void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override { ::mempool.GetTransactionAncestry(txid, ancestors, descendants); } bool checkChainLimits(CTransactionRef tx) override { LockPoints lp; CTxMemPoolEntry entry(tx, 0, 0, 0, false, 0, lp); CTxMemPool::setEntries ancestors; auto limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); auto limit_ancestor_size = gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * 1000; auto limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); auto limit_descendant_size = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000; std::string unused_error_string; LOCK(::mempool.cs); return ::mempool.CalculateMemPoolAncestors(entry, ancestors, limit_ancestor_count, limit_ancestor_size, limit_descendant_count, limit_descendant_size, unused_error_string); } CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override { return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative); } unsigned int estimateMaxBlocks() override { return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); } CFeeRate mempoolMinFee() override { return ::mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); } CAmount maxTxFee() override { return ::maxTxFee; } bool getPruneMode() override { return ::fPruneMode; } bool p2pEnabled() override { return g_connman != nullptr; } int64_t getAdjustedTime() override { return GetAdjustedTime(); } void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); } void initWarning(const std::string& message) override { InitWarning(message); } void initError(const std::string& message) override { InitError(message); } }; } // namespace std::unique_ptr MakeChain() { return MakeUnique(); } } // namespace interfaces