From d176e4f6b7ed72d5c011753c9351b37f54903a35 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Wed, 17 Jul 2024 14:50:05 +0200 Subject: [PATCH] Start Template Provider with -sv2 --- src/CMakeLists.txt | 7 ++++ src/init.cpp | 72 +++++++++++++++++++++++++++++++++++++++++ src/node/context.cpp | 3 ++ src/node/context.h | 8 +++++ src/test/CMakeLists.txt | 3 +- 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 92af76123e9621..6563c2783ce317 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -304,8 +304,15 @@ target_link_libraries(bitcoin_node libevent::extra $ $ + $ ) +if(WITH_SV2) + target_compile_definitions(bitcoin_node + PUBLIC + WITH_SV2=1 + ) +endif() # Bitcoin Core bitcoind. if(BUILD_DAEMON) diff --git a/src/init.cpp b/src/init.cpp index c76d167b33b2af..90b3590c6b7da3 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -54,6 +54,9 @@ #include #include #include +#ifdef WITH_SV2 +#include +#endif #include #include #include @@ -268,6 +271,11 @@ void Interrupt(NodeContext& node) InterruptRPC(); InterruptREST(); InterruptTorControl(); +#ifdef WITH_SV2 + if (node.sv2_template_provider) { + node.sv2_template_provider->Interrupt(); + } +#endif InterruptMapPort(); if (node.connman) node.connman->Interrupt(); @@ -307,6 +315,11 @@ void Shutdown(NodeContext& node) StopTorControl(); +#ifdef WITH_SV2 + // Stop Template Provider + if (node.sv2_template_provider) node.sv2_template_provider->StopThreads(); +#endif + if (node.background_init_thread.joinable()) node.background_init_thread.join(); // After everything has been shut down, but before things get flushed, stop the // the scheduler. After this point, SyncWithValidationInterfaceQueue() should not be called anymore @@ -320,6 +333,9 @@ void Shutdown(NodeContext& node) node.banman.reset(); node.addrman.reset(); node.netgroupman.reset(); +#ifdef WITH_SV2 + node.sv2_template_provider.reset(); +#endif if (node.mempool && node.mempool->GetLoadTried() && ShouldPersistMempool(*node.args)) { DumpMempool(*node.mempool, MempoolPath(*node.args)); @@ -648,6 +664,11 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) argsman.AddArg("-blockmaxweight=", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockmintxfee=", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockversion=", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION); +#ifdef WITH_SV2 + argsman.AddArg("-sv2", "Bitcoind will act as a Stratum v2 Template Provider (default: false)", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-sv2interval", strprintf("Template Provider block template update interval (default: %d seconds)", Sv2TemplateProviderOptions().fee_check_interval.count()), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-sv2feedelta", strprintf("Minimum fee delta for Template Provider to send update upstream (default: %d sat)", uint64_t(Sv2TemplateProviderOptions().fee_delta)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); +#endif argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid values for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); @@ -669,6 +690,11 @@ void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc) argsman.AddArg("-ipcbind=
", "Bind to Unix socket address and listen for incoming connections. Valid address values are \"unix\" to listen on the default path, /node.sock, or \"unix:/custom/path\" to specify a custom path. Can be specified multiple times to listen on multiple paths. Default behavior is not to listen on any path. If relative paths are specified, they are interpreted relative to the network data directory. If paths include any parent directory components and the parent directories do not exist, they will be created.", ArgsManager::ALLOW_ANY, OptionsCategory::IPC); } +#ifdef WITH_SV2 + argsman.AddArg("-sv2bind=[:]", strprintf("Bind to given address and always listen on it (default: 127.0.0.1). Use [host]:port notation for IPv6."), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); + argsman.AddArg("-sv2port=", strprintf("Listen for Stratum v2 connections on (default: %u, testnet: %u, signet: %u, regtest: %u)", defaultBaseParams->Sv2Port(), testnetBaseParams->Sv2Port(), signetBaseParams->Sv2Port(), regtestBaseParams->Sv2Port()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); +#endif + #if HAVE_DECL_FORK argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsman.AddArg("-daemonwait", strprintf("Wait for initialization to be finished before exiting. This implies -daemon (default: %d)", DEFAULT_DAEMONWAIT), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); @@ -1142,6 +1168,9 @@ bool CheckHostPortOptions(const ArgsManager& args) { {"-onion", true}, {"-proxy", true}, {"-rpcbind", false}, +#ifdef WITH_SV2 + {"-sv2bind", false}, +#endif {"-torcontrol", false}, {"-whitebind", false}, {"-zmqpubhashblock", true}, @@ -1978,6 +2007,49 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return false; } +#ifdef WITH_SV2 + if (args.GetBoolArg("-sv2", false)) { + assert(!node.sv2_template_provider); + assert(node.mining); + + Sv2TemplateProviderOptions options{}; + + node.sv2_template_provider = std::make_unique(*node.mining); + + const std::string sv2_port_arg = args.GetArg("-sv2port", ""); + + if (sv2_port_arg.empty()) { + options.port = BaseParams().Sv2Port(); + } else { + if (!ParseUInt16(sv2_port_arg, &options.port) || options.port == 0) { + return InitError(InvalidPortErrMsg("sv2port", sv2_port_arg)); + } + } + + if (gArgs.IsArgSet("-sv2bind")) { // Specific bind address + std::optional sv2_bind{gArgs.GetArg("-sv2bind")}; + if (sv2_bind) { + if (!SplitHostPort(sv2_bind.value(), options.port, options.host)) { + throw std::runtime_error(strprintf("Invalid port %d", options.port)); + } + } + } + + options.fee_delta = gArgs.GetIntArg("-sv2feedelta", Sv2TemplateProviderOptions().fee_delta); + + if (gArgs.IsArgSet("-sv2interval")) { + if (args.GetIntArg("-sv2interval", 0) < 1) { + return InitError(Untranslated("-sv2interval must be at least one second")); + } + options.fee_check_interval = std::chrono::seconds(gArgs.GetIntArg("-sv2interval", 0)); + } + + if (!node.sv2_template_provider->Start(options)) { + return InitError(_("Unable to start Stratum v2 Template Provider")); + } + } +#endif + // ********************************************************* Step 13: finished // At this point, the RPC is "started", but still in warmup, which means it diff --git a/src/node/context.cpp b/src/node/context.cpp index 75dfaee866d8ac..fc1387130a8210 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -17,6 +17,9 @@ #include #include #include +#ifdef WITH_SV2 +#include +#endif #include #include #include diff --git a/src/node/context.h b/src/node/context.h index 8334a84d5b8ac3..61ed967303b63c 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -25,7 +25,9 @@ class ChainstateManager; class ECC_Context; class NetGroupManager; class PeerManager; +#ifdef WITH_SV2 class Sv2TemplateProvider; +#endif namespace interfaces { class Chain; class ChainClient; @@ -40,6 +42,11 @@ namespace util { class SignalInterrupt; } +#ifndef WITH_SV2 +// Dummy +class Sv2TemplateProvider {}; +#endif + namespace node { class KernelNotifications; class Warnings; @@ -72,6 +79,7 @@ struct NodeContext { std::unique_ptr peerman; std::unique_ptr chainman; std::unique_ptr banman; + std::unique_ptr sv2_template_provider; ArgsManager* args{nullptr}; // Currently a raw pointer because the memory is not managed by this struct std::vector indexes; // raw pointers because memory is not managed by this struct std::unique_ptr chain; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b9ae4b8f4cba20..fcc356cbfb9291 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -184,7 +184,8 @@ if(WITH_SV2) sv2_messages_tests.cpp sv2_template_provider_tests.cpp ) - target_link_libraries(test_bitcoin bitcoin_sv2) + # target_link_libraries is not needed here, because bitcoin_sv2 is included + # by bitcoin_node below endif() function(add_boost_test source_file)