From 13525e0c248eab9b199583cde76430c6da2426e2 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Fri, 1 Sep 2023 17:46:23 +0100 Subject: [PATCH 01/63] rpc: add arg helper unit test Compare the results of self.Arg with the request.params accessors to ensure they behave the same way. --- src/test/rpc_tests.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 0d2460c606..934a099661 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -581,4 +581,58 @@ BOOST_AUTO_TEST_CASE(help_example) BOOST_CHECK_NE(HelpExampleRpcNamed("foo", {{"arg", true}}), HelpExampleRpcNamed("foo", {{"arg", "true"}})); } +static void CheckRpc(const std::vector& params, const UniValue& args, RPCHelpMan::RPCMethodImpl test_impl) +{ + auto null_result{RPCResult{RPCResult::Type::NONE, "", "None"}}; + const RPCHelpMan rpc{"dummy", "dummy description", params, null_result, RPCExamples{""}, test_impl}; + JSONRPCRequest req; + req.params = args; + + rpc.HandleRequest(req); +} + +BOOST_AUTO_TEST_CASE(rpc_arg_helper) +{ + constexpr bool DEFAULT_BOOL = true; + constexpr auto DEFAULT_STRING = "default"; + constexpr uint64_t DEFAULT_UINT64_T = 3; + + //! Parameters with which the RPCHelpMan is instantiated + const std::vector params{ + // Required arg + {"req_int", RPCArg::Type::NUM, RPCArg::Optional::NO, ""}, + {"req_str", RPCArg::Type::STR, RPCArg::Optional::NO, ""}, + // Default arg + {"def_uint64_t", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_UINT64_T}, ""}, + {"def_string", RPCArg::Type::STR, RPCArg::Default{DEFAULT_STRING}, ""}, + {"def_bool", RPCArg::Type::BOOL, RPCArg::Default{DEFAULT_BOOL}, ""}, + // Optional arg without default + {"opt_double", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, ""}, + {"opt_string", RPCArg::Type::STR, RPCArg::Optional::OMITTED, ""} + }; + + //! Check that `self.Arg` returns the same value as the `request.params` accessors + RPCHelpMan::RPCMethodImpl check_positional = [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + BOOST_CHECK_EQUAL(self.Arg(0), request.params[0].getInt()); + BOOST_CHECK_EQUAL(self.Arg(1), request.params[1].get_str()); + BOOST_CHECK_EQUAL(self.Arg(2), request.params[2].isNull() ? DEFAULT_UINT64_T : request.params[2].getInt()); + BOOST_CHECK_EQUAL(self.Arg(3), request.params[3].isNull() ? DEFAULT_STRING : request.params[3].get_str()); + BOOST_CHECK_EQUAL(self.Arg(4), request.params[4].isNull() ? DEFAULT_BOOL : request.params[4].get_bool()); + if (!request.params[5].isNull()) { + BOOST_CHECK_EQUAL(self.MaybeArg(5).value(), request.params[5].get_real()); + } else { + BOOST_CHECK(!self.MaybeArg(5)); + } + if (!request.params[6].isNull()) { + BOOST_CHECK(self.MaybeArg(6)); + BOOST_CHECK_EQUAL(*self.MaybeArg(6), request.params[6].get_str()); + } else { + BOOST_CHECK(!self.MaybeArg(6)); + } + return UniValue{}; + }; + CheckRpc(params, UniValue{JSON(R"([5, "hello", null, null, null, null, null])")}, check_positional); + CheckRpc(params, UniValue{JSON(R"([5, "hello", 4, "test", true, 1.23, "world"])")}, check_positional); +} + BOOST_AUTO_TEST_SUITE_END() From bbb31269bfa449e82d3b6a20c2c3481fb3dcc316 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Thu, 18 Jan 2024 17:27:36 +0000 Subject: [PATCH 02/63] rpc: add named arg helper Overload the Arg and MaybeArg helpers to allow accessing arguments by name as well. Also update the docs to document Arg and MaybeArg separately --- src/rpc/util.cpp | 12 ++++++++ src/rpc/util.h | 62 +++++++++++++++++++++++++++++++++++------- src/test/rpc_tests.cpp | 14 ++++++++++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 51c88cc1ba..c90456fe57 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -24,6 +24,8 @@ #include #include +#include +#include #include #include @@ -728,6 +730,16 @@ std::vector> RPCHelpMan::GetArgNames() const return ret; } +size_t RPCHelpMan::GetParamIndex(std::string_view key) const +{ + auto it{std::find_if( + m_args.begin(), m_args.end(), [&key](const auto& arg) { return arg.GetName() == key;} + )}; + + CHECK_NONFATAL(it != m_args.end()); // TODO: ideally this is checked at compile time + return std::distance(m_args.begin(), it); +} + std::string RPCHelpMan::ToString() const { std::string ret; diff --git a/src/rpc/util.h b/src/rpc/util.h index ad3ed97b2e..6b35922d07 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -402,18 +402,25 @@ class RPCHelpMan UniValue HandleRequest(const JSONRPCRequest& request) const; /** - * Helper to get a request argument. - * This function only works during m_fun(), i.e. it should only be used in - * RPC method implementations. The helper internally checks whether the - * user-passed argument isNull() and parses (from JSON) and returns the - * user-passed argument, or the default value derived from the RPCArg - * documentation, or a falsy value if no default was given. + * @brief Helper to get a required or default-valued request argument. * - * Use Arg(i) to get the argument or its default value. Otherwise, - * use MaybeArg(i) to get the optional argument or a falsy value. + * Use this function when the argument is required or when it has a default value. If the + * argument is optional and may not be provided, use MaybeArg instead. * - * The Type passed to this helper must match the corresponding - * RPCArg::Type. + * This function only works during m_fun(), i.e., it should only be used in + * RPC method implementations. It internally checks whether the user-passed + * argument isNull() and parses (from JSON) and returns the user-passed argument, + * or the default value derived from the RPCArg documentation. + * + * There are two overloads of this function: + * - Use Arg(size_t i) to get the argument (or the default value) by index. + * - Use Arg(const std::string& key) to get the argument (or the default value) by key. + * + * The Type passed to this helper must match the corresponding RPCArg::Type. + * + * @return The value of the RPC argument (or the default value) cast to type Type. + * + * @see MaybeArg for handling optional arguments without default values. */ template auto Arg(size_t i) const @@ -427,6 +434,34 @@ class RPCHelpMan return ArgValue(i); } } + template + auto Arg(std::string_view key) const + { + return Arg(GetParamIndex(key)); + } + /** + * @brief Helper to get an optional request argument. + * + * Use this function when the argument is optional and does not have a default value. If the + * argument is required or has a default value, use Arg instead. + * + * This function only works during m_fun(), i.e., it should only be used in + * RPC method implementations. It internally checks whether the user-passed + * argument isNull() and parses (from JSON) and returns the user-passed argument, + * or a falsy value if no argument was passed. + * + * There are two overloads of this function: + * - Use MaybeArg(size_t i) to get the optional argument by index. + * - Use MaybeArg(const std::string& key) to get the optional argument by key. + * + * The Type passed to this helper must match the corresponding RPCArg::Type. + * + * @return For integral and floating-point types, a std::optional is returned. + * For other types, a Type* pointer to the argument is returned. If the + * argument is not provided, std::nullopt or a null pointer is returned. + * + * @see Arg for handling arguments that are required or have a default value. + */ template auto MaybeArg(size_t i) const { @@ -439,6 +474,11 @@ class RPCHelpMan return ArgValue(i); } } + template + auto MaybeArg(std::string_view key) const + { + return MaybeArg(GetParamIndex(key)); + } std::string ToString() const; /** Return the named args that need to be converted from string to another JSON type */ UniValue GetArgMap() const; @@ -458,6 +498,8 @@ class RPCHelpMan mutable const JSONRPCRequest* m_req{nullptr}; // A pointer to the request for the duration of m_fun() template R ArgValue(size_t i) const; + //! Return positional index of a parameter using its name as key. + size_t GetParamIndex(std::string_view key) const; }; /** diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 934a099661..9926fdfdcb 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -633,6 +633,20 @@ BOOST_AUTO_TEST_CASE(rpc_arg_helper) }; CheckRpc(params, UniValue{JSON(R"([5, "hello", null, null, null, null, null])")}, check_positional); CheckRpc(params, UniValue{JSON(R"([5, "hello", 4, "test", true, 1.23, "world"])")}, check_positional); + + //! Check that `self.Arg` returns the same value when using index and key + RPCHelpMan::RPCMethodImpl check_named = [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + BOOST_CHECK_EQUAL(self.Arg(0), self.Arg("req_int")); + BOOST_CHECK_EQUAL(self.Arg(1), self.Arg("req_str")); + BOOST_CHECK_EQUAL(self.Arg(2), self.Arg("def_uint64_t")); + BOOST_CHECK_EQUAL(self.Arg(3), self.Arg("def_string")); + BOOST_CHECK_EQUAL(self.Arg(4), self.Arg("def_bool")); + BOOST_CHECK(self.MaybeArg(5) == self.MaybeArg("opt_double")); + BOOST_CHECK(self.MaybeArg(6) == self.MaybeArg("opt_string")); + return UniValue{}; + }; + CheckRpc(params, UniValue{JSON(R"([5, "hello", null, null, null, null, null])")}, check_named); + CheckRpc(params, UniValue{JSON(R"([5, "hello", 4, "test", true, 1.23, "world"])")}, check_named); } BOOST_AUTO_TEST_SUITE_END() From 30a6c999351041d6a1e8712a9659be1296a1b46a Mon Sep 17 00:00:00 2001 From: stickies-v Date: Thu, 18 Jan 2024 17:27:50 +0000 Subject: [PATCH 03/63] rpc: access some args by name Use the new key-based Arg helper in a few locations to show how it is used. --- src/rpc/blockchain.cpp | 9 +++++---- src/rpc/mining.cpp | 8 ++++---- src/rpc/net.cpp | 6 +++--- src/rpc/signmessage.cpp | 6 +++--- src/wallet/rpc/coins.cpp | 7 ++----- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 50908e9f96..2f6e5c4217 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2149,7 +2149,8 @@ static RPCHelpMan scantxoutset() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { UniValue result(UniValue::VOBJ); - if (request.params[0].get_str() == "status") { + const auto action{self.Arg("action")}; + if (action == "status") { CoinsViewScanReserver reserver; if (reserver.reserve()) { // no scan in progress @@ -2157,7 +2158,7 @@ static RPCHelpMan scantxoutset() } result.pushKV("progress", g_scan_progress.load()); return result; - } else if (request.params[0].get_str() == "abort") { + } else if (action == "abort") { CoinsViewScanReserver reserver; if (reserver.reserve()) { // reserve was possible which means no scan was running @@ -2166,7 +2167,7 @@ static RPCHelpMan scantxoutset() // set the abort flag g_should_abort_scan = true; return true; - } else if (request.params[0].get_str() == "start") { + } else if (action == "start") { CoinsViewScanReserver reserver; if (!reserver.reserve()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Scan already in progress, use action \"abort\" or \"status\""); @@ -2235,7 +2236,7 @@ static RPCHelpMan scantxoutset() result.pushKV("unspents", unspents); result.pushKV("total_amount", ValueFromAmount(total_in)); } else { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", request.params[0].get_str())); + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid action '%s'", action)); } return result; }, diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index ff39a31a43..bb50de3489 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -122,7 +122,7 @@ static RPCHelpMan getnetworkhashps() { ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); - return GetNetworkHashPS(self.Arg(0), self.Arg(1), chainman.ActiveChain()); + return GetNetworkHashPS(self.Arg("nblocks"), self.Arg("height"), chainman.ActiveChain()); }, }; } @@ -229,12 +229,12 @@ static RPCHelpMan generatetodescriptor() "\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const auto num_blocks{self.Arg(0)}; - const auto max_tries{self.Arg(2)}; + const auto num_blocks{self.Arg("num_blocks")}; + const auto max_tries{self.Arg("maxtries")}; CScript coinbase_script; std::string error; - if (!getScriptFromDescriptor(self.Arg(1), coinbase_script, error)) { + if (!getScriptFromDescriptor(self.Arg("descriptor"), coinbase_script, error)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error); } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 5e6f42b596..666d1586b8 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -322,7 +322,7 @@ static RPCHelpMan addnode() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const std::string command{request.params[1].get_str()}; + const auto command{self.Arg("command")}; if (command != "onetry" && command != "add" && command != "remove") { throw std::runtime_error( self.ToString()); @@ -331,9 +331,9 @@ static RPCHelpMan addnode() NodeContext& node = EnsureAnyNodeContext(request.context); CConnman& connman = EnsureConnman(node); - const std::string node_arg{request.params[0].get_str()}; + const auto node_arg{self.Arg("node")}; bool node_v2transport = connman.GetLocalServices() & NODE_P2P_V2; - bool use_v2transport = self.MaybeArg(2).value_or(node_v2transport); + bool use_v2transport = self.MaybeArg("v2transport").value_or(node_v2transport); if (use_v2transport && !node_v2transport) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Error: v2transport requested but not enabled (see -v2transport)"); diff --git a/src/rpc/signmessage.cpp b/src/rpc/signmessage.cpp index 8c752ba1fd..9f3c24efcf 100644 --- a/src/rpc/signmessage.cpp +++ b/src/rpc/signmessage.cpp @@ -38,9 +38,9 @@ static RPCHelpMan verifymessage() }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - std::string strAddress = request.params[0].get_str(); - std::string strSign = request.params[1].get_str(); - std::string strMessage = request.params[2].get_str(); + std::string strAddress = self.Arg("address"); + std::string strSign = self.Arg("signature"); + std::string strMessage = self.Arg("message"); switch (MessageVerify(strAddress, strSign, strMessage)) { case MessageVerificationResult::ERR_INVALID_ADDRESS: diff --git a/src/wallet/rpc/coins.cpp b/src/wallet/rpc/coins.cpp index 0cb0891141..b6c7396f4b 100644 --- a/src/wallet/rpc/coins.cpp +++ b/src/wallet/rpc/coins.cpp @@ -194,15 +194,12 @@ RPCHelpMan getbalance() LOCK(pwallet->cs_wallet); - const auto dummy_value{self.MaybeArg(0)}; + const auto dummy_value{self.MaybeArg("dummy")}; if (dummy_value && *dummy_value != "*") { throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\"."); } - int min_depth = 0; - if (!request.params[1].isNull()) { - min_depth = request.params[1].getInt(); - } + const auto min_depth{self.Arg("minconf")}; bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet); From 2179e2c3209a41c1419f1f5ed6270a0dad68b50d Mon Sep 17 00:00:00 2001 From: brunoerg Date: Tue, 2 Apr 2024 09:01:15 -0300 Subject: [PATCH 04/63] doc: i2p: improve `-i2pacceptincoming` mention --- doc/i2p.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/i2p.md b/doc/i2p.md index b6c07388b7..b769a74df4 100644 --- a/doc/i2p.md +++ b/doc/i2p.md @@ -79,8 +79,8 @@ one of the networks has issues. ## Persistent vs transient I2P addresses The first time Bitcoin Core connects to the I2P router, it automatically -generates a persistent I2P address and its corresponding private key by default -or if `-i2pacceptincoming=1` is set. The private key is saved in a file named +generates a persistent I2P address and its corresponding private key by default, +unless `-i2pacceptincoming=0` is set. The private key is saved in a file named `i2p_private_key` in the Bitcoin Core data directory. The persistent I2P address is used for making outbound connections and accepting inbound connections. From 038fd979effb54ee76ce1b7cf078e920c652326a Mon Sep 17 00:00:00 2001 From: dergoegge Date: Fri, 25 Nov 2022 15:31:04 +0000 Subject: [PATCH 05/63] [net processing] Move nTimeOffset to net_processing --- src/net.cpp | 1 - src/net.h | 2 -- src/net_processing.cpp | 10 +++++++--- src/net_processing.h | 1 + src/qt/guiutil.cpp | 4 ++-- src/qt/guiutil.h | 4 ++-- src/qt/rpcconsole.cpp | 2 +- src/rpc/net.cpp | 2 +- 8 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/net.cpp b/src/net.cpp index e388f05b03..a1154b60eb 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -599,7 +599,6 @@ void CNode::CopyStats(CNodeStats& stats) X(m_last_tx_time); X(m_last_block_time); X(m_connected); - X(nTimeOffset); X(m_addr_name); X(nVersion); { diff --git a/src/net.h b/src/net.h index 46d9422695..f1911fa2ce 100644 --- a/src/net.h +++ b/src/net.h @@ -191,7 +191,6 @@ class CNodeStats std::chrono::seconds m_last_tx_time; std::chrono::seconds m_last_block_time; std::chrono::seconds m_connected; - int64_t nTimeOffset; std::string m_addr_name; int nVersion; std::string cleanSubVer; @@ -703,7 +702,6 @@ class CNode std::atomic m_last_recv{0s}; //! Unix epoch time at peer connection const std::chrono::seconds m_connected; - std::atomic nTimeOffset{0}; // Address of this peer const CAddress addr; // Bind address of our side of the connection diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6996af38cb..fe48aa25a9 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -390,6 +390,10 @@ struct Peer { /** Whether this peer wants invs or headers (when possible) for block announcements */ bool m_prefers_headers GUARDED_BY(NetEventsInterface::g_msgproc_mutex){false}; + /** Time offset computed during the version handshake based on the + * timestamp the peer sent in the version message. */ + std::atomic m_time_offset{0}; + explicit Peer(NodeId id, ServiceFlags our_services) : m_id{id} , m_our_services{our_services} @@ -1792,6 +1796,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c stats.presync_height = peer->m_headers_sync->GetPresyncHeight(); } } + stats.time_offset = peer->m_time_offset; return true; } @@ -3666,12 +3671,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(), remoteAddr, (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : "")); - int64_t nTimeOffset = nTime - GetTime(); - pfrom.nTimeOffset = nTimeOffset; + peer->m_time_offset = nTime - GetTime(); if (!pfrom.IsInboundConn()) { // Don't use timedata samples from inbound peers to make it // harder for others to tamper with our adjusted time. - AddTimeData(pfrom.addr, nTimeOffset); + AddTimeData(pfrom.addr, peer->m_time_offset); } // If the peer is old enough to have the old alert system, send it the final alert. diff --git a/src/net_processing.h b/src/net_processing.h index f8d7a8f511..e00946ea64 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -41,6 +41,7 @@ struct CNodeStateStats { bool m_addr_relay_enabled{false}; ServiceFlags their_services; int64_t presync_height{-1}; + int64_t time_offset{0}; }; class PeerManager : public CValidationInterface, public NetEventsInterface diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 084b9a6615..5f5e002db7 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -771,9 +771,9 @@ QString formatPingTime(std::chrono::microseconds ping_time) QObject::tr("%1 ms").arg(QString::number((int)(count_microseconds(ping_time) / 1000), 10)); } -QString formatTimeOffset(int64_t nTimeOffset) +QString formatTimeOffset(int64_t time_offset) { - return QObject::tr("%1 s").arg(QString::number((int)nTimeOffset, 10)); + return QObject::tr("%1 s").arg(QString::number((int)time_offset, 10)); } QString formatNiceTimeOffset(qint64 secs) diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 7f06fdfe37..3e28e54557 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -240,8 +240,8 @@ namespace GUIUtil /** Format a CNodeStats.m_last_ping_time into a user-readable string or display N/A, if 0 */ QString formatPingTime(std::chrono::microseconds ping_time); - /** Format a CNodeCombinedStats.nTimeOffset into a user-readable string */ - QString formatTimeOffset(int64_t nTimeOffset); + /** Format a CNodeStateStats.time_offset into a user-readable string */ + QString formatTimeOffset(int64_t time_offset); QString formatNiceTimeOffset(qint64 secs); diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index d2b184ebdf..cc51e413ee 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -1196,7 +1196,6 @@ void RPCConsole::updateDetailWidget() ui->peerBytesRecv->setText(GUIUtil::formatBytes(stats->nodeStats.nRecvBytes)); ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.m_last_ping_time)); ui->peerMinPing->setText(GUIUtil::formatPingTime(stats->nodeStats.m_min_ping_time)); - ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset)); if (stats->nodeStats.nVersion) { ui->peerVersion->setText(QString::number(stats->nodeStats.nVersion)); } @@ -1228,6 +1227,7 @@ void RPCConsole::updateDetailWidget() // This check fails for example if the lock was busy and // nodeStateStats couldn't be fetched. if (stats->fNodeStateStatsAvailable) { + ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStateStats.time_offset)); ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStateStats.their_services)); // Sync height is init to -1 if (stats->nodeStateStats.nSyncHeight > -1) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 3fa2b18495..14eae8c5df 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -239,7 +239,7 @@ static RPCHelpMan getpeerinfo() obj.pushKV("bytessent", stats.nSendBytes); obj.pushKV("bytesrecv", stats.nRecvBytes); obj.pushKV("conntime", count_seconds(stats.m_connected)); - obj.pushKV("timeoffset", stats.nTimeOffset); + obj.pushKV("timeoffset", statestats.time_offset); if (stats.m_last_ping_time > 0us) { obj.pushKV("pingtime", Ticks(stats.m_last_ping_time)); } From 55361a15d1aa6984051441bce88112000688fb43 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Sat, 3 Feb 2024 17:15:41 +0000 Subject: [PATCH 06/63] [net processing] Use std::chrono for type-safe time offsets --- src/net_processing.cpp | 6 +++--- src/net_processing.h | 4 +++- src/qt/rpcconsole.cpp | 3 ++- src/rpc/net.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index fe48aa25a9..363de48022 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -392,7 +392,7 @@ struct Peer { /** Time offset computed during the version handshake based on the * timestamp the peer sent in the version message. */ - std::atomic m_time_offset{0}; + std::atomic m_time_offset{0s}; explicit Peer(NodeId id, ServiceFlags our_services) : m_id{id} @@ -3671,11 +3671,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(), remoteAddr, (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : "")); - peer->m_time_offset = nTime - GetTime(); + peer->m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now(); if (!pfrom.IsInboundConn()) { // Don't use timedata samples from inbound peers to make it // harder for others to tamper with our adjusted time. - AddTimeData(pfrom.addr, peer->m_time_offset); + AddTimeData(pfrom.addr, Ticks(peer->m_time_offset.load())); } // If the peer is old enough to have the old alert system, send it the final alert. diff --git a/src/net_processing.h b/src/net_processing.h index e00946ea64..452a973d54 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -9,6 +9,8 @@ #include #include +#include + class AddrMan; class CChainParams; class CTxMemPool; @@ -41,7 +43,7 @@ struct CNodeStateStats { bool m_addr_relay_enabled{false}; ServiceFlags their_services; int64_t presync_height{-1}; - int64_t time_offset{0}; + std::chrono::seconds time_offset{0}; }; class PeerManager : public CValidationInterface, public NetEventsInterface diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index cc51e413ee..bafef62945 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -1227,7 +1228,7 @@ void RPCConsole::updateDetailWidget() // This check fails for example if the lock was busy and // nodeStateStats couldn't be fetched. if (stats->fNodeStateStatsAvailable) { - ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStateStats.time_offset)); + ui->timeoffset->setText(GUIUtil::formatTimeOffset(Ticks(stats->nodeStateStats.time_offset))); ui->peerServices->setText(GUIUtil::formatServicesStr(stats->nodeStateStats.their_services)); // Sync height is init to -1 if (stats->nodeStateStats.nSyncHeight > -1) { diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 14eae8c5df..176cf0e404 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -239,7 +239,7 @@ static RPCHelpMan getpeerinfo() obj.pushKV("bytessent", stats.nSendBytes); obj.pushKV("bytesrecv", stats.nRecvBytes); obj.pushKV("conntime", count_seconds(stats.m_connected)); - obj.pushKV("timeoffset", statestats.time_offset); + obj.pushKV("timeoffset", Ticks(statestats.time_offset)); if (stats.m_last_ping_time > 0us) { obj.pushKV("pingtime", Ticks(stats.m_last_ping_time)); } From ee178dfcc1175e0af8163216c9c024f4bfc97965 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Thu, 7 Mar 2024 11:23:00 +0000 Subject: [PATCH 07/63] Add TimeOffsets helper class This helper class is an alternative to CMedianFilter, but without a lot of the special logic and exceptions that we needed while it was still used for consensus. --- src/Makefile.am | 2 + src/Makefile.test.include | 2 + src/net_processing.cpp | 9 +++- src/node/timeoffsets.cpp | 69 ++++++++++++++++++++++++++++ src/node/timeoffsets.h | 39 ++++++++++++++++ src/test/fuzz/timeoffsets.cpp | 28 +++++++++++ src/test/timeoffsets_tests.cpp | 69 ++++++++++++++++++++++++++++ src/warnings.cpp | 11 +++++ src/warnings.h | 3 ++ test/functional/feature_maxtipage.py | 4 ++ 10 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 src/node/timeoffsets.cpp create mode 100644 src/node/timeoffsets.h create mode 100644 src/test/fuzz/timeoffsets.cpp create mode 100644 src/test/timeoffsets_tests.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 1f55bfbafd..383767a5a0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -233,6 +233,7 @@ BITCOIN_CORE_H = \ node/peerman_args.h \ node/protocol_version.h \ node/psbt.h \ + node/timeoffsets.h \ node/transaction.h \ node/txreconciliation.h \ node/utxo_snapshot.h \ @@ -435,6 +436,7 @@ libbitcoin_node_a_SOURCES = \ node/minisketchwrapper.cpp \ node/peerman_args.cpp \ node/psbt.cpp \ + node/timeoffsets.cpp \ node/transaction.cpp \ node/txreconciliation.cpp \ node/utxo_snapshot.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9f9bdbbd0c..fb703a0b8c 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -152,6 +152,7 @@ BITCOIN_TESTS =\ test/sync_tests.cpp \ test/system_tests.cpp \ test/timedata_tests.cpp \ + test/timeoffsets_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ test/translation_tests.cpp \ @@ -382,6 +383,7 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/strprintf.cpp \ test/fuzz/system.cpp \ test/fuzz/timedata.cpp \ + test/fuzz/timeoffsets.cpp \ test/fuzz/torcontrol.cpp \ test/fuzz/transaction.cpp \ test/fuzz/tx_in.cpp \ diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 363de48022..b549178677 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -753,6 +754,8 @@ class PeerManagerImpl final : public PeerManager /** Next time to check for stale tip */ std::chrono::seconds m_stale_tip_check_time GUARDED_BY(cs_main){0s}; + TimeOffsets m_outbound_time_offsets; + const Options m_opts; bool RejectIncomingTxs(const CNode& peer) const; @@ -3673,9 +3676,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, peer->m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now(); if (!pfrom.IsInboundConn()) { - // Don't use timedata samples from inbound peers to make it - // harder for others to tamper with our adjusted time. + // Don't use time offset samples from inbound peers to make it + // harder for others to create false warnings about our clock being out of sync. AddTimeData(pfrom.addr, Ticks(peer->m_time_offset.load())); + m_outbound_time_offsets.Add(peer->m_time_offset); + m_outbound_time_offsets.WarnIfOutOfSync(); } // If the peer is old enough to have the old alert system, send it the final alert. diff --git a/src/node/timeoffsets.cpp b/src/node/timeoffsets.cpp new file mode 100644 index 0000000000..62f527be8a --- /dev/null +++ b/src/node/timeoffsets.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2024-present 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 + +using namespace std::chrono_literals; + +void TimeOffsets::Add(std::chrono::seconds offset) +{ + LOCK(m_mutex); + + if (m_offsets.size() >= MAX_SIZE) { + m_offsets.pop_front(); + } + m_offsets.push_back(offset); + LogDebug(BCLog::NET, "Added time offset %+ds, total samples %d\n", + Ticks(offset), m_offsets.size()); +} + +std::chrono::seconds TimeOffsets::Median() const +{ + LOCK(m_mutex); + + // Only calculate the median if we have 5 or more offsets + if (m_offsets.size() < 5) return 0s; + + auto sorted_copy = m_offsets; + std::sort(sorted_copy.begin(), sorted_copy.end()); + return sorted_copy[sorted_copy.size() / 2]; // approximate median is good enough, keep it simple +} + +bool TimeOffsets::WarnIfOutOfSync() const +{ + // when median == std::numeric_limits::min(), calling std::chrono::abs is UB + auto median{std::max(Median(), std::chrono::seconds(std::numeric_limits::min() + 1))}; + if (std::chrono::abs(median) <= WARN_THRESHOLD) { + SetMedianTimeOffsetWarning(std::nullopt); + uiInterface.NotifyAlertChanged(); + return false; + } + + bilingual_str msg{strprintf(_( + "Your computer's date and time appear to be more than %d minutes out of sync with the network, " + "this may lead to consensus failure. After you've confirmed your computer's clock, this message " + "should no longer appear when you restart your node. Without a restart, it should stop showing " + "automatically after you've connected to a sufficient number of new outbound peers, which may " + "take some time. You can inspect the `timeoffset` field of the `getpeerinfo` and `getnetworkinfo` " + "RPC methods to get more info." + ), Ticks(WARN_THRESHOLD))}; + LogWarning("%s\n", msg.original); + SetMedianTimeOffsetWarning(msg); + uiInterface.NotifyAlertChanged(); + return true; +} diff --git a/src/node/timeoffsets.h b/src/node/timeoffsets.h new file mode 100644 index 0000000000..2b12584e12 --- /dev/null +++ b/src/node/timeoffsets.h @@ -0,0 +1,39 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_NODE_TIMEOFFSETS_H +#define BITCOIN_NODE_TIMEOFFSETS_H + +#include + +#include +#include +#include + +class TimeOffsets +{ + //! Maximum number of timeoffsets stored. + static constexpr size_t MAX_SIZE{50}; + //! Minimum difference between system and network time for a warning to be raised. + static constexpr std::chrono::minutes WARN_THRESHOLD{10}; + + mutable Mutex m_mutex; + /** The observed time differences between our local clock and those of our outbound peers. A + * positive offset means our peer's clock is ahead of our local clock. */ + std::deque m_offsets GUARDED_BY(m_mutex){}; + +public: + /** Add a new time offset sample. */ + void Add(std::chrono::seconds offset) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + + /** Compute and return the median of the collected time offset samples. The median is returned + * as 0 when there are less than 5 samples. */ + std::chrono::seconds Median() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); + + /** Raise warnings if the median time offset exceeds the warnings threshold. Returns true if + * warnings were raised. */ + bool WarnIfOutOfSync() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex); +}; + +#endif // BITCOIN_NODE_TIMEOFFSETS_H diff --git a/src/test/fuzz/timeoffsets.cpp b/src/test/fuzz/timeoffsets.cpp new file mode 100644 index 0000000000..019337a94a --- /dev/null +++ b/src/test/fuzz/timeoffsets.cpp @@ -0,0 +1,28 @@ +// Copyright (c) 2024-present 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 + +void initialize_timeoffsets() +{ + static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN); +} + +FUZZ_TARGET(timeoffsets, .init = initialize_timeoffsets) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + TimeOffsets offsets{}; + LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 4'000) { + (void)offsets.Median(); + offsets.Add(std::chrono::seconds{fuzzed_data_provider.ConsumeIntegral()}); + offsets.WarnIfOutOfSync(); + } +} diff --git a/src/test/timeoffsets_tests.cpp b/src/test/timeoffsets_tests.cpp new file mode 100644 index 0000000000..008f1a9db9 --- /dev/null +++ b/src/test/timeoffsets_tests.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2024-present 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 + +using namespace std::chrono_literals; + +static void AddMulti(TimeOffsets& offsets, const std::vector& to_add) +{ + for (auto offset : to_add) { + offsets.Add(offset); + } +} + +BOOST_FIXTURE_TEST_SUITE(timeoffsets_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(timeoffsets) +{ + TimeOffsets offsets{}; + BOOST_CHECK(offsets.Median() == 0s); + + AddMulti(offsets, {{0s, -1s, -2s, -3s}}); + // median should be zero for < 5 offsets + BOOST_CHECK(offsets.Median() == 0s); + + offsets.Add(-4s); + // we now have 5 offsets: [-4, -3, -2, -1, 0] + BOOST_CHECK(offsets.Median() == -2s); + + AddMulti(offsets, {4, 5s}); + // we now have 9 offsets: [-4, -3, -2, -1, 0, 5, 5, 5, 5] + BOOST_CHECK(offsets.Median() == 0s); + + AddMulti(offsets, {41, 10s}); + // the TimeOffsets is now at capacity with 50 offsets, oldest offsets is discarded for any additional offset + BOOST_CHECK(offsets.Median() == 10s); + + AddMulti(offsets, {25, 15s}); + // we now have 25 offsets of 10s followed by 25 offsets of 15s + BOOST_CHECK(offsets.Median() == 15s); +} + +static bool IsWarningRaised(const std::vector& check_offsets) +{ + TimeOffsets offsets{}; + AddMulti(offsets, check_offsets); + return offsets.WarnIfOutOfSync(); +} + + +BOOST_AUTO_TEST_CASE(timeoffsets_warning) +{ + BOOST_CHECK(IsWarningRaised({{-60min, -40min, -30min, 0min, 10min}})); + BOOST_CHECK(IsWarningRaised({5, 11min})); + + BOOST_CHECK(!IsWarningRaised({4, 60min})); + BOOST_CHECK(!IsWarningRaised({100, 3min})); +} + + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/warnings.cpp b/src/warnings.cpp index 84b021dad5..d55eecc48d 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -14,11 +14,13 @@ #include #include +#include #include static GlobalMutex g_warnings_mutex; static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex); static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false; +static std::optional g_timeoffset_warning GUARDED_BY(g_warnings_mutex){}; void SetMiscWarning(const bilingual_str& warning) { @@ -32,6 +34,11 @@ void SetfLargeWorkInvalidChainFound(bool flag) fLargeWorkInvalidChainFound = flag; } +void SetMedianTimeOffsetWarning(std::optional warning) +{ + LOCK(g_warnings_mutex); + g_timeoffset_warning = warning; +} bilingual_str GetWarnings(bool verbose) { bilingual_str warnings_concise; @@ -56,6 +63,10 @@ bilingual_str GetWarnings(bool verbose) warnings_verbose.emplace_back(warnings_concise); } + if (g_timeoffset_warning) { + warnings_verbose.emplace_back(g_timeoffset_warning.value()); + } + if (verbose) { return Join(warnings_verbose, Untranslated("
")); } diff --git a/src/warnings.h b/src/warnings.h index b21e2ea2b8..866bce6246 100644 --- a/src/warnings.h +++ b/src/warnings.h @@ -6,12 +6,15 @@ #ifndef BITCOIN_WARNINGS_H #define BITCOIN_WARNINGS_H +#include #include struct bilingual_str; void SetMiscWarning(const bilingual_str& warning); void SetfLargeWorkInvalidChainFound(bool flag); +/** Pass std::nullopt to disable the warning */ +void SetMedianTimeOffsetWarning(std::optional warning); /** Format a string that describes several potential problems detected by the core. * @param[in] verbose bool * - if true, get all warnings separated by
diff --git a/test/functional/feature_maxtipage.py b/test/functional/feature_maxtipage.py index 51f37ef1e0..a1774a5395 100755 --- a/test/functional/feature_maxtipage.py +++ b/test/functional/feature_maxtipage.py @@ -43,6 +43,10 @@ def test_maxtipage(self, maxtipage, set_parameter=True, test_deltas=True): self.generate(node_miner, 1) assert_equal(node_ibd.getblockchaininfo()['initialblockdownload'], False) + # reset time to system time so we don't have a time offset with the ibd node the next + # time we connect to it, ensuring TimeOffsets::WarnIfOutOfSync() doesn't output to stderr + node_miner.setmocktime(0) + def run_test(self): self.log.info("Test IBD with maximum tip age of 24 hours (default).") self.test_maxtipage(DEFAULT_MAX_TIP_AGE, set_parameter=False) From 7d9c3ec622d73a98d07ab3cee78751718982a5bc Mon Sep 17 00:00:00 2001 From: dergoegge Date: Mon, 27 Nov 2023 17:22:41 +0000 Subject: [PATCH 08/63] [net processing] Introduce PeerManagerInfo For querying statistics/info from PeerManager. The median outbound time offset is the only initial field. --- src/net_processing.cpp | 8 ++++++++ src/net_processing.h | 7 +++++++ src/rpc/net.cpp | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index b549178677..6289d13989 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -518,6 +518,7 @@ class PeerManagerImpl final : public PeerManager std::optional FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); + PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); bool IgnoresIncomingTxs() override { return m_opts.ignore_incoming_txs; } void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); @@ -1804,6 +1805,13 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c return true; } +PeerManagerInfo PeerManagerImpl::GetInfo() const +{ + return PeerManagerInfo{ + .median_outbound_time_offset = m_outbound_time_offsets.Median(), + }; +} + void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx) { if (m_opts.max_extra_txs <= 0) diff --git a/src/net_processing.h b/src/net_processing.h index 452a973d54..d0ff02311b 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -46,6 +46,10 @@ struct CNodeStateStats { std::chrono::seconds time_offset{0}; }; +struct PeerManagerInfo { + std::chrono::seconds median_outbound_time_offset{0s}; +}; + class PeerManager : public CValidationInterface, public NetEventsInterface { public: @@ -86,6 +90,9 @@ class PeerManager : public CValidationInterface, public NetEventsInterface /** Get statistics from node state */ virtual bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const = 0; + /** Get peer manager info. */ + virtual PeerManagerInfo GetInfo() const = 0; + /** Whether this node ignores txs received over p2p. */ virtual bool IgnoresIncomingTxs() = 0; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 176cf0e404..823b6d620f 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -679,9 +678,10 @@ static RPCHelpMan getnetworkinfo() obj.pushKV("localservicesnames", GetServicesNames(services)); } if (node.peerman) { + auto peerman_info{node.peerman->GetInfo()}; obj.pushKV("localrelay", !node.peerman->IgnoresIncomingTxs()); + obj.pushKV("timeoffset", Ticks(peerman_info.median_outbound_time_offset)); } - obj.pushKV("timeoffset", GetTimeOffset()); if (node.connman) { obj.pushKV("networkactive", node.connman->GetNetworkActive()); obj.pushKV("connections", node.connman->GetNodeCount(ConnectionDirection::Both)); From 92e72b5d0d49aa395e626c238bc28aba8e4c3d44 Mon Sep 17 00:00:00 2001 From: dergoegge Date: Wed, 29 Nov 2023 12:03:49 +0000 Subject: [PATCH 09/63] [net processing] Move IgnoresIncomingTxs to PeerManagerInfo --- src/net_processing.cpp | 2 +- src/net_processing.h | 4 +--- src/rpc/net.cpp | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 6289d13989..0a6f180ab4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -519,7 +519,6 @@ class PeerManagerImpl final : public PeerManager EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); PeerManagerInfo GetInfo() const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); - bool IgnoresIncomingTxs() override { return m_opts.ignore_incoming_txs; } void SendPings() override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void RelayTransaction(const uint256& txid, const uint256& wtxid) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex); void SetBestBlock(int height, std::chrono::seconds time) override @@ -1809,6 +1808,7 @@ PeerManagerInfo PeerManagerImpl::GetInfo() const { return PeerManagerInfo{ .median_outbound_time_offset = m_outbound_time_offsets.Median(), + .ignores_incoming_txs = m_opts.ignore_incoming_txs, }; } diff --git a/src/net_processing.h b/src/net_processing.h index d0ff02311b..85e399d948 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -48,6 +48,7 @@ struct CNodeStateStats { struct PeerManagerInfo { std::chrono::seconds median_outbound_time_offset{0s}; + bool ignores_incoming_txs{false}; }; class PeerManager : public CValidationInterface, public NetEventsInterface @@ -93,9 +94,6 @@ class PeerManager : public CValidationInterface, public NetEventsInterface /** Get peer manager info. */ virtual PeerManagerInfo GetInfo() const = 0; - /** Whether this node ignores txs received over p2p. */ - virtual bool IgnoresIncomingTxs() = 0; - /** Relay transaction to all peers. */ virtual void RelayTransaction(const uint256& txid, const uint256& wtxid) = 0; diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 823b6d620f..e3d50917a5 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -679,7 +679,7 @@ static RPCHelpMan getnetworkinfo() } if (node.peerman) { auto peerman_info{node.peerman->GetInfo()}; - obj.pushKV("localrelay", !node.peerman->IgnoresIncomingTxs()); + obj.pushKV("localrelay", !peerman_info.ignores_incoming_txs); obj.pushKV("timeoffset", Ticks(peerman_info.median_outbound_time_offset)); } if (node.connman) { From c6be144c4b774a03a8bcab5a165768cf81e9b06b Mon Sep 17 00:00:00 2001 From: stickies-v Date: Sun, 4 Feb 2024 05:08:26 +0000 Subject: [PATCH 10/63] Remove timedata With the introduction and usage of TimeOffsets, there is no more need for this file. Remove it. --- src/Makefile.am | 2 - src/Makefile.test.include | 2 - src/addrman_impl.h | 1 - src/init.cpp | 2 - src/net_processing.cpp | 4 +- src/test/denialofservice_tests.cpp | 2 - src/test/fuzz/timedata.cpp | 31 -------- src/test/net_tests.cpp | 5 -- src/test/timedata_tests.cpp | 105 -------------------------- src/timedata.cpp | 116 ----------------------------- src/timedata.h | 82 -------------------- 11 files changed, 1 insertion(+), 351 deletions(-) delete mode 100644 src/test/fuzz/timedata.cpp delete mode 100644 src/test/timedata_tests.cpp delete mode 100644 src/timedata.cpp delete mode 100644 src/timedata.h diff --git a/src/Makefile.am b/src/Makefile.am index 383767a5a0..43d487c6dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -284,7 +284,6 @@ BITCOIN_CORE_H = \ support/lockedpool.h \ sync.h \ threadsafety.h \ - timedata.h \ torcontrol.h \ txdb.h \ txmempool.h \ @@ -464,7 +463,6 @@ libbitcoin_node_a_SOURCES = \ rpc/txoutproof.cpp \ script/sigcache.cpp \ signet.cpp \ - timedata.cpp \ torcontrol.cpp \ txdb.cpp \ txmempool.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index fb703a0b8c..c20b531032 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -151,7 +151,6 @@ BITCOIN_TESTS =\ test/streams_tests.cpp \ test/sync_tests.cpp \ test/system_tests.cpp \ - test/timedata_tests.cpp \ test/timeoffsets_tests.cpp \ test/torcontrol_tests.cpp \ test/transaction_tests.cpp \ @@ -382,7 +381,6 @@ test_fuzz_fuzz_SOURCES = \ test/fuzz/string.cpp \ test/fuzz/strprintf.cpp \ test/fuzz/system.cpp \ - test/fuzz/timedata.cpp \ test/fuzz/timeoffsets.cpp \ test/fuzz/torcontrol.cpp \ test/fuzz/transaction.cpp \ diff --git a/src/addrman_impl.h b/src/addrman_impl.h index 867c894d01..dd7f7b318f 100644 --- a/src/addrman_impl.h +++ b/src/addrman_impl.h @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/src/init.cpp b/src/init.cpp index 0aa04755cb..bc49a14c6c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -67,7 +67,6 @@ #include #include