From 06bf649e1b9685bee70aa0940b14e929bf2a1e80 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Fri, 12 Nov 2021 15:20:53 -0500 Subject: [PATCH 01/13] merge bitcoin#23499: Add interfaces::Node::broadCastTransaction method --- src/interfaces/node.h | 4 ++++ src/node/interfaces.cpp | 4 ++++ src/qt/psbtoperationsdialog.cpp | 4 ++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/interfaces/node.h b/src/interfaces/node.h index cda4c1add15ae..11d6a936d01d5 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -35,6 +35,7 @@ class UniValue; class Proxy; struct bilingual_str; enum class SynchronizationState; +enum class TransactionError; struct CNodeStateStats; struct NodeContext; @@ -264,6 +265,9 @@ class Node //! Get unspent outputs associated with a transaction. virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0; + //! Broadcast transaction. + virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, bilingual_str& err_string) = 0; + //! Get wallet loader. virtual WalletLoader& walletLoader() = 0; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e1418aa442b25..d257321a11017 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -496,6 +496,10 @@ class NodeImpl : public Node LOCK(::cs_main); return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin); } + TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, bilingual_str& err_string) override + { + return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false); + } WalletLoader& walletLoader() override { return *Assert(m_context->wallet_loader); diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index 25ac248e58724..9811e7ec5031a 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -108,8 +108,8 @@ void PSBTOperationsDialog::broadcastTransaction() CTransactionRef tx = MakeTransactionRef(mtx); bilingual_str err_string; - TransactionError error = BroadcastTransaction( - *m_client_model->node().context(), tx, err_string, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true, /* await_callback */ false); + TransactionError error = + m_client_model->node().broadcastTransaction(tx, DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), err_string); if (error == TransactionError::OK) { showStatus(tr("Transaction broadcast successfully! Transaction ID: %1") From 9aacee78ae0408d55db21636d2d64c62c84847c0 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 27 Oct 2024 20:23:12 +0000 Subject: [PATCH 02/13] merge bitcoin#23832: Changes time variables from int to chrono includes: - fe86eb50c986f7b5ccce63f984d8a51cd9ee9e2c continuation of 9399f90a in dash#6097 --- src/net_processing.cpp | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0ac9e317f4558..5b8c1241d2c93 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -78,11 +78,11 @@ static constexpr int32_t MAX_PEER_OBJECT_IN_FLIGHT = 100; /** Maximum number of announced objects from a peer */ static constexpr int32_t MAX_PEER_OBJECT_ANNOUNCEMENTS = 2 * MAX_INV_SZ; /** How many microseconds to delay requesting transactions from inbound peers */ -static constexpr std::chrono::microseconds INBOUND_PEER_TX_DELAY{std::chrono::seconds{2}}; -/** How long to wait (in microseconds) before downloading a transaction from an additional peer */ -static constexpr std::chrono::microseconds GETDATA_TX_INTERVAL{std::chrono::seconds{60}}; -/** Maximum delay (in microseconds) for transaction requests to avoid biasing some peers over others. */ -static constexpr std::chrono::microseconds MAX_GETDATA_RANDOM_DELAY{std::chrono::seconds{2}}; +static constexpr auto INBOUND_PEER_TX_DELAY{2s}; +/** How long to wait before downloading a transaction from an additional peer */ +static constexpr auto GETDATA_TX_INTERVAL{60s}; +/** Maximum delay for transaction requests to avoid biasing some peers over others. */ +static constexpr auto MAX_GETDATA_RANDOM_DELAY{2s}; /** How long to wait (expiry * factor microseconds) before expiring an in-flight getdata request to a peer */ static constexpr int64_t TX_EXPIRY_INTERVAL_FACTOR = 10; static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY, @@ -111,7 +111,7 @@ static constexpr auto STALE_CHECK_INTERVAL{150s}; // 2.5 minutes (~block interva /** How frequently to check for extra outbound peers and disconnect */ static constexpr auto EXTRA_PEER_CHECK_INTERVAL{45s}; /** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict */ -static constexpr std::chrono::seconds MINIMUM_CONNECT_TIME{30}; +static constexpr auto MINIMUM_CONNECT_TIME{30s}; /** SHA256("main address relay")[0:8] */ static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; /// Age after which a stale block will no longer be served if requested as @@ -121,7 +121,7 @@ static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60; /// limiting block relay. Set to one week, denominated in seconds. static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60; /** Time between pings automatically sent out for latency probing and keepalive */ -static constexpr std::chrono::minutes PING_INTERVAL{2}; +static constexpr auto PING_INTERVAL{2min}; /** The maximum number of entries in a locator */ static const unsigned int MAX_LOCATOR_SZ = 101; /** Number of blocks that can be requested at any given time from a single peer. */ @@ -152,17 +152,17 @@ static const int MAX_UNCONNECTING_HEADERS = 10; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; /** Average delay between local address broadcasts */ -static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24h; +static constexpr auto AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24h}; /** Average delay between peer address broadcasts */ -static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL = 30s; +static constexpr auto AVG_ADDRESS_BROADCAST_INTERVAL{30s}; /** Average delay between trickled inventory transmissions for inbound peers. * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. */ -static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL = 5s; +static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s}; /** Average delay between trickled inventory transmissions for outbound peers. * Use a smaller delay as there is less privacy concern for them. * Blocks and peers with NetPermissionFlags::NoBan permission bypass this. * Masternode outbound peers get half this delay. */ -static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL = 2s; +static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s}; /** Maximum rate of inventory items to send per second. * Limits the impact of low-fee transaction floods. * We have 4 times smaller block times in Dash, so we need to push 4 times more invs per 1MB. */ @@ -458,7 +458,7 @@ struct CNodeState { * - its chain tip has at least as much work as ours * * CHAIN_SYNC_TIMEOUT: if a peer's best known block has less work than our tip, - * set a timeout CHAIN_SYNC_TIMEOUT seconds in the future: + * set a timeout CHAIN_SYNC_TIMEOUT in the future: * - If at timeout their best known block now has more work than our tip * when the timeout was set, then either reset the timeout or clear it * (after comparing against our current tip's work) @@ -1477,11 +1477,11 @@ std::chrono::microseconds GetObjectInterval(int invType) switch(invType) { case MSG_QUORUM_RECOVERED_SIG: - return std::chrono::seconds{15}; + return 15s; case MSG_CLSIG: - return std::chrono::seconds{5}; + return 5s; case MSG_ISDLOCK: - return std::chrono::seconds{10}; + return 10s; default: return GETDATA_TX_INTERVAL; } @@ -1604,7 +1604,7 @@ void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler) // Schedule next run for 10-15 minutes in the future. // We add randomness on every cycle to avoid the possibility of P2P fingerprinting. - const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5}); + const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -1706,7 +1706,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c // since pingtime does not update until the ping is complete, which might take a while. // So, if a ping is taking an unusually long time in flight, // the caller can immediately detect that this is happening. - std::chrono::microseconds ping_wait{0}; + auto ping_wait{0us}; if ((0 != peer->m_ping_nonce_sent) && (0 != peer->m_ping_start.load().count())) { ping_wait = GetTime() - peer->m_ping_start.load(); } @@ -1947,7 +1947,7 @@ void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler) scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL}); // schedule next run for 10-15 minutes in the future - const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5}); + const std::chrono::milliseconds delta = 10min + GetRandMillis(5min); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); } @@ -2558,10 +2558,10 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic std::vector vNotFound; const CNetMsgMaker msgMaker(pfrom.GetCommonVersion()); - const std::chrono::seconds now = GetTime(); + const auto now{GetTime()}; // Get last mempool request time - const std::chrono::seconds mempool_req = tx_relay != nullptr ? tx_relay->m_last_mempool_req.load() - : std::chrono::seconds::min(); + const auto mempool_req = tx_relay != nullptr ? tx_relay->m_last_mempool_req.load() + : std::chrono::seconds::min(); // Process as many TX items from the front of the getdata queue as // possible, since they're common and it's efficient to batch process @@ -3782,7 +3782,7 @@ void PeerManagerImpl::ProcessMessage( int64_t nSince = nNow - 10 * 60; // Update/increment addr rate limiting bucket. - const auto current_time = GetTime(); + const auto current_time{GetTime()}; if (peer->m_addr_token_bucket < MAX_ADDR_PROCESSING_TOKEN_BUCKET) { // Don't increment bucket if it's already full const auto time_diff = std::max(current_time - peer->m_addr_token_timestamp, 0us); @@ -3877,7 +3877,7 @@ void PeerManagerImpl::ProcessMessage( LOCK(cs_main); - const auto current_time = GetTime(); + const auto current_time{GetTime()}; uint256* best_block{nullptr}; for (CInv& inv : vInv) { @@ -4315,7 +4315,7 @@ void PeerManagerImpl::ProcessMessage( } } if (!fRejectedParents) { - const auto current_time = GetTime(); + const auto current_time{GetTime()}; for (const uint256& parent_txid : unique_parents) { CInv _inv(MSG_TX, parent_txid); @@ -5573,7 +5573,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // If we get here, the outgoing message serialization version is set and can't change. const CNetMsgMaker msgMaker(pto->GetCommonVersion()); - const auto current_time = GetTime(); + const auto current_time{GetTime()}; if (pto->IsAddrFetchConn() && current_time - pto->m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) { LogPrint(BCLog::NET_NETCONN, "addrfetch connection timeout; disconnecting peer=%d\n", pto->GetId()); From 2d299f128aad0cbb01cb83d36931ef307140470a Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 10 Jan 2022 14:48:13 +0100 Subject: [PATCH 03/13] merge bitcoin#24136: Extract CTxIn::MAX_SEQUENCE_NONFINAL constant, rework BIP 65/68/112 docs --- src/primitives/transaction.h | 36 +++++++++++++++++++++++++-------- src/rpc/rawtransaction_util.cpp | 7 ++++++- src/test/fuzz/util.cpp | 2 +- src/test/miner_tests.cpp | 2 +- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 4e9a04b914849..4a408958e29dd 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -74,25 +74,45 @@ class CTxIn CScript scriptSig; uint32_t nSequence; - /* Setting nSequence to this value for every input in a transaction - * disables nLockTime. */ + /** + * Setting nSequence to this value for every input in a transaction + * disables nLockTime/IsFinalTx(). + * It fails OP_CHECKLOCKTIMEVERIFY/CheckLockTime() for any input that has + * it set (BIP 65). + * It has SEQUENCE_LOCKTIME_DISABLE_FLAG set (BIP 68/112). + */ static const uint32_t SEQUENCE_FINAL = 0xffffffff; + /** + * This is the maximum sequence number that enables both nLockTime and + * OP_CHECKLOCKTIMEVERIFY (BIP 65). + * It has SEQUENCE_LOCKTIME_DISABLE_FLAG set (BIP 68/112). + */ + static const uint32_t MAX_SEQUENCE_NONFINAL{SEQUENCE_FINAL - 1}; - /* Below flags apply in the context of BIP 68*/ - /* If this flag set, CTxIn::nSequence is NOT interpreted as a - * relative lock-time. */ + // Below flags apply in the context of BIP 68. BIP 68 requires the tx + // version to be set to 2, or higher. + /** + * If this flag is set, CTxIn::nSequence is NOT interpreted as a + * relative lock-time. + * It skips SequenceLocks() for any input that has it set (BIP 68). + * It fails OP_CHECKSEQUENCEVERIFY/CheckSequence() for any input that has + * it set (BIP 112). + */ static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1U << 31); - /* If CTxIn::nSequence encodes a relative lock-time and this flag + /** + * If CTxIn::nSequence encodes a relative lock-time and this flag * is set, the relative lock-time has units of 512 seconds, * otherwise it specifies blocks with a granularity of 1. */ static const uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22); - /* If CTxIn::nSequence encodes a relative lock-time, this mask is + /** + * If CTxIn::nSequence encodes a relative lock-time, this mask is * applied to extract that lock-time from the sequence field. */ static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff; - /* In order to use the same number of bits to encode roughly the + /** + * In order to use the same number of bits to encode roughly the * same wall-clock duration, and because blocks are naturally * limited to occur every 600s on average, the minimum granularity * for time-based relative lock-time is fixed at 512 seconds. diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 9e41942965822..5291696b85f50 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -58,7 +58,12 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); - uint32_t nSequence = (rawTx.nLockTime ? CTxIn::SEQUENCE_FINAL - 1 : CTxIn::SEQUENCE_FINAL); + uint32_t nSequence; + if (rawTx.nLockTime) { + nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */ + } else { + nSequence = CTxIn::SEQUENCE_FINAL; + } // set the sequence number if passed in the parameters object const UniValue& sequenceObj = find_value(o, "sequence"); diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 848040bb6f7f9..bd55d99f97a6d 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -348,7 +348,7 @@ uint32_t ConsumeSequence(FuzzedDataProvider& fuzzed_data_provider) noexcept return fuzzed_data_provider.ConsumeBool() ? fuzzed_data_provider.PickValueInArray({ CTxIn::SEQUENCE_FINAL, - CTxIn::SEQUENCE_FINAL - 1 + CTxIn::MAX_SEQUENCE_NONFINAL, }) : fuzzed_data_provider.ConsumeIntegral(); } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 76017966b05f3..3788934cace99 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -478,7 +478,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // absolute height locked tx.vin[0].prevout.hash = txFirst[2]->GetHash(); - tx.vin[0].nSequence = CTxIn::SEQUENCE_FINAL - 1; + tx.vin[0].nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; prevheights[0] = baseheight + 3; tx.nLockTime = m_node.chainman->ActiveChain().Tip()->nHeight + 1; hash = tx.GetHash(); From 9a8d6e149fb24d0caa5f8ecf69e90cd5088d2c62 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Fri, 4 Feb 2022 17:57:51 +0200 Subject: [PATCH 04/13] merge bitcoin#24265: Drop StripRedundantLastElementsOfPath() function --- src/init.cpp | 2 +- src/test/getarg_tests.cpp | 92 ++++++++++++++++++++++++++++++++++ src/util/system.cpp | 31 +++++------- src/util/system.h | 10 ++++ src/wallet/load.cpp | 2 +- src/wallet/test/init_tests.cpp | 8 +-- src/wallet/walletutil.cpp | 2 +- 7 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 4524a33d84615..ec3e351ce05c1 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1468,7 +1468,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); // Warn about relative -datadir path. - if (args.IsArgSet("-datadir") && !fs::PathFromString(args.GetArg("-datadir", "")).is_absolute()) { + if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) { LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */ "current working directory '%s'. This is fragile, because if Dash Core is started in the future " "from a different location, it will be unable to locate the current data files. There could " diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 78a314d2eebd3..7d7687e9090df 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -153,6 +153,98 @@ BOOST_AUTO_TEST_CASE(intarg) BOOST_CHECK_EQUAL(m_local_args.GetArg("-bar", 11), 0); } +BOOST_AUTO_TEST_CASE(patharg) +{ + const auto dir = std::make_pair("-dir", ArgsManager::ALLOW_ANY); + SetupArgs({dir}); + ResetArgs(""); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), fs::path{}); + + const fs::path root_path{"/"}; + ResetArgs("-dir=/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + + ResetArgs("-dir=/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), root_path); + +#ifdef WIN32 + const fs::path win_root_path{"C:\\"}; + ResetArgs("-dir=C:\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); + + ResetArgs("-dir=C:\\.\\\\"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), win_root_path); +#endif + + const fs::path absolute_path{"/home/user/.bitcoin"}; + ResetArgs("-dir=/home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/root/../home/user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/./user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + ResetArgs("-dir=/home/user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), absolute_path); + + const fs::path relative_path{"user/.bitcoin"}; + ResetArgs("-dir=user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=somewhere/../user/.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/./.bitcoin"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/."); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/./"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); + + ResetArgs("-dir=user/.bitcoin/.//"); + BOOST_CHECK_EQUAL(m_local_args.GetPathArg("-dir"), relative_path); +} + BOOST_AUTO_TEST_CASE(doubledash) { const auto foo = std::make_pair("-foo", ArgsManager::ALLOW_ANY); diff --git a/src/util/system.cpp b/src/util/system.cpp index 9ecadeabce703..6834189aa6b96 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -261,19 +261,6 @@ static bool CheckValid(const std::string& key, const util::SettingsValue& val, u return true; } -namespace { -fs::path StripRedundantLastElementsOfPath(const fs::path& path) -{ - auto result = path; - while (result.filename().empty() || fs::PathToString(result.filename()) == ".") { - result = result.parent_path(); - } - - assert(fs::equivalent(result, path.lexically_normal())); - return result; -} -} // namespace - // Define default constructor and destructor that are not inline, so code instantiating this class doesn't need to // #include class definitions for all members. // For example, m_settings has an internal dependency on univalue. @@ -420,6 +407,13 @@ std::optional ArgsManager::GetArgFlags(const std::string& name) co return std::nullopt; } +fs::path ArgsManager::GetPathArg(std::string pathlike_arg) const +{ + auto result = fs::PathFromString(GetArg(pathlike_arg, "")).lexically_normal(); + // Remove trailing slash, if present. + return result.has_filename() ? result : result.parent_path(); +} + const fs::path ArgsManager::GetBlocksDirPath() const { LOCK(cs_args); @@ -430,7 +424,7 @@ const fs::path ArgsManager::GetBlocksDirPath() const if (!path.empty()) return path; if (IsArgSet("-blocksdir")) { - path = fs::absolute(fs::PathFromString(GetArg("-blocksdir", ""))); + path = fs::absolute(GetPathArg("-blocksdir")); if (!fs::is_directory(path)) { path = ""; return path; @@ -454,9 +448,9 @@ const fs::path ArgsManager::GetDataDir(bool net_specific) const // this function if (!path.empty()) return path; - std::string datadir = GetArg("-datadir", ""); + const fs::path datadir{GetPathArg("-datadir")}; if (!datadir.empty()) { - path = fs::absolute(StripRedundantLastElementsOfPath(fs::PathFromString(datadir))); + path = fs::absolute(datadir); if (!fs::is_directory(path)) { path = ""; return path; @@ -476,7 +470,6 @@ const fs::path ArgsManager::GetDataDir(bool net_specific) const } } - path = StripRedundantLastElementsOfPath(path); return path; } @@ -871,8 +864,8 @@ fs::path GetBackupsDir() bool CheckDataDirOption() { - std::string datadir = gArgs.GetArg("-datadir", ""); - return datadir.empty() || fs::is_directory(fs::absolute(fs::PathFromString(datadir))); + const fs::path datadir{gArgs.GetPathArg("-datadir")}; + return datadir.empty() || fs::is_directory(fs::absolute(datadir)); } fs::path GetConfigFile(const std::string& confPath) diff --git a/src/util/system.h b/src/util/system.h index da838c61c4fbb..b99a5f9a1e8c4 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -283,6 +283,16 @@ class ArgsManager */ const std::map> GetCommandLineArgs() const; + /** + * Get a normalized path from a specified pathlike argument + * + * It is guaranteed that the returned path has no trailing slashes. + * + * @param pathlike_arg Pathlike argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir") + * @return Normalized path which is get from a specified pathlike argument + */ + fs::path GetPathArg(std::string pathlike_arg) const; + /** * Get blocks directory path * diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 5ecaa2faae85f..6f5b661efd728 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -24,7 +24,7 @@ bool VerifyWallets(interfaces::Chain& chain) { if (gArgs.IsArgSet("-walletdir")) { - fs::path wallet_dir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + const fs::path wallet_dir{gArgs.GetPathArg("-walletdir")}; std::error_code error; // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory // It also lets the fs::exists and fs::is_directory checks below pass on windows, since they return false diff --git a/src/wallet/test/init_tests.cpp b/src/wallet/test/init_tests.cpp index ca27dbdc03136..4c0b7af8cb575 100644 --- a/src/wallet/test/init_tests.cpp +++ b/src/wallet/test/init_tests.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_default) bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); } - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -32,7 +32,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_custom) bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); } - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["custom"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing) bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); } - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(walletinit_verify_walletdir_no_trailing2) bool result = m_wallet_loader->verify(); BOOST_CHECK(result == true); } - fs::path walletdir = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + fs::path walletdir = gArgs.GetPathArg("-walletdir"); fs::path expected_path = fs::canonical(m_walletdir_path_cases["default"]); BOOST_CHECK_EQUAL(walletdir, expected_path); } diff --git a/src/wallet/walletutil.cpp b/src/wallet/walletutil.cpp index 08af6a59eea59..b76bcc1e1900d 100644 --- a/src/wallet/walletutil.cpp +++ b/src/wallet/walletutil.cpp @@ -12,7 +12,7 @@ fs::path GetWalletDir() fs::path path; if (gArgs.IsArgSet("-walletdir")) { - path = fs::PathFromString(gArgs.GetArg("-walletdir", "")); + path = gArgs.GetPathArg("-walletdir"); if (!fs::is_directory(path)) { // If the path specified doesn't exist, we return the deliberately // invalid empty string. From c2defe72103fc60e09825e58d2afb701977240fb Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 29 Oct 2024 07:52:52 +0000 Subject: [PATCH 05/13] merge bitcoin#23819: don't serialize block hash twice continuation of 7f2c84b7 in dash#5042 Co-authored-by: UdjinM6 --- src/validation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index b4f0c1810ba81..6dfa1e10c7df9 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2307,12 +2307,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, ::g_stats_client->gauge("blocks.tip.SigOps", nSigOps, 1.0f); TRACE6(validation, block_connected, - block.GetHash().data(), + block_hash.data(), pindex->nHeight, block.vtx.size(), nInputs, nSigOps, - GetTimeMicros() - nTimeStart // in microseconds (µs) + nTime8 - nTimeStart // in microseconds (µs) ); return true; From aa945c2c1de9ef25207f82a66895f85dd2512d72 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Mon, 8 Nov 2021 14:27:35 +0100 Subject: [PATCH 06/13] merge bitcoin#23595: Add ParseHex() helper includes: - facd1fb911abfc595a3484ee53397eff515d4c40 continuation of cf4522f8 in dash#5901 --- src/key.cpp | 4 ++-- src/key.h | 4 ++-- src/test/bip32_tests.cpp | 7 ++++--- src/test/key_io_tests.cpp | 2 +- src/wallet/hdchain.cpp | 2 +- src/wallet/rpcdump.cpp | 2 +- src/wallet/scriptpubkeyman.cpp | 2 +- src/wallet/test/bip39_tests.cpp | 2 +- src/wallet/wallet.cpp | 2 +- 9 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/key.cpp b/src/key.cpp index 66209c7274b4a..2e7f6dd34e751 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -348,11 +348,11 @@ bool CExtKey::Derive(CExtKey &out, unsigned int _nChild) const { return key.Derive(out.key, out.chaincode, _nChild, chaincode); } -void CExtKey::SetSeed(Span seed) +void CExtKey::SetSeed(Span seed) { static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'}; std::vector> vout(64); - CHMAC_SHA512{hashkey, sizeof(hashkey)}.Write(seed.data(), seed.size()).Finalize(vout.data()); + CHMAC_SHA512{hashkey, sizeof(hashkey)}.Write(UCharCast(seed.data()), seed.size()).Finalize(vout.data()); key.Set(vout.data(), vout.data() + 32, true); memcpy(chaincode.begin(), vout.data() + 32, 32); nDepth = 0; diff --git a/src/key.h b/src/key.h index f9723e4f22d12..a7a57f7d8926b 100644 --- a/src/key.h +++ b/src/key.h @@ -91,7 +91,7 @@ class CKey //! Simple read-only vector-like interface. unsigned int size() const { return (fValid ? keydata.size() : 0); } - const unsigned char* data() const { return keydata.data(); } + const std::byte* data() const { return reinterpret_cast(keydata.data()); } const unsigned char* begin() const { return keydata.data(); } const unsigned char* end() const { return keydata.data() + size(); } @@ -188,7 +188,7 @@ struct CExtKey { void Decode(const unsigned char code[BIP32_EXTKEY_SIZE]); bool Derive(CExtKey& out, unsigned int nChild) const; CExtPubKey Neuter() const; - void SetSeed(Span seed); + void SetSeed(Span seed); }; /** Initialize the elliptic curve support. May not be called twice without calling ECC_Stop first. */ diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp index 0fa6b7784f344..314e3ea0d8f8c 100644 --- a/src/test/bip32_tests.cpp +++ b/src/test/bip32_tests.cpp @@ -120,11 +120,12 @@ const std::vector TEST5 = { "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHL" }; -void RunTest(const TestVector &test) { - std::vector seed = ParseHex(test.strHexMaster); +void RunTest(const TestVector& test) +{ + std::vector seed{ParseHex(test.strHexMaster)}; CExtKey key; CExtPubKey pubkey; - key.SetSeed(seed); + key.SetSeed(MakeByteSpan(seed)); pubkey = key.Neuter(); for (const TestDerivation &derive : test.vDerive) { unsigned char data[74]; diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index 683fe8590087c..496c7fd27d989 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) continue; } std::string exp_base58string = test[0].get_str(); - std::vector exp_payload = ParseHex(test[1].get_str()); + const std::vector exp_payload{ParseHex(test[1].get_str())}; const UniValue &metadata = test[2].get_obj(); bool isPrivkey = find_value(metadata, "isPrivkey").get_bool(); SelectParams(find_value(metadata, "chain").get_str()); diff --git a/src/wallet/hdchain.cpp b/src/wallet/hdchain.cpp index 0f3b2dd49848e..710784d37f12d 100644 --- a/src/wallet/hdchain.cpp +++ b/src/wallet/hdchain.cpp @@ -140,7 +140,7 @@ void CHDChain::DeriveChildExtKey(uint32_t nAccountIndex, bool fInternal, uint32_ CExtKey changeKey; //key at m/purpose'/coin_type'/account'/change CExtKey childKey; //key at m/purpose'/coin_type'/account'/change/address_index - masterKey.SetSeed(vchSeed); + masterKey.SetSeed(MakeByteSpan(vchSeed)); // Use hardened derivation for purpose, coin_type and account // (keys >= 0x80000000 are hardened after bip32) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 3a69d4337f173..d829bbab2c4f3 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1007,7 +1007,7 @@ RPCHelpMan dumpwallet() file << "# HD seed: " << HexStr(vchSeed) << "\n\n"; CExtKey masterKey; - masterKey.SetSeed(vchSeed); + masterKey.SetSeed(MakeByteSpan(vchSeed)); file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n"; diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 29ad2f0df8125..66c553cfc9099 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -350,7 +350,7 @@ void LegacyScriptPubKeyMan::UpgradeKeyMetadata() CExtKey masterKey; SecureVector vchSeed = hdChainCurrent.GetSeed(); - masterKey.SetSeed(vchSeed); + masterKey.SetSeed(MakeByteSpan(vchSeed)); CKeyID master_id = masterKey.key.GetPubKey().GetID(); std::unique_ptr batch = std::make_unique(m_storage.GetDatabase()); diff --git a/src/wallet/test/bip39_tests.cpp b/src/wallet/test/bip39_tests.cpp index 7ea5e5c988f21..612ad59d9a1bc 100644 --- a/src/wallet/test/bip39_tests.cpp +++ b/src/wallet/test/bip39_tests.cpp @@ -54,7 +54,7 @@ BOOST_AUTO_TEST_CASE(bip39_vectors) CExtKey key; CExtPubKey pubkey; - key.SetSeed(seed); + key.SetSeed(MakeByteSpan(seed)); pubkey = key.Neuter(); // printf("CBitcoinExtKey: %s\n", EncodeExtKey(key).c_str()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 049100a764477..576703ab60824 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5866,7 +5866,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans() // Get the extended key CExtKey master_key; - master_key.SetSeed(seed_key); + master_key.SetSeed(MakeByteSpan(seed_key)); for (bool internal : {false, true}) { { // OUTPUT_TYPE is only one: LEGACY From 74dceb3c5c9627a17b3cad565730838547ca59a4 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sun, 6 Mar 2022 20:03:36 +0100 Subject: [PATCH 07/13] merge bitcoin#24486: dedup sqlite blob binding --- src/wallet/sqlite.cpp | 67 +++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/src/wallet/sqlite.cpp b/src/wallet/sqlite.cpp index 1437f7ae6f8d3..f41b27d28f71b 100644 --- a/src/wallet/sqlite.cpp +++ b/src/wallet/sqlite.cpp @@ -36,6 +36,22 @@ static void ErrorLogCallback(void* arg, int code, const char* msg) LogPrintf("SQLite Error. Code: %d. Message: %s\n", code, msg); } +static bool BindBlobToStatement(sqlite3_stmt* stmt, + int index, + Span blob, + const std::string& description) +{ + int res = sqlite3_bind_blob(stmt, index, blob.data(), blob.size(), SQLITE_STATIC); + if (res != SQLITE_OK) { + LogPrintf("Unable to bind %s to statement: %s\n", description, sqlite3_errstr(res)); + sqlite3_clear_bindings(stmt); + sqlite3_reset(stmt); + return false; + } + + return true; +} + static std::optional ReadPragmaInteger(sqlite3* db, const std::string& key, const std::string& description, bilingual_str& error) { std::string stmt_text = strprintf("PRAGMA %s", key); @@ -376,14 +392,8 @@ bool SQLiteBatch::ReadKey(CDataStream&& key, CDataStream& value) assert(m_read_stmt); // Bind: leftmost parameter in statement is index 1 - int res = sqlite3_bind_blob(m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC); - if (res != SQLITE_OK) { - LogPrintf("%s: Unable to bind statement: %s\n", __func__, sqlite3_errstr(res)); - sqlite3_clear_bindings(m_read_stmt); - sqlite3_reset(m_read_stmt); - return false; - } - res = sqlite3_step(m_read_stmt); + if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false; + int res = sqlite3_step(m_read_stmt); if (res != SQLITE_ROW) { if (res != SQLITE_DONE) { // SQLITE_DONE means "not found", don't log an error in that case. @@ -417,23 +427,11 @@ bool SQLiteBatch::WriteKey(CDataStream&& key, CDataStream&& value, bool overwrit // Bind: leftmost parameter in statement is index 1 // Insert index 1 is key, 2 is value - int res = sqlite3_bind_blob(stmt, 1, key.data(), key.size(), SQLITE_STATIC); - if (res != SQLITE_OK) { - LogPrintf("%s: Unable to bind key to statement: %s\n", __func__, sqlite3_errstr(res)); - sqlite3_clear_bindings(stmt); - sqlite3_reset(stmt); - return false; - } - res = sqlite3_bind_blob(stmt, 2, value.data(), value.size(), SQLITE_STATIC); - if (res != SQLITE_OK) { - LogPrintf("%s: Unable to bind value to statement: %s\n", __func__, sqlite3_errstr(res)); - sqlite3_clear_bindings(stmt); - sqlite3_reset(stmt); - return false; - } + if (!BindBlobToStatement(stmt, 1, key, "key")) return false; + if (!BindBlobToStatement(stmt, 2, value, "value")) return false; // Execute - res = sqlite3_step(stmt); + int res = sqlite3_step(stmt); sqlite3_clear_bindings(stmt); sqlite3_reset(stmt); if (res != SQLITE_DONE) { @@ -448,16 +446,10 @@ bool SQLiteBatch::EraseKey(CDataStream&& key) assert(m_delete_stmt); // Bind: leftmost parameter in statement is index 1 - int res = sqlite3_bind_blob(m_delete_stmt, 1, key.data(), key.size(), SQLITE_STATIC); - if (res != SQLITE_OK) { - LogPrintf("%s: Unable to bind statement: %s\n", __func__, sqlite3_errstr(res)); - sqlite3_clear_bindings(m_delete_stmt); - sqlite3_reset(m_delete_stmt); - return false; - } + if (!BindBlobToStatement(m_delete_stmt, 1, key, "key")) return false; // Execute - res = sqlite3_step(m_delete_stmt); + int res = sqlite3_step(m_delete_stmt); sqlite3_clear_bindings(m_delete_stmt); sqlite3_reset(m_delete_stmt); if (res != SQLITE_DONE) { @@ -472,18 +464,11 @@ bool SQLiteBatch::HasKey(CDataStream&& key) assert(m_read_stmt); // Bind: leftmost parameter in statement is index 1 - bool ret = false; - int res = sqlite3_bind_blob(m_read_stmt, 1, key.data(), key.size(), SQLITE_STATIC); - if (res == SQLITE_OK) { - res = sqlite3_step(m_read_stmt); - if (res == SQLITE_ROW) { - ret = true; - } - } - + if (!BindBlobToStatement(m_read_stmt, 1, key, "key")) return false; + int res = sqlite3_step(m_read_stmt); sqlite3_clear_bindings(m_read_stmt); sqlite3_reset(m_read_stmt); - return ret; + return res == SQLITE_ROW; } bool SQLiteBatch::StartCursor() From 092a11e2d1a782647b54102b40fbeb5282fc1fff Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Sat, 16 Feb 2019 16:40:00 +0000 Subject: [PATCH 08/13] merge bitcoin#15423: Query Tor for correct -onion configuration --- src/torcontrol.cpp | 88 ++++++++++++++++++++++++++++++++++++---------- src/torcontrol.h | 2 ++ 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 21ab55195a6af..26154a9939891 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -48,6 +48,7 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5; * this is belt-and-suspenders sanity limit to prevent memory exhaustion. */ static const int MAX_LINE_LENGTH = 100000; +static const uint16_t DEFAULT_TOR_SOCKS_PORT = 9050; /****** Low-level TorControlConnection ********/ @@ -333,6 +334,73 @@ TorController::~TorController() } } +void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlReply& reply) +{ + // NOTE: We can only get here if -onion is unset + std::string socks_location; + if (reply.code == 250) { + for (const auto& line : reply.lines) { + if (0 == line.compare(0, 20, "net/listeners/socks=")) { + const std::string port_list_str = line.substr(20); + std::vector port_list = SplitString(port_list_str, ' '); + + for (auto& portstr : port_list) { + if (portstr.empty()) continue; + if ((portstr[0] == '"' || portstr[0] == '\'') && portstr.size() >= 2 && (*portstr.rbegin() == portstr[0])) { + portstr = portstr.substr(1, portstr.size() - 2); + if (portstr.empty()) continue; + } + socks_location = portstr; + if (0 == portstr.compare(0, 10, "127.0.0.1:")) { + // Prefer localhost - ignore other ports + break; + } + } + } + } + if (!socks_location.empty()) { + LogPrint(BCLog::TOR, "tor: Get SOCKS port command yielded %s\n", socks_location); + } else { + LogPrintf("tor: Get SOCKS port command returned nothing\n"); + } + } else if (reply.code == 510) { // 510 Unrecognized command + LogPrintf("tor: Get SOCKS port command failed with unrecognized command (You probably should upgrade Tor)\n"); + } else { + LogPrintf("tor: Get SOCKS port command failed; error code %d\n", reply.code); + } + + CService resolved; + Assume(!resolved.IsValid()); + if (!socks_location.empty()) { + resolved = LookupNumeric(socks_location, DEFAULT_TOR_SOCKS_PORT); + } + if (!resolved.IsValid()) { + // Fallback to old behaviour + resolved = LookupNumeric("127.0.0.1", DEFAULT_TOR_SOCKS_PORT); + } + + Assume(resolved.IsValid()); + LogPrint(BCLog::TOR, "tor: Configuring onion proxy for %s\n", resolved.ToStringAddrPort()); + Proxy addrOnion = Proxy(resolved, true); + SetProxy(NET_ONION, addrOnion); + + const auto onlynets = gArgs.GetArgs("-onlynet"); + + const bool onion_allowed_by_onlynet{ + !gArgs.IsArgSet("-onlynet") || + std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) { + return ParseNetwork(n) == NET_ONION; + })}; + + if (onion_allowed_by_onlynet) { + // If NET_ONION is reachable, then the below is a noop. + // + // If NET_ONION is not reachable, then none of -proxy or -onion was given. + // Since we are here, then -torcontrol and -torpassword were given. + SetReachable(NET_ONION, true); + } +} + void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply) { if (reply.code == 250) { @@ -376,25 +444,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply& // Now that we know Tor is running setup the proxy for onion addresses // if -onion isn't set to something else. if (gArgs.GetArg("-onion", "") == "") { - CService resolved(LookupNumeric("127.0.0.1", 9050)); - Proxy addrOnion = Proxy(resolved, true); - SetProxy(NET_ONION, addrOnion); - - const auto onlynets = gArgs.GetArgs("-onlynet"); - - const bool onion_allowed_by_onlynet{ - !gArgs.IsArgSet("-onlynet") || - std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) { - return ParseNetwork(n) == NET_ONION; - })}; - - if (onion_allowed_by_onlynet) { - // If NET_ONION is reachable, then the below is a noop. - // - // If NET_ONION is not reachable, then none of -proxy or -onion was given. - // Since we are here, then -torcontrol and -torpassword were given. - SetReachable(NET_ONION, true); - } + _conn.Command("GETINFO net/listeners/socks", std::bind(&TorController::get_socks_cb, this, std::placeholders::_1, std::placeholders::_2)); } // Finally - now create the service diff --git a/src/torcontrol.h b/src/torcontrol.h index 7258f27cb69ce..75464b148e1f1 100644 --- a/src/torcontrol.h +++ b/src/torcontrol.h @@ -140,6 +140,8 @@ class TorController std::vector clientNonce; public: + /** Callback for GETINFO net/listeners/socks result */ + void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for ADD_ONION result */ void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for AUTHENTICATE result */ From 80615b8c017fbc55d8f1f494cf00ece7a2b96f31 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 29 Oct 2024 08:20:00 +0000 Subject: [PATCH 09/13] merge bitcoin#24784: deduplicate integer serialization in RollingBloom benchmark --- src/bench/rollingbloom.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/bench/rollingbloom.cpp b/src/bench/rollingbloom.cpp index 30bc1d5fdf01b..ade4768d677f6 100644 --- a/src/bench/rollingbloom.cpp +++ b/src/bench/rollingbloom.cpp @@ -5,6 +5,9 @@ #include #include +#include + +#include static void RollingBloom(benchmark::Bench& bench) { @@ -13,16 +16,10 @@ static void RollingBloom(benchmark::Bench& bench) uint32_t count = 0; bench.run([&] { count++; - data[0] = count & 0xFF; - data[1] = (count >> 8) & 0xFF; - data[2] = (count >> 16) & 0xFF; - data[3] = (count >> 24) & 0xFF; + WriteLE32(data.data(), count); filter.insert(data); - data[0] = (count >> 24) & 0xFF; - data[1] = (count >> 16) & 0xFF; - data[2] = (count >> 8) & 0xFF; - data[3] = count & 0xFF; + WriteBE32(data.data(), count); filter.contains(data); }); } From 87b556d3229b92245789e3b40746e2a0b322bdeb Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 29 Oct 2024 08:21:32 +0000 Subject: [PATCH 10/13] refactor: use loop to iterate through `SoftForkDescPushBack` args --- src/rpc/blockchain.cpp | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d80263fc69415..e88e6996e52fe 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1818,24 +1818,28 @@ RPCHelpMan getblockchaininfo() const Consensus::Params& consensusParams = Params().GetConsensus(); UniValue softforks(UniValue::VOBJ); - // sorted by activation block - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_BIP147); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_CSV); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0001); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0003); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0008); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0020); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0024); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_BRR); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_V19); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_V20); - SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_MN_RR); - SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, Consensus::DEPLOYMENT_WITHDRAWALS); - SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); - + for (auto deploy : { /* sorted by activation block */ + Consensus::DEPLOYMENT_HEIGHTINCB, + Consensus::DEPLOYMENT_DERSIG, + Consensus::DEPLOYMENT_CLTV, + Consensus::DEPLOYMENT_BIP147, + Consensus::DEPLOYMENT_CSV, + Consensus::DEPLOYMENT_DIP0001, + Consensus::DEPLOYMENT_DIP0003, + Consensus::DEPLOYMENT_DIP0008, + Consensus::DEPLOYMENT_DIP0020, + Consensus::DEPLOYMENT_DIP0024, + Consensus::DEPLOYMENT_BRR, + Consensus::DEPLOYMENT_V19, + Consensus::DEPLOYMENT_V20, + Consensus::DEPLOYMENT_MN_RR }) { + SoftForkDescPushBack(tip, softforks, consensusParams, deploy); + } + for (auto ehf_deploy : { /* sorted by activation block */ + Consensus::DEPLOYMENT_WITHDRAWALS, + Consensus::DEPLOYMENT_TESTDUMMY }) { + SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, ehf_deploy); + } obj.pushKV("softforks", softforks); obj.pushKV("warnings", GetWarnings(false).original); From 99d028e9e1c1ef85dbd745f824e658e549455480 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 29 Oct 2024 09:14:27 +0000 Subject: [PATCH 11/13] merge bitcoin#24956: Call CHECK_NONFATAL only once where needed --- src/rpc/blockchain.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index e88e6996e52fe..ce3e4dcbb70d1 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1782,10 +1782,10 @@ RPCHelpMan getblockchaininfo() LOCK(cs_main); CChainState& active_chainstate = chainman.ActiveChainstate(); - const CBlockIndex* tip = CHECK_NONFATAL(active_chainstate.m_chain.Tip()); - const int height = tip->nHeight; + const CBlockIndex& tip{*CHECK_NONFATAL(active_chainstate.m_chain.Tip())}; + const int height{tip.nHeight}; - const auto ehfSignals = CHECK_NONFATAL(node.mnhf_manager)->GetSignalsStage(tip); + const auto ehfSignals{CHECK_NONFATAL(node.mnhf_manager)->GetSignalsStage(&tip)}; UniValue obj(UniValue::VOBJ); if (args.IsArgSet("-devnet")) { @@ -1795,18 +1795,17 @@ RPCHelpMan getblockchaininfo() } obj.pushKV("blocks", height); obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1); - obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex()); - obj.pushKV("difficulty", (double)GetDifficulty(tip)); - obj.pushKV("time", (int64_t)tip->nTime); - obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast()); - obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip)); + obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex()); + obj.pushKV("difficulty", GetDifficulty(&tip)); + obj.pushKV("time", int64_t{tip.nTime}); + obj.pushKV("mediantime", tip.GetMedianTimePast()); + obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), &tip)); obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); - obj.pushKV("chainwork", tip->nChainWork.GetHex()); + obj.pushKV("chainwork", tip.nChainWork.GetHex()); obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); if (fPruneMode) { - const CBlockIndex* block = CHECK_NONFATAL(tip); - obj.pushKV("pruneheight", GetFirstStoredBlock(block)->nHeight); + obj.pushKV("pruneheight", GetFirstStoredBlock(&tip)->nHeight); // if 0, execution bypasses the whole if block. bool automatic_pruning{args.GetArg("-prune", 0) != 1}; @@ -1833,12 +1832,12 @@ RPCHelpMan getblockchaininfo() Consensus::DEPLOYMENT_V19, Consensus::DEPLOYMENT_V20, Consensus::DEPLOYMENT_MN_RR }) { - SoftForkDescPushBack(tip, softforks, consensusParams, deploy); + SoftForkDescPushBack(&tip, softforks, consensusParams, deploy); } for (auto ehf_deploy : { /* sorted by activation block */ Consensus::DEPLOYMENT_WITHDRAWALS, Consensus::DEPLOYMENT_TESTDUMMY }) { - SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, ehf_deploy); + SoftForkDescPushBack(&tip, ehfSignals, softforks, consensusParams, ehf_deploy); } obj.pushKV("softforks", softforks); From cfda9e5eb5b9b82904838193e5f59c5086d2d272 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Wed, 27 Apr 2022 12:21:22 +0200 Subject: [PATCH 12/13] merge bitcoin#25016: GetFirstStoredBlock() and getblockchaininfo follow-ups --- src/index/base.cpp | 2 +- src/node/blockstorage.cpp | 6 +++--- src/node/blockstorage.h | 6 +++--- src/rpc/blockchain.cpp | 11 ++++++----- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/index/base.cpp b/src/index/base.cpp index e132e27ee5d1d..bc9a3fa575677 100644 --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -76,7 +76,7 @@ bool BaseIndex::Init() if (!m_best_block_index) { // index is not built yet // make sure we have all block data back to the genesis - prune_violation = GetFirstStoredBlock(active_chain.Tip()) != active_chain.Genesis(); + prune_violation = m_chainstate->m_blockman.GetFirstStoredBlock(*active_chain.Tip()) != active_chain.Genesis(); } // in case the index has a best block set and is not fully synced // check if we have the required blocks to continue building the index diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index a86437099bd5a..3c13592e8a7a9 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -421,10 +421,10 @@ bool BlockManager::IsBlockPruned(const CBlockIndex* pblockindex) return (m_have_pruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0); } -const CBlockIndex* GetFirstStoredBlock(const CBlockIndex* start_block) { +const CBlockIndex* BlockManager::GetFirstStoredBlock(const CBlockIndex& start_block) +{ AssertLockHeld(::cs_main); - assert(start_block); - const CBlockIndex* last_block = start_block; + const CBlockIndex* last_block = &start_block; while (last_block->pprev && (last_block->pprev->nStatus & BLOCK_HAVE_DATA)) { last_block = last_block->pprev; } diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index a0c25f10d990e..54b09808b0cf7 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -196,6 +196,9 @@ class BlockManager //! Returns last CBlockIndex* that is a checkpoint const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); + //! Find the first block that is not pruned + const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + /** True if any block files have ever been pruned. */ bool m_have_pruned = false; @@ -206,9 +209,6 @@ class BlockManager void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); }; -//! Find the first block that is not pruned -const CBlockIndex* GetFirstStoredBlock(const CBlockIndex* start_block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); - void CleanupBlockRevFiles(); /** Open a block file (blk?????.dat) */ diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index ce3e4dcbb70d1..5baf3c3d3361b 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1335,8 +1335,9 @@ static RPCHelpMan pruneblockchain() CChain& active_chain = active_chainstate.m_chain; int heightParam = request.params[0].get_int(); - if (heightParam < 0) + if (heightParam < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height."); + } // Height value more than a billion is too high to be a block height, and // too low to be a block time (corresponds to timestamp from Sep 2001). @@ -1361,8 +1362,8 @@ static RPCHelpMan pruneblockchain() } PruneBlockFilesManual(active_chainstate, height); - const CBlockIndex* block = CHECK_NONFATAL(active_chain.Tip()); - const CBlockIndex* last_block = GetFirstStoredBlock(block); + const CBlockIndex& block{*CHECK_NONFATAL(active_chain.Tip())}; + const CBlockIndex* last_block{active_chainstate.m_blockman.GetFirstStoredBlock(block)}; return static_cast(last_block->nHeight); }, @@ -1797,7 +1798,7 @@ RPCHelpMan getblockchaininfo() obj.pushKV("headers", chainman.m_best_header ? chainman.m_best_header->nHeight : -1); obj.pushKV("bestblockhash", tip.GetBlockHash().GetHex()); obj.pushKV("difficulty", GetDifficulty(&tip)); - obj.pushKV("time", int64_t{tip.nTime}); + obj.pushKV("time", tip.GetBlockTime()); obj.pushKV("mediantime", tip.GetMedianTimePast()); obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), &tip)); obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload()); @@ -1805,7 +1806,7 @@ RPCHelpMan getblockchaininfo() obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage()); obj.pushKV("pruned", fPruneMode); if (fPruneMode) { - obj.pushKV("pruneheight", GetFirstStoredBlock(&tip)->nHeight); + obj.pushKV("pruneheight", chainman.m_blockman.GetFirstStoredBlock(tip)->nHeight); // if 0, execution bypasses the whole if block. bool automatic_pruning{args.GetArg("-prune", 0) != 1}; From 02320032c7c779a04a8e7347b48af368a56a32cf Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kwvg@users.noreply.github.com> Date: Tue, 3 May 2022 22:20:06 +0200 Subject: [PATCH 13/13] merge bitcoin#25060: add LIFETIMEBOUND to GetFirstStoredBlock()::start_time --- src/node/blockstorage.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 54b09808b0cf7..5b7468e79c24b 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -5,9 +5,10 @@ #ifndef BITCOIN_NODE_BLOCKSTORAGE_H #define BITCOIN_NODE_BLOCKSTORAGE_H +#include #include #include -#include // For CMessageHeader::MessageStartChars +#include #include #include @@ -197,7 +198,7 @@ class BlockManager const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); //! Find the first block that is not pruned - const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block LIFETIMEBOUND) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); /** True if any block files have ever been pruned. */ bool m_have_pruned = false;