diff --git a/configure.ac b/configure.ac index 975936501c..26a7f44bb1 100644 --- a/configure.ac +++ b/configure.ac @@ -649,7 +649,7 @@ CXXFLAGS="$TEMP_CXXFLAGS" fi -CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO" +CPPFLAGS="$CPPFLAGS -DHAVE_BUILD_INFO -DGSL_NO_IOSTREAMS" AC_ARG_WITH([utils], [AS_HELP_STRING([--with-utils], diff --git a/src/coinjoin/client.cpp b/src/coinjoin/client.cpp index 1675a6408e..64ebb14174 100644 --- a/src/coinjoin/client.cpp +++ b/src/coinjoin/client.cpp @@ -96,11 +96,9 @@ PeerMsgRet CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CDataS } // if the queue is ready, submit if we can - if (dsq.fReady && ranges::any_of(m_walletman.raw(), - [this, &dmn](const auto &pair) { - return pair.second->TrySubmitDenominate(dmn->pdmnState->addr, - this->connman); - })) { + if (dsq.fReady && m_walletman.ForAnyCJClientMan([this, &dmn](std::unique_ptr& clientman) { + return clientman->TrySubmitDenominate(dmn->pdmnState->addr, this->connman); + })) { LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); return {}; @@ -121,8 +119,9 @@ PeerMsgRet CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CDataS LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); - ranges::any_of(m_walletman.raw(), - [&dsq](const auto &pair) { return pair.second->MarkAlreadyJoinedQueueAsTried(dsq); }); + m_walletman.ForAnyCJClientMan([&dsq](const std::unique_ptr& clientman) { + return clientman->MarkAlreadyJoinedQueueAsTried(dsq); + }); WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq)); } @@ -155,11 +154,14 @@ void CCoinJoinClientManager::ProcessMessage(CNode& peer, CChainState& active_cha } } -CCoinJoinClientSession::CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - const CMasternodeSync& mn_sync, const std::unique_ptr& queueman, bool is_masternode) : +CCoinJoinClientSession::CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, + CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, + const std::unique_ptr& queueman, + bool is_masternode) : m_wallet(wallet), m_walletman(walletman), - m_manager(*Assert(walletman.Get(wallet.GetName()))), + m_clientman(clientman), m_dmnman(dmnman), m_mn_metaman(mn_metaman), m_mn_sync(mn_sync), @@ -638,14 +640,14 @@ bool CCoinJoinClientSession::SignFinalTransaction(CNode& peer, CChainState& acti // fill values for found outpoints m_wallet.chain().findCoins(coins); - std::map signing_errors; + std::map signing_errors; m_wallet.SignTransaction(finalMutableTransaction, coins, SIGHASH_ALL | SIGHASH_ANYONECANPAY, signing_errors); for (const auto& [input_index, error_string] : signing_errors) { // NOTE: this is a partial signing so it's expected for SignTransaction to return // "Input not found or already spent" errors for inputs that aren't ours - if (error_string != "Input not found or already spent") { - WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- signing input %d failed: %s!\n", __func__, input_index, error_string); + if (error_string.original != "Input not found or already spent") { + WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- signing input %d failed: %s!\n", __func__, input_index, error_string.original); UnlockCoins(); keyHolderStorage.ReturnAll(); SetNull(); @@ -684,7 +686,7 @@ void CCoinJoinClientSession::CompletedTransaction(PoolMessage nMessageID) if (m_is_masternode) return; if (nMessageID == MSG_SUCCESS) { - m_manager.UpdatedSuccessBlock(); + m_clientman.UpdatedSuccessBlock(); keyHolderStorage.KeepAll(); WalletCJLogPrint(m_wallet, "CompletedTransaction -- success\n"); } else { @@ -995,7 +997,8 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(CChainState& active_chainst AssertLockNotHeld(cs_deqsessions); LOCK(cs_deqsessions); if (int(deqSessions.size()) < CCoinJoinClientOptions::GetSessions()) { - deqSessions.emplace_back(m_wallet, m_walletman, m_dmnman, m_mn_metaman, m_mn_sync, m_queueman, m_is_masternode); + deqSessions.emplace_back(m_wallet, m_walletman, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_queueman, + m_is_masternode); } for (auto& session : deqSessions) { if (!CheckAutomaticBackup()) return false; @@ -1100,7 +1103,7 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, continue; } - m_manager.AddUsedMasternode(dsq.masternodeOutpoint); + m_clientman.AddUsedMasternode(dsq.masternodeOutpoint); if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) { WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString()); @@ -1145,14 +1148,14 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon // otherwise, try one randomly while (nTries < 10) { - auto dmn = m_manager.GetRandomNotUsedMasternode(); + auto dmn = m_clientman.GetRandomNotUsedMasternode(); if (!dmn) { strAutoDenomResult = _("Can't find random Masternode."); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- %s\n", strAutoDenomResult.original); return false; } - m_manager.AddUsedMasternode(dmn->collateralOutpoint); + m_clientman.AddUsedMasternode(dmn->collateralOutpoint); // skip next mn payments winners if (dmn->pdmnState->nLastPaidHeight + nWeightedMnCount < mnList.GetHeight() + WinnersToSkip()) { @@ -1526,7 +1529,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tally return false; } - m_manager.UpdatedSuccessBlock(); + m_clientman.UpdatedSuccessBlock(); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- txid: %s\n", __func__, strResult.original); @@ -1803,7 +1806,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con } // use the same nCachedLastSuccessBlock as for DS mixing to prevent race - m_manager.UpdatedSuccessBlock(); + m_clientman.UpdatedSuccessBlock(); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- txid: %s\n", __func__, strResult.original); @@ -1894,35 +1897,43 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const obj.pushKV("sessions", arrSessions); } -void CoinJoinWalletManager::Add(CWallet& wallet) { - m_wallet_manager_map.try_emplace( - wallet.GetName(), - std::make_unique(wallet, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_queueman, m_is_masternode) - ); +void CoinJoinWalletManager::Add(CWallet& wallet) +{ + { + LOCK(cs_wallet_manager_map); + m_wallet_manager_map.try_emplace(wallet.GetName(), + std::make_unique(wallet, *this, m_dmnman, m_mn_metaman, + m_mn_sync, m_queueman, m_is_masternode)); + } g_wallet_init_interface.InitCoinJoinSettings(*this); } -void CoinJoinWalletManager::DoMaintenance() { - for (auto& [wallet_str, walletman] : m_wallet_manager_map) { - walletman->DoMaintenance(m_chainstate, m_connman, m_mempool); +void CoinJoinWalletManager::DoMaintenance() +{ + LOCK(cs_wallet_manager_map); + for (auto& [_, clientman] : m_wallet_manager_map) { + clientman->DoMaintenance(m_chainstate, m_connman, m_mempool); } } void CoinJoinWalletManager::Remove(const std::string& name) { - m_wallet_manager_map.erase(name); + { + LOCK(cs_wallet_manager_map); + m_wallet_manager_map.erase(name); + } g_wallet_init_interface.InitCoinJoinSettings(*this); } void CoinJoinWalletManager::Flush(const std::string& name) { - auto clientman = Get(name); - assert(clientman != nullptr); + auto clientman = Assert(Get(name)); clientman->ResetPool(); clientman->StopMixing(); } CCoinJoinClientManager* CoinJoinWalletManager::Get(const std::string& name) const { + LOCK(cs_wallet_manager_map); auto it = m_wallet_manager_map.find(name); return (it != m_wallet_manager_map.end()) ? it->second.get() : nullptr; } diff --git a/src/coinjoin/client.h b/src/coinjoin/client.h index ba77e565cf..326f352c6a 100644 --- a/src/coinjoin/client.h +++ b/src/coinjoin/client.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -80,6 +81,7 @@ class CoinJoinWalletManager { {} ~CoinJoinWalletManager() { + LOCK(cs_wallet_manager_map); for (auto& [wallet_name, cj_man] : m_wallet_manager_map) { cj_man.reset(); } @@ -93,7 +95,21 @@ class CoinJoinWalletManager { CCoinJoinClientManager* Get(const std::string& name) const; - const wallet_name_cjman_map& raw() const { return m_wallet_manager_map; } + template + void ForEachCJClientMan(Callable&& func) + { + LOCK(cs_wallet_manager_map); + for (auto&& [_, clientman] : m_wallet_manager_map) { + func(clientman); + } + }; + + template + bool ForAnyCJClientMan(Callable&& func) + { + LOCK(cs_wallet_manager_map); + return ranges::any_of(m_wallet_manager_map, [&](auto& pair) { return func(pair.second); }); + }; private: CChainState& m_chainstate; @@ -105,7 +121,9 @@ class CoinJoinWalletManager { const std::unique_ptr& m_queueman; const bool m_is_masternode; - wallet_name_cjman_map m_wallet_manager_map; + + mutable Mutex cs_wallet_manager_map; + wallet_name_cjman_map m_wallet_manager_map GUARDED_BY(cs_wallet_manager_map); }; class CCoinJoinClientSession : public CCoinJoinBaseSession @@ -113,7 +131,7 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession private: CWallet& m_wallet; CoinJoinWalletManager& m_walletman; - CCoinJoinClientManager& m_manager; + CCoinJoinClientManager& m_clientman; CDeterministicMNManager& m_dmnman; CMasternodeMetaMan& m_mn_metaman; const CMasternodeSync& m_mn_sync; @@ -168,8 +186,10 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin); public: - explicit CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman, - const CMasternodeSync& mn_sync, const std::unique_ptr& queueman, bool is_masternode); + explicit CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, + CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, + CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, + const std::unique_ptr& queueman, bool is_masternode); void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv); diff --git a/src/dsnotificationinterface.cpp b/src/dsnotificationinterface.cpp index 3a30fec2c0..f948aa0148 100644 --- a/src/dsnotificationinterface.cpp +++ b/src/dsnotificationinterface.cpp @@ -86,9 +86,8 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con m_cj_ctx->dstxman->UpdatedBlockTip(pindexNew, *m_llmq_ctx->clhandler, m_mn_sync); #ifdef ENABLE_WALLET - for (auto& pair : m_cj_ctx->walletman->raw()) { - pair.second->UpdatedBlockTip(pindexNew); - } + m_cj_ctx->walletman->ForEachCJClientMan( + [&pindexNew](std::unique_ptr& clientman) { clientman->UpdatedBlockTip(pindexNew); }); #endif // ENABLE_WALLET m_llmq_ctx->isman->UpdatedBlockTip(pindexNew); diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 6b195ea831..89336190ed 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -55,7 +55,6 @@ CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, CNetFulfi m_mn_sync{mn_sync}, nTimeLastDiff(0), nCachedBlockHeight(0), - setRequestedObjects(), fRateChecksEnabled(true), votedFundingYesTriggerHash(std::nullopt), mapTrigger{} @@ -172,7 +171,7 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash); - if (!AcceptObjectMessage(nHash)) { + if (!AcceptMessage(nHash)) { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received unrequested object: %s\n", strHash); return {}; } @@ -240,7 +239,7 @@ PeerMsgRet CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, Pe std::string strHash = nHash.ToString(); - if (!AcceptVoteMessage(nHash)) { + if (!AcceptMessage(nHash)) { LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d\n", vote.ToString(tip_mn_list), strHash, peer.GetId()); return {}; @@ -453,7 +452,18 @@ void CGovernanceManager::CheckAndRemove() } } - LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- %s\n", ToString()); + // forget about expired requests + auto r_it = m_requested_hash_time.begin(); + while (r_it != m_requested_hash_time.end()) { + if (r_it->second < std::chrono::seconds(nNow)) { + m_requested_hash_time.erase(r_it++); + } else { + ++r_it; + } + } + + LogPrint(BCLog::GOBJECT, "CGovernanceManager::UpdateCachesAndClean -- %s, m_requested_hash_time size=%d\n", + ToString(), m_requested_hash_time.size()); } const CGovernanceObject* CGovernanceManager::FindConstGovernanceObject(const uint256& nHash) const @@ -837,23 +847,13 @@ bool CGovernanceManager::ConfirmInventoryRequest(const CInv& inv) return false; } - - hash_s_t* setHash = nullptr; - switch (inv.type) { - case MSG_GOVERNANCE_OBJECT: - setHash = &setRequestedObjects; - break; - case MSG_GOVERNANCE_OBJECT_VOTE: - setHash = &setRequestedVotes; - break; - default: - return false; - } - - const auto& [_itr, inserted] = setHash->insert(inv.hash); + const auto valid_until = GetTime() + std::chrono::seconds(RELIABLE_PROPAGATION_TIME); + const auto& [_itr, inserted] = m_requested_hash_time.emplace(inv.hash, valid_until); if (inserted) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest added inv to requested set\n"); + LogPrint(BCLog::GOBJECT, /* Continued */ + "CGovernanceManager::ConfirmInventoryRequest added %s inv hash to m_requested_hash_time, size=%d\n", + inv.type == MSG_GOVERNANCE_OBJECT ? "object" : "vote", m_requested_hash_time.size()); } LogPrint(BCLog::GOBJECT, "CGovernanceManager::ConfirmInventoryRequest reached end, returning true\n"); @@ -1330,27 +1330,16 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& return int(vTriggerObjHashes.size() + vOtherObjHashes.size()); } -bool CGovernanceManager::AcceptObjectMessage(const uint256& nHash) +bool CGovernanceManager::AcceptMessage(const uint256& nHash) { LOCK(cs); - return AcceptMessage(nHash, setRequestedObjects); -} - -bool CGovernanceManager::AcceptVoteMessage(const uint256& nHash) -{ - LOCK(cs); - return AcceptMessage(nHash, setRequestedVotes); -} - -bool CGovernanceManager::AcceptMessage(const uint256& nHash, hash_s_t& setHash) -{ - auto it = setHash.find(nHash); - if (it == setHash.end()) { + auto it = m_requested_hash_time.find(nHash); + if (it == m_requested_hash_time.end()) { // We never requested this return false; } // Only accept one response - setHash.erase(it); + m_requested_hash_time.erase(it); return true; } @@ -1580,7 +1569,7 @@ void CGovernanceManager::RemoveInvalidVotes() cmapVoteToObject.Erase(voteHash); cmapInvalidVotes.Erase(voteHash); cmmapOrphanVotes.Erase(voteHash); - setRequestedVotes.erase(voteHash); + m_requested_hash_time.erase(voteHash); } } } diff --git a/src/governance/governance.h b/src/governance/governance.h index 40c69af981..9e38f411fa 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -270,8 +270,7 @@ class CGovernanceManager : public GovernanceStore int nCachedBlockHeight; std::map mapPostponedObjects; hash_s_t setAdditionalRelayObjects; - hash_s_t setRequestedObjects; - hash_s_t setRequestedVotes; + std::map m_requested_hash_time; bool fRateChecksEnabled; std::optional votedFundingYesTriggerHash; std::map> mapTrigger; @@ -389,13 +388,8 @@ class CGovernanceManager : public GovernanceStore bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman); - /// Called to indicate a requested object has been received - bool AcceptObjectMessage(const uint256& nHash); - - /// Called to indicate a requested vote has been received - bool AcceptVoteMessage(const uint256& nHash); - - static bool AcceptMessage(const uint256& nHash, hash_s_t& setHash); + /// Called to indicate a requested object or vote has been received + bool AcceptMessage(const uint256& nHash); void CheckOrphanVotes(CGovernanceObject& govobj, PeerManager& peerman); diff --git a/src/gsl/pointers.h b/src/gsl/pointers.h index bf444ef5f2..93a194999e 100644 --- a/src/gsl/pointers.h +++ b/src/gsl/pointers.h @@ -20,12 +20,10 @@ #include // for Ensures, Expects #include -#include // for forward #include // for ptrdiff_t, nullptr_t, size_t -#include // for shared_ptr, unique_ptr -#include // for hash +#include // for shared_ptr, unique_ptr, hash #include // for enable_if_t, is_convertible, is_assignable -#include // for declval +#include // for declval, forward #if !defined(GSL_NO_IOSTREAMS) #include // for ostream diff --git a/src/init.cpp b/src/init.cpp index 88e981898a..a8b518d46b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -717,7 +717,6 @@ void SetupServerArgs(NodeContext& node) argsman.AddArg("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", DEFAULT_STOPAFTERBLOCKIMPORT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-stopatheight", strprintf("Stop running after reaching the given height in the main chain (default: %u)", DEFAULT_STOPATHEIGHT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-watchquorums=", strprintf("Watch and validate quorum communication (default: %u)", llmq::DEFAULT_WATCH_QUORUMS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_BOOL | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-disablegovernance", strprintf("Disable governance validation (0-1, default: %u)", 0), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-maxsigcachesize=", strprintf("Limit sum of signature cache and script execution cache sizes to MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index dcc399a29d..d84688dcc0 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -198,7 +198,7 @@ class Chain virtual bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, - std::string& err_string) = 0; + bilingual_str& err_string) = 0; //! Calculate mempool ancestor and descendant counts for the given transaction. virtual void getTransactionAncestry(const uint256& txid, size_t& ancestors, size_t& descendants) = 0; diff --git a/src/masternode/utils.cpp b/src/masternode/utils.cpp index 90311288f9..6bf48f2b5c 100644 --- a/src/masternode/utils.cpp +++ b/src/masternode/utils.cpp @@ -23,9 +23,9 @@ void CMasternodeUtils::DoMaintenance(CConnman& connman, CDeterministicMNManager& std::vector vecDmns; // will be empty when no wallet #ifdef ENABLE_WALLET - for (auto& pair : cj_ctx.walletman->raw()) { - pair.second->GetMixingMasternodesInfo(vecDmns); - } + cj_ctx.walletman->ForEachCJClientMan([&vecDmns](const std::unique_ptr& clientman) { + clientman->GetMixingMasternodesInfo(vecDmns); + }); #endif // ENABLE_WALLET // Don't disconnect masternode connections when we have less then the desired amount of outbound nodes diff --git a/src/net.cpp b/src/net.cpp index 73569a96b8..60d3d551ad 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -257,10 +257,6 @@ bool IsPeerAddrLocalGood(CNode *pnode) std::optional GetLocalAddrForPeer(CNode& node) { CService addrLocal{GetLocalAddress(node.addr)}; - if (gArgs.GetBoolArg("-addrmantest", false)) { - // use IPv4 loopback during addrmantest - addrLocal = CService(LookupNumeric("127.0.0.1", GetListenPort())); - } // If discovery is enabled, sometimes give our peer the address it // tells us that it sees us as in case it has a better idea of our // address than we do. @@ -280,7 +276,7 @@ std::optional GetLocalAddrForPeer(CNode& node) addrLocal.SetIP(node.GetAddrLocal()); } } - if (addrLocal.IsRoutable() || gArgs.GetBoolArg("-addrmantest", false)) + if (addrLocal.IsRoutable()) { LogPrint(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToString(), node.GetId()); return addrLocal; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index c5a76acf10..db6d9c70ff 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -5095,9 +5095,9 @@ void PeerManagerImpl::ProcessMessage( //probably one the extensions #ifdef ENABLE_WALLET ProcessPeerMsgRet(m_cj_ctx->queueman->ProcessMessage(pfrom, msg_type, vRecv), pfrom); - for (auto& pair : m_cj_ctx->walletman->raw()) { - pair.second->ProcessMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv); - } + m_cj_ctx->walletman->ForEachCJClientMan([this, &pfrom, &msg_type, &vRecv](std::unique_ptr& clientman) { + clientman->ProcessMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv); + }); #endif // ENABLE_WALLET ProcessPeerMsgRet(m_cj_ctx->server->ProcessMessage(pfrom, msg_type, vRecv), pfrom); ProcessPeerMsgRet(m_sporkman.ProcessMessage(pfrom, m_connman, *this, msg_type, vRecv), pfrom); diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index eba23b0195..d453ff8975 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -879,7 +879,7 @@ class ChainImpl : public Chain auto it = m_node.mempool->GetIter(txid); return it && (*it)->GetCountWithDescendants() > 1; } - bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, std::string& err_string) override + bool broadcastTransaction(const CTransactionRef& tx, const CAmount& max_tx_fee, bool relay, bilingual_str& err_string) override { const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false); // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures. diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp index 76264ffb1c..9c039c1a6e 100644 --- a/src/node/transaction.cpp +++ b/src/node/transaction.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -28,7 +29,7 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str } } -TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback, bool bypass_limits) +TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, bilingual_str& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback, bool bypass_limits) { // BroadcastTransaction can be called by either sendrawtransaction RPC or wallet RPCs. // node.peerman is assigned both before chain clients and before RPC server is accepting calls, @@ -59,7 +60,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, bypass_limits, true /* test_accept */); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { - return HandleATMPError(result.m_state, err_string); + return HandleATMPError(result.m_state, err_string.original); } else if (result.m_base_fees.value() > max_tx_fee) { return TransactionError::MAX_FEE_EXCEEDED; } @@ -68,7 +69,7 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t const MempoolAcceptResult result = AcceptToMemoryPool(node.chainman->ActiveChainstate(), *node.mempool, tx, bypass_limits, false /* test_accept */); if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { - return HandleATMPError(result.m_state, err_string); + return HandleATMPError(result.m_state, err_string.original); } // Transaction was accepted to the mempool. diff --git a/src/node/transaction.h b/src/node/transaction.h index 3867401586..511a252817 100644 --- a/src/node/transaction.h +++ b/src/node/transaction.h @@ -35,12 +35,12 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10}; * * @param[in] node reference to node context * @param[in] tx the transaction to broadcast - * @param[out] err_string reference to std::string to fill with error string if available + * @param[out] err_string reference to bilingual_str to fill with error string if available * @param[in] relay flag if both mempool insertion and p2p relay are requested * @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC. * return error */ -[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& highfee, bool relay, bool wait_callback, bool bypass_limits = false); +[[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, bilingual_str& err_string, const CAmount& highfee, bool relay, bool wait_callback, bool bypass_limits = false); /** * Return transaction with a given hash. diff --git a/src/qt/psbtoperationsdialog.cpp b/src/qt/psbtoperationsdialog.cpp index bb642d1f1b..609f442bf2 100644 --- a/src/qt/psbtoperationsdialog.cpp +++ b/src/qt/psbtoperationsdialog.cpp @@ -107,7 +107,7 @@ void PSBTOperationsDialog::broadcastTransaction() } CTransactionRef tx = MakeTransactionRef(mtx); - std::string err_string; + 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); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index e5ffa1f317..d3c37f7345 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -1165,12 +1166,12 @@ RPCHelpMan sendrawtransaction() bool bypass_limits = false; if (!request.params[3].isNull()) bypass_limits = request.params[3].get_bool(); - std::string err_string; + bilingual_str err_string; AssertLockNotHeld(cs_main); NodeContext& node = EnsureAnyNodeContext(request.context); const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /* relay */ true, /* wait_callback */ true, bypass_limits); if (TransactionError::OK != err) { - throw JSONRPCTransactionError(err, err_string); + throw JSONRPCTransactionError(err, err_string.original); } return tx->GetHash().GetHex(); @@ -1199,7 +1200,7 @@ static RPCHelpMan testmempoolaccept() RPCResult{ RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n" "Returns results for each transaction in the same order they were passed in.\n" - "It is possible for transactions to not be fully validated ('allowed' unset) if another transaction failed.\n", + "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n", { {RPCResult::Type::OBJ, "", "", { diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 11df0c274e..6453c14622 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -18,6 +18,7 @@ #include #include #include +#include CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime) { @@ -227,22 +228,22 @@ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, int nHashType = ParseSighashString(hashType); // Script verification errors - std::map input_errors; + std::map input_errors; bool complete = SignTransaction(mtx, keystore, coins, nHashType, input_errors); SignTransactionResultToJSON(mtx, complete, coins, input_errors, result); } -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map& coins, const std::map& input_errors, UniValue& result) +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map& coins, const std::map& input_errors, UniValue& result) { // Make errors UniValue UniValue vErrors(UniValue::VARR); for (const auto& err_pair : input_errors) { - if (err_pair.second == "Missing amount") { + if (err_pair.second.original == "Missing amount") { // This particular error needs to be an exception for some reason throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing amount for %s", coins.at(mtx.vin.at(err_pair.first).prevout).out.ToString())); } - TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second); + TxInErrorToJSON(mtx.vin.at(err_pair.first), vErrors, err_pair.second.original); } result.pushKV("hex", EncodeHexTx(CTransaction(mtx))); diff --git a/src/rpc/rawtransaction_util.h b/src/rpc/rawtransaction_util.h index c8865588bc..6ee04e77e1 100644 --- a/src/rpc/rawtransaction_util.h +++ b/src/rpc/rawtransaction_util.h @@ -8,6 +8,7 @@ #include #include +struct bilingual_str; class FillableSigningProvider; class UniValue; struct CMutableTransaction; @@ -25,7 +26,7 @@ class SigningProvider; * @param result JSON object where signed transaction results accumulate */ void SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore, const std::map& coins, const UniValue& hashType, UniValue& result); -void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map& coins, const std::map& input_errors, UniValue& result); +void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const std::map& coins, const std::map& input_errors, UniValue& result); /** * Parse a prevtxs UniValue array and get the map of coins from it diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 054d8de795..bc42d65e21 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1162,6 +1162,14 @@ std::unique_ptr InferDescriptor(const CScript& script, const Signing return InferScript(script, ParseScriptContext::TOP, provider); } +uint256 DescriptorID(const Descriptor& desc) +{ + std::string desc_str = desc.ToString(); + uint256 id; + CSHA256().Write((unsigned char*)desc_str.data(), desc_str.size()).Finalize(id.begin()); + return id; +} + void DescriptorCache::CacheParentExtPubKey(uint32_t key_exp_pos, const CExtPubKey& xpub) { m_parent_xpubs[key_exp_pos] = xpub; diff --git a/src/script/descriptor.h b/src/script/descriptor.h index f5bbf487c6..c10329c484 100644 --- a/src/script/descriptor.h +++ b/src/script/descriptor.h @@ -182,4 +182,9 @@ std::string GetDescriptorChecksum(const std::string& descriptor); */ std::unique_ptr InferDescriptor(const CScript& script, const SigningProvider& provider); +/** Unique identifier that may not change over time, unless explicitly marked as not backwards compatible. +* This is not part of BIP 380, not guaranteed to be interoperable and should not be exposed to the user. +*/ +uint256 DescriptorID(const Descriptor& desc); + #endif // BITCOIN_SCRIPT_DESCRIPTOR_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index bb120d784c..c9491f65f5 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -11,6 +11,7 @@ #include