diff options
Diffstat (limited to 'src/node/interfaces.cpp')
-rw-r--r-- | src/node/interfaces.cpp | 169 |
1 files changed, 149 insertions, 20 deletions
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e0bab6e22e..0010c104a8 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -8,6 +8,7 @@ #include <chain.h> #include <chainparams.h> #include <common/args.h> +#include <consensus/merkle.h> #include <consensus/validation.h> #include <deploymentstatus.h> #include <external_signer.h> @@ -17,6 +18,7 @@ #include <interfaces/handler.h> #include <interfaces/mining.h> #include <interfaces/node.h> +#include <interfaces/types.h> #include <interfaces/wallet.h> #include <kernel/chain.h> #include <kernel/context.h> @@ -33,6 +35,7 @@ #include <node/interface_ui.h> #include <node/mini_miner.h> #include <node/miner.h> +#include <node/kernel_notifications.h> #include <node/transaction.h> #include <node/types.h> #include <node/warnings.h> @@ -58,7 +61,7 @@ #include <validation.h> #include <validationinterface.h> -#include <config/bitcoin-config.h> // IWYU pragma: keep +#include <bitcoin-build-config.h> // IWYU pragma: keep #include <any> #include <memory> @@ -67,6 +70,8 @@ #include <boost/signals2/signal.hpp> +using interfaces::BlockRef; +using interfaces::BlockTemplate; using interfaces::BlockTip; using interfaces::Chain; using interfaces::FoundBlock; @@ -100,7 +105,7 @@ public: void initParameterInteraction() override { InitParameterInteraction(args()); } bilingual_str getWarnings() override { return Join(Assert(m_context->warnings)->GetMessages(), Untranslated("<hr />")); } int getExitStatus() override { return Assert(m_context)->exit_status.load(); } - uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } + BCLog::CategoryMask getLogCategories() override { return LogInstance().GetCategoryMask(); } bool baseInitialize() override { if (!AppInitBasicSetup(args(), Assert(context())->exit_status)) return false; @@ -130,9 +135,11 @@ public: } void startShutdown() override { - if (!(*Assert(Assert(m_context)->shutdown))()) { + NodeContext& ctx{*Assert(m_context)}; + if (!(Assert(ctx.shutdown_request))()) { LogError("Failed to send shutdown signal\n"); } + // Stop RPC for clean shutdown if any of waitfor* commands is executed. if (args().GetBoolArg("-server", false)) { InterruptRPC(); @@ -180,7 +187,7 @@ public: }); args().WriteSettingsFile(); } - void mapPort(bool use_upnp, bool use_natpmp) override { StartMapPort(use_upnp, use_natpmp); } + void mapPort(bool use_upnp, bool use_pcp) override { StartMapPort(use_upnp, use_pcp); } bool getProxy(Network net, Proxy& proxy_info) override { return GetProxy(net, proxy_info); } size_t getNodeCount(ConnectionDirection flags) override { @@ -278,6 +285,7 @@ public: int64_t getTotalBytesSent() override { return m_context->connman ? m_context->connman->GetTotalBytesSent() : 0; } size_t getMempoolSize() override { return m_context->mempool ? m_context->mempool->size() : 0; } size_t getMempoolDynamicUsage() override { return m_context->mempool ? m_context->mempool->DynamicMemoryUsage() : 0; } + size_t getMempoolMaxUsage() override { return m_context->mempool ? m_context->mempool->m_opts.max_size_bytes : 0; } bool getHeaderTip(int& height, int64_t& block_time) override { LOCK(::cs_main); @@ -289,6 +297,13 @@ public: } return false; } + std::map<CNetAddr, LocalServiceInfo> getNetLocalAddresses() override + { + if (m_context->connman) + return m_context->connman->getNetLocalAddresses(); + else + return {}; + } int getNumBlocks() override { LOCK(::cs_main); @@ -806,16 +821,34 @@ public: }); return result; } - bool updateRwSetting(const std::string& name, const common::SettingsValue& value, bool write) override + bool updateRwSetting(const std::string& name, + const interfaces::SettingsUpdate& update_settings_func) override { + std::optional<interfaces::SettingsAction> action; args().LockSettings([&](common::Settings& settings) { - if (value.isNull()) { - settings.rw_settings.erase(name); + if (auto* value = common::FindKey(settings.rw_settings, name)) { + action = update_settings_func(*value); + if (value->isNull()) settings.rw_settings.erase(name); } else { - settings.rw_settings[name] = value; + UniValue new_value; + action = update_settings_func(new_value); + if (!new_value.isNull()) settings.rw_settings[name] = std::move(new_value); } }); - return !write || args().WriteSettingsFile(); + if (!action) return false; + // Now dump value to disk if requested + return *action != interfaces::SettingsAction::WRITE || args().WriteSettingsFile(); + } + bool overwriteRwSetting(const std::string& name, common::SettingsValue value, interfaces::SettingsAction action) override + { + return updateRwSetting(name, [&](common::SettingsValue& settings) { + settings = std::move(value); + return action; + }); + } + bool deleteRwSettings(const std::string& name, interfaces::SettingsAction action) override + { + return overwriteRwSetting(name, {}, action); } void requestMempoolTransactions(Notifications& notifications) override { @@ -837,6 +870,82 @@ public: NodeContext& m_node; }; +class BlockTemplateImpl : public BlockTemplate +{ +public: + explicit BlockTemplateImpl(std::unique_ptr<CBlockTemplate> block_template, NodeContext& node) : m_block_template(std::move(block_template)), m_node(node) + { + assert(m_block_template); + } + + CBlockHeader getBlockHeader() override + { + return m_block_template->block; + } + + CBlock getBlock() override + { + return m_block_template->block; + } + + std::vector<CAmount> getTxFees() override + { + return m_block_template->vTxFees; + } + + std::vector<int64_t> getTxSigops() override + { + return m_block_template->vTxSigOpsCost; + } + + CTransactionRef getCoinbaseTx() override + { + return m_block_template->block.vtx[0]; + } + + std::vector<unsigned char> getCoinbaseCommitment() override + { + return m_block_template->vchCoinbaseCommitment; + } + + int getWitnessCommitmentIndex() override + { + return GetWitnessCommitmentIndex(m_block_template->block); + } + + std::vector<uint256> getCoinbaseMerklePath() override + { + return BlockMerkleBranch(m_block_template->block); + } + + bool submitSolution(uint32_t version, uint32_t timestamp, uint32_t nonce, CMutableTransaction coinbase) override + { + CBlock block{m_block_template->block}; + + auto cb = MakeTransactionRef(std::move(coinbase)); + + if (block.vtx.size() == 0) { + block.vtx.push_back(cb); + } else { + block.vtx[0] = cb; + } + + block.nVersion = version; + block.nTime = timestamp; + block.nNonce = nonce; + + block.hashMerkleRoot = BlockMerkleRoot(block); + + auto block_ptr = std::make_shared<const CBlock>(block); + return chainman().ProcessNewBlock(block_ptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/nullptr); + } + + const std::unique_ptr<CBlockTemplate> m_block_template; + + ChainstateManager& chainman() { return *Assert(m_node.chainman); } + NodeContext& m_node; +}; + class MinerImpl : public Mining { public: @@ -852,12 +961,26 @@ public: return chainman().IsInitialBlockDownload(); } - std::optional<uint256> getTipHash() override + std::optional<BlockRef> getTip() override { LOCK(::cs_main); CBlockIndex* tip{chainman().ActiveChain().Tip()}; if (!tip) return {}; - return tip->GetBlockHash(); + return BlockRef{tip->GetBlockHash(), tip->nHeight}; + } + + BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override + { + if (timeout > std::chrono::years{100}) timeout = std::chrono::years{100}; // Upper bound to avoid UB in std::chrono + { + WAIT_LOCK(notifications().m_tip_block_mutex, lock); + notifications().m_tip_block_cv.wait_for(lock, timeout, [&]() EXCLUSIVE_LOCKS_REQUIRED(notifications().m_tip_block_mutex) { + return (notifications().m_tip_block != current_tip && notifications().m_tip_block != uint256::ZERO) || chainman().m_interrupt; + }); + } + // Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks. + LOCK(::cs_main); + return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight}; } bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override @@ -870,23 +993,29 @@ public: return context()->mempool->GetTransactionsUpdated(); } - bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root) override + bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override { - LOCK(::cs_main); - return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root); + LOCK(cs_main); + CBlockIndex* tip{chainman().ActiveChain().Tip()}; + // Fail if the tip updated before the lock was taken + if (block.hashPrevBlock != tip->GetBlockHash()) { + state.Error("Block does not connect to current chain tip."); + return false; + } + + return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); } - std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override + std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override { - BlockAssembler::Options options; - ApplyArgsManOptions(gArgs, options); - - LOCK(::cs_main); - return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key); + BlockAssembler::Options assemble_options{options}; + ApplyArgsManOptions(*Assert(m_node.args), assemble_options); + return std::make_unique<BlockTemplateImpl>(BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key), m_node); } NodeContext* context() override { return &m_node; } ChainstateManager& chainman() { return *Assert(m_node.chainman); } + KernelNotifications& notifications() { return *Assert(m_node.notifications); } NodeContext& m_node; }; } // namespace |