diff options
author | Russell Yanofsky <russ@yanofsky.org> | 2020-11-24 10:13:23 -0500 |
---|---|---|
committer | Russell Yanofsky <russ@yanofsky.org> | 2020-11-24 10:13:23 -0500 |
commit | 2a26771d8161d30be1853a35acfee588cce03634 (patch) | |
tree | f82ddb9210278cb06e8bbd87183c9ed94cf8c764 /src/node/interfaces.cpp | |
parent | 12bd0fc9d70333c54c83ebb08c734272dbd330c2 (diff) |
Move ChainImpl from interfaces/chain.cpp to node/interfaces.cpp
No changes to ChainImpl or any related classes (review with `git diff --color-moved=dimmed_zebra`)
Diffstat (limited to 'src/node/interfaces.cpp')
-rw-r--r-- | src/node/interfaces.cpp | 395 |
1 files changed, 390 insertions, 5 deletions
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 74098eba96..77a5957a56 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -2,47 +2,58 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <interfaces/node.h> - #include <addrdb.h> #include <banman.h> +#include <boost/signals2/signal.hpp> #include <chain.h> #include <chainparams.h> #include <init.h> #include <interfaces/chain.h> #include <interfaces/handler.h> +#include <interfaces/node.h> #include <interfaces/wallet.h> #include <net.h> #include <net_processing.h> #include <netaddress.h> #include <netbase.h> +#include <node/coin.h> #include <node/context.h> +#include <node/transaction.h> #include <node/ui_interface.h> #include <policy/feerate.h> #include <policy/fees.h> +#include <policy/policy.h> +#include <policy/rbf.h> #include <policy/settings.h> #include <primitives/block.h> +#include <primitives/transaction.h> +#include <rpc/protocol.h> #include <rpc/server.h> #include <shutdown.h> #include <support/allocators/secure.h> #include <sync.h> +#include <timedata.h> #include <txmempool.h> +#include <uint256.h> +#include <univalue.h> #include <util/check.h> #include <util/ref.h> #include <util/system.h> #include <util/translation.h> #include <validation.h> +#include <validationinterface.h> #include <warnings.h> #if defined(HAVE_CONFIG_H) #include <config/bitcoin-config.h> #endif -#include <univalue.h> - -#include <boost/signals2/signal.hpp> +#include <memory> +#include <utility> using interfaces::BlockTip; +using interfaces::Chain; +using interfaces::FoundBlock; using interfaces::Handler; using interfaces::MakeHandler; using interfaces::Node; @@ -300,9 +311,383 @@ public: NodeContext* m_context{nullptr}; util::Ref m_context_ref; }; + +bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<RecursiveMutex>& lock) +{ + if (!index) return false; + if (block.m_hash) *block.m_hash = index->GetBlockHash(); + if (block.m_height) *block.m_height = index->nHeight; + if (block.m_time) *block.m_time = index->GetBlockTime(); + if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax(); + if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast(); + if (block.m_data) { + REVERSE_LOCK(lock); + if (!ReadBlockFromDisk(*block.m_data, index, Params().GetConsensus())) block.m_data->SetNull(); + } + return true; +} + +class NotificationsProxy : public CValidationInterface +{ +public: + explicit NotificationsProxy(std::shared_ptr<Chain::Notifications> notifications) + : m_notifications(std::move(notifications)) {} + virtual ~NotificationsProxy() = default; + void TransactionAddedToMempool(const CTransactionRef& tx, uint64_t mempool_sequence) override + { + m_notifications->transactionAddedToMempool(tx, mempool_sequence); + } + void TransactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRemovalReason reason, uint64_t mempool_sequence) override + { + m_notifications->transactionRemovedFromMempool(tx, reason, mempool_sequence); + } + void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override + { + m_notifications->blockConnected(*block, index->nHeight); + } + void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* index) override + { + m_notifications->blockDisconnected(*block, index->nHeight); + } + void UpdatedBlockTip(const CBlockIndex* index, const CBlockIndex* fork_index, bool is_ibd) override + { + m_notifications->updatedBlockTip(); + } + void ChainStateFlushed(const CBlockLocator& locator) override { m_notifications->chainStateFlushed(locator); } + std::shared_ptr<Chain::Notifications> m_notifications; +}; + +class NotificationsHandlerImpl : public Handler +{ +public: + explicit NotificationsHandlerImpl(std::shared_ptr<Chain::Notifications> notifications) + : m_proxy(std::make_shared<NotificationsProxy>(std::move(notifications))) + { + RegisterSharedValidationInterface(m_proxy); + } + ~NotificationsHandlerImpl() override { disconnect(); } + void disconnect() override + { + if (m_proxy) { + UnregisterSharedValidationInterface(m_proxy); + m_proxy.reset(); + } + } + std::shared_ptr<NotificationsProxy> m_proxy; +}; + +class RpcHandlerImpl : public Handler +{ +public: + explicit RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command) + { + m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) { + if (!m_wrapped_command) return false; + try { + return m_wrapped_command->actor(request, result, last_handler); + } catch (const UniValue& e) { + // If this is not the last handler and a wallet not found + // exception was thrown, return false so the next handler can + // try to handle the request. Otherwise, reraise the exception. + if (!last_handler) { + const UniValue& code = e["code"]; + if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) { + return false; + } + } + throw; + } + }; + ::tableRPC.appendCommand(m_command.name, &m_command); + } + + void disconnect() final + { + if (m_wrapped_command) { + m_wrapped_command = nullptr; + ::tableRPC.removeCommand(m_command.name, &m_command); + } + } + + ~RpcHandlerImpl() override { disconnect(); } + + CRPCCommand m_command; + const CRPCCommand* m_wrapped_command; +}; + +class ChainImpl : public Chain +{ +public: + explicit ChainImpl(NodeContext& node) : m_node(node) {} + Optional<int> getHeight() override + { + LOCK(::cs_main); + int height = ::ChainActive().Height(); + if (height >= 0) { + return height; + } + return nullopt; + } + Optional<int> getBlockHeight(const uint256& hash) override + { + LOCK(::cs_main); + CBlockIndex* block = LookupBlockIndex(hash); + if (block && ::ChainActive().Contains(block)) { + return block->nHeight; + } + return nullopt; + } + uint256 getBlockHash(int height) override + { + LOCK(::cs_main); + CBlockIndex* block = ::ChainActive()[height]; + assert(block); + return block->GetBlockHash(); + } + bool haveBlockOnDisk(int height) override + { + LOCK(cs_main); + CBlockIndex* block = ::ChainActive()[height]; + return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; + } + Optional<int> findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* 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 checkFinalTx(const CTransaction& tx) override + { + LOCK(cs_main); + return CheckFinalTx(tx); + } + Optional<int> findLocatorFork(const CBlockLocator& locator) override + { + LOCK(cs_main); + if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { + return fork->nHeight; + } + return nullopt; + } + bool findBlock(const uint256& hash, const FoundBlock& block) override + { + WAIT_LOCK(cs_main, lock); + return FillBlock(LookupBlockIndex(hash), block, lock); + } + bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock& block) override + { + WAIT_LOCK(cs_main, lock); + return FillBlock(ChainActive().FindEarliestAtLeast(min_time, min_height), block, lock); + } + bool findNextBlock(const uint256& block_hash, int block_height, const FoundBlock& next, bool* reorg) override { + WAIT_LOCK(cs_main, lock); + CBlockIndex* block = ChainActive()[block_height]; + if (block && block->GetBlockHash() != block_hash) block = nullptr; + if (reorg) *reorg = !block; + return FillBlock(block ? ChainActive()[block_height + 1] : nullptr, next, lock); + } + bool findAncestorByHeight(const uint256& block_hash, int ancestor_height, const FoundBlock& ancestor_out) override + { + WAIT_LOCK(cs_main, lock); + if (const CBlockIndex* block = LookupBlockIndex(block_hash)) { + if (const CBlockIndex* ancestor = block->GetAncestor(ancestor_height)) { + return FillBlock(ancestor, ancestor_out, lock); + } + } + return FillBlock(nullptr, ancestor_out, lock); + } + bool findAncestorByHash(const uint256& block_hash, const uint256& ancestor_hash, const FoundBlock& ancestor_out) override + { + WAIT_LOCK(cs_main, lock); + const CBlockIndex* block = LookupBlockIndex(block_hash); + const CBlockIndex* ancestor = LookupBlockIndex(ancestor_hash); + if (block && ancestor && block->GetAncestor(ancestor->nHeight) != ancestor) ancestor = nullptr; + return FillBlock(ancestor, ancestor_out, lock); + } + bool findCommonAncestor(const uint256& block_hash1, const uint256& block_hash2, const FoundBlock& ancestor_out, const FoundBlock& block1_out, const FoundBlock& block2_out) override + { + WAIT_LOCK(cs_main, lock); + const CBlockIndex* block1 = LookupBlockIndex(block_hash1); + const CBlockIndex* block2 = LookupBlockIndex(block_hash2); + const CBlockIndex* ancestor = block1 && block2 ? LastCommonAncestor(block1, block2) : nullptr; + // Using & instead of && below to avoid short circuiting and leaving + // output uninitialized. + return FillBlock(ancestor, ancestor_out, lock) & FillBlock(block1, block1_out, lock) & FillBlock(block2, block2_out, lock); + } + void findCoins(std::map<COutPoint, Coin>& coins) override { return FindCoins(m_node, coins); } + double guessVerificationProgress(const uint256& block_hash) override + { + LOCK(cs_main); + return GuessVerificationProgress(Params().TxData(), LookupBlockIndex(block_hash)); + } + bool hasBlocks(const uint256& block_hash, int min_height, Optional<int> max_height) override + { + // hasBlocks returns true if all ancestors of block_hash in specified + // range have block data (are not pruned), false if any ancestors in + // specified range are missing data. + // + // For simplicity and robustness, min_height and max_height are only + // used to limit the range, and passing min_height that's too low or + // max_height that's too high will not crash or change the result. + LOCK(::cs_main); + if (CBlockIndex* block = LookupBlockIndex(block_hash)) { + if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height); + for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) { + // Check pprev to not segfault if min_height is too low + if (block->nHeight <= min_height || !block->pprev) return true; + } + } + return false; + } + RBFTransactionState isRBFOptIn(const CTransaction& tx) override + { + if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx); + LOCK(m_node.mempool->cs); + return IsRBFOptIn(tx, *m_node.mempool); + } + bool hasDescendantsInMempool(const uint256& txid) override + { + if (!m_node.mempool) return false; + LOCK(m_node.mempool->cs); + auto it = m_node.mempool->GetIter(txid); + return it && (*it)->GetCountWithDescendants() > 1; + } + bool broadcastTransaction(const CTransactionRef& tx, + const CAmount& max_tx_fee, + bool relay, + std::string& err_string) override + { + const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false); + // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures. + // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures + // that Chain clients do not need to know about. + return TransactionError::OK == err; + } + void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) override + { + ancestors = descendants = 0; + if (!m_node.mempool) return; + m_node.mempool->GetTransactionAncestry(txid, ancestors, descendants); + } + void getPackageLimits(unsigned int& limit_ancestor_count, unsigned int& limit_descendant_count) override + { + limit_ancestor_count = gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); + limit_descendant_count = gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); + } + bool checkChainLimits(const CTransactionRef& tx) override + { + if (!m_node.mempool) return true; + 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(m_node.mempool->cs); + return m_node.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 + { + if (!m_node.mempool) return {}; + return m_node.mempool->GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000); + } + CFeeRate relayMinFee() override { return ::minRelayTxFee; } + CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; } + CFeeRate relayDustFee() override { return ::dustRelayFee; } + bool havePruned() override + { + LOCK(cs_main); + return ::fHavePruned; + } + bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); } + bool isInitialBlockDownload() override { return ::ChainstateActive().IsInitialBlockDownload(); } + bool shutdownRequested() override { return ShutdownRequested(); } + int64_t getAdjustedTime() override { return GetAdjustedTime(); } + void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); } + void initWarning(const bilingual_str& message) override { InitWarning(message); } + void initError(const bilingual_str& message) override { InitError(message); } + void showProgress(const std::string& title, int progress, bool resume_possible) override + { + ::uiInterface.ShowProgress(title, progress, resume_possible); + } + std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) override + { + return MakeUnique<NotificationsHandlerImpl>(std::move(notifications)); + } + void waitForNotificationsIfTipChanged(const uint256& old_tip) override + { + if (!old_tip.IsNull()) { + LOCK(::cs_main); + if (old_tip == ::ChainActive().Tip()->GetBlockHash()) return; + } + SyncWithValidationInterfaceQueue(); + } + std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override + { + return MakeUnique<RpcHandlerImpl>(command); + } + bool rpcEnableDeprecated(const std::string& method) override { return IsDeprecatedRPCEnabled(method); } + void rpcRunLater(const std::string& name, std::function<void()> fn, int64_t seconds) override + { + RPCRunLater(name, std::move(fn), seconds); + } + int rpcSerializationFlags() override { return RPCSerializationFlags(); } + util::SettingsValue getRwSetting(const std::string& name) override + { + util::SettingsValue result; + gArgs.LockSettings([&](const util::Settings& settings) { + if (const util::SettingsValue* value = util::FindKey(settings.rw_settings, name)) { + result = *value; + } + }); + return result; + } + bool updateRwSetting(const std::string& name, const util::SettingsValue& value) override + { + gArgs.LockSettings([&](util::Settings& settings) { + if (value.isNull()) { + settings.rw_settings.erase(name); + } else { + settings.rw_settings[name] = value; + } + }); + return gArgs.WriteSettingsFile(); + } + void requestMempoolTransactions(Notifications& notifications) override + { + if (!m_node.mempool) return; + LOCK2(::cs_main, m_node.mempool->cs); + for (const CTxMemPoolEntry& entry : m_node.mempool->mapTx) { + notifications.transactionAddedToMempool(entry.GetSharedTx(), 0 /* mempool_sequence */); + } + } + NodeContext& m_node; +}; } // namespace } // namespace node namespace interfaces { std::unique_ptr<Node> MakeNode(NodeContext* context) { return MakeUnique<node::NodeImpl>(context); } +std::unique_ptr<Chain> MakeChain(NodeContext& context) { return MakeUnique<node::ChainImpl>(context); } } // namespace interfaces |