diff options
Diffstat (limited to 'src/node/interfaces.cpp')
-rw-r--r-- | src/node/interfaces.cpp | 140 |
1 files changed, 119 insertions, 21 deletions
diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 54b986c926..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 { @@ -819,29 +826,29 @@ public: { std::optional<interfaces::SettingsAction> action; args().LockSettings([&](common::Settings& settings) { - auto* ptr_value = common::FindKey(settings.rw_settings, name); - // Create value if it doesn't exist - auto& value = ptr_value ? *ptr_value : settings.rw_settings[name]; - action = update_settings_func(value); + if (auto* value = common::FindKey(settings.rw_settings, name)) { + action = update_settings_func(*value); + if (value->isNull()) settings.rw_settings.erase(name); + } else { + UniValue new_value; + action = update_settings_func(new_value); + if (!new_value.isNull()) settings.rw_settings[name] = std::move(new_value); + } }); if (!action) return false; // Now dump value to disk if requested - return *action == interfaces::SettingsAction::SKIP_WRITE || args().WriteSettingsFile(); + return *action != interfaces::SettingsAction::WRITE || args().WriteSettingsFile(); } - bool overwriteRwSetting(const std::string& name, common::SettingsValue& value, bool write) override + bool overwriteRwSetting(const std::string& name, common::SettingsValue value, interfaces::SettingsAction action) override { - if (value.isNull()) return deleteRwSettings(name, write); return updateRwSetting(name, [&](common::SettingsValue& settings) { settings = std::move(value); - return write ? interfaces::SettingsAction::WRITE : interfaces::SettingsAction::SKIP_WRITE; + return action; }); } - bool deleteRwSettings(const std::string& name, bool write) override + bool deleteRwSettings(const std::string& name, interfaces::SettingsAction action) override { - args().LockSettings([&](common::Settings& settings) { - settings.rw_settings.erase(name); - }); - return !write || args().WriteSettingsFile(); + return overwriteRwSetting(name, {}, action); } void requestMempoolTransactions(Notifications& notifications) override { @@ -863,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: @@ -878,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 @@ -909,15 +1006,16 @@ public: return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); } - std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override + std::unique_ptr<BlockTemplate> createNewBlock(const CScript& script_pub_key, const BlockCreateOptions& options) override { BlockAssembler::Options assemble_options{options}; ApplyArgsManOptions(*Assert(m_node.args), assemble_options); - return BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(script_pub_key); + 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 |