Merge pull request #5163 from kittywhiskers/mempool_deglob

backport: merge bitcoin#20222, #18766, #14033, #19486, #19607, #20291, partial #20187, #20228 (deglobalize addrman and feeEstimator)
This commit is contained in:
UdjinM6 2023-02-28 00:11:41 +03:00 committed by GitHub
commit 7e57ae6956
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 373 additions and 399 deletions

View File

@ -268,8 +268,18 @@ protected:
//! Select several addresses at once. //! Select several addresses at once.
void GetAddr_(std::vector<CAddress> &vAddr) EXCLUSIVE_LOCKS_REQUIRED(cs); void GetAddr_(std::vector<CAddress> &vAddr) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Mark an entry as currently-connected-to. /** We have successfully connected to this peer. Calling this function
void Connected_(const CService &addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs); * updates the CAddress's nTime, which is used in our IsTerrible()
* decisions and gossiped to peers. Callers should be careful that updating
* this information doesn't leak topology information to network spies.
*
* net_processing calls this function when it *disconnects* from a peer to
* not leak information about currently connected peers.
*
* @param[in] addr The address of the peer we were connected to
* @param[in] nTime The time that we were last connected to this peer
*/
void Connected_(const CService& addr, int64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(cs);
//! Update an entry's service bits. //! Update an entry's service bits.
void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs); void SetServices_(const CService &addr, ServiceFlags nServices) EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -710,7 +720,7 @@ public:
return vAddr; return vAddr;
} }
//! Mark an entry as currently-connected-to. //! Outer function for Connected_()
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
{ {
LOCK(cs); LOCK(cs);

View File

@ -54,7 +54,6 @@ void CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CDataStream&
vRecv >> dsq; vRecv >> dsq;
if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) { if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 100); Misbehaving(peer.GetId(), 100);
return; return;
} }
@ -64,7 +63,6 @@ void CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CDataStream&
if (auto dmn = mnList.GetValidMN(dsq.m_protxHash)) { if (auto dmn = mnList.GetValidMN(dsq.m_protxHash)) {
dsq.masternodeOutpoint = dmn->collateralOutpoint; dsq.masternodeOutpoint = dmn->collateralOutpoint;
} else { } else {
LOCK(cs_main);
Misbehaving(peer.GetId(), 10); Misbehaving(peer.GetId(), 10);
return; return;
} }
@ -100,7 +98,6 @@ void CCoinJoinClientQueueManager::ProcessDSQueue(const CNode& peer, CDataStream&
} }
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 10); Misbehaving(peer.GetId(), 10);
return; return;
} }
@ -756,7 +753,7 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
// //
// Passively run mixing in the background to mix funds based on the given configuration. // Passively run mixing in the background to mix funds based on the given configuration.
// //
bool CCoinJoinClientSession::DoAutomaticDenominating(CTxMemPool& mempool, CConnman& connman, bool fDryRun) bool CCoinJoinClientSession::DoAutomaticDenominating(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool, bool fDryRun)
{ {
if (fMasternodeMode) return false; // no client-side mixing on masternodes if (fMasternodeMode) return false; // no client-side mixing on masternodes
if (nState != POOL_STATE_IDLE) return false; if (nState != POOL_STATE_IDLE) return false;
@ -875,12 +872,12 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(CTxMemPool& mempool, CConnm
// there are funds to denominate and denominated balance does not exceed // there are funds to denominate and denominated balance does not exceed
// max amount to mix yet. // max amount to mix yet.
if (nBalanceAnonimizableNonDenom >= nValueMin + CCoinJoin::GetCollateralAmount() && nBalanceToDenominate > 0) { if (nBalanceAnonimizableNonDenom >= nValueMin + CCoinJoin::GetCollateralAmount() && nBalanceToDenominate > 0) {
CreateDenominated(nBalanceToDenominate); CreateDenominated(fee_estimator, nBalanceToDenominate);
} }
//check if we have the collateral sized inputs //check if we have the collateral sized inputs
if (!mixingWallet.HasCollateralInputs()) { if (!mixingWallet.HasCollateralInputs()) {
return !mixingWallet.HasCollateralInputs(false) && MakeCollateralAmounts(); return !mixingWallet.HasCollateralInputs(false) && MakeCollateralAmounts(fee_estimator);
} }
if (nSessionID) { if (nSessionID) {
@ -936,7 +933,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(CTxMemPool& mempool, CConnm
return false; return false;
} }
bool CCoinJoinClientManager::DoAutomaticDenominating(CTxMemPool& mempool, CConnman& connman, bool fDryRun) bool CCoinJoinClientManager::DoAutomaticDenominating(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool, bool fDryRun)
{ {
if (fMasternodeMode) return false; // no client-side mixing on masternodes if (fMasternodeMode) return false; // no client-side mixing on masternodes
if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false; if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false;
@ -978,7 +975,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(CTxMemPool& mempool, CConnm
return false; return false;
} }
fResult &= session.DoAutomaticDenominating(mempool, connman, fDryRun); fResult &= session.DoAutomaticDenominating(connman, fee_estimator, mempool, fDryRun);
} }
return fResult; return fResult;
@ -1372,7 +1369,7 @@ bool CCoinJoinClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, s
} }
// Create collaterals by looping through inputs grouped by addresses // Create collaterals by looping through inputs grouped by addresses
bool CCoinJoinClientSession::MakeCollateralAmounts() bool CCoinJoinClientSession::MakeCollateralAmounts(const CBlockPolicyEstimator& fee_estimator)
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
@ -1395,13 +1392,13 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
// First try to use only non-denominated funds // First try to use only non-denominated funds
for (const auto& item : vecTally) { for (const auto& item : vecTally) {
if (!MakeCollateralAmounts(item, false)) continue; if (!MakeCollateralAmounts(fee_estimator, item, false)) continue;
return true; return true;
} }
// There should be at least some denominated funds we should be able to break in pieces to continue mixing // There should be at least some denominated funds we should be able to break in pieces to continue mixing
for (const auto& item : vecTally) { for (const auto& item : vecTally) {
if (!MakeCollateralAmounts(item, true)) continue; if (!MakeCollateralAmounts(fee_estimator, item, true)) continue;
return true; return true;
} }
@ -1411,7 +1408,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
} }
// Split up large inputs or create fee sized inputs // Split up large inputs or create fee sized inputs
bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated) bool CCoinJoinClientSession::MakeCollateralAmounts(const CBlockPolicyEstimator& fee_estimator, const CompactTallyItem& tallyItem, bool fTryDenominated)
{ {
AssertLockHeld(mixingWallet.cs_wallet); AssertLockHeld(mixingWallet.cs_wallet);
@ -1434,7 +1431,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tally
return false; return false;
} }
CTransactionBuilder txBuilder(pwallet, tallyItem); CTransactionBuilder txBuilder(pwallet, tallyItem, fee_estimator);
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString()); LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
@ -1553,7 +1550,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
} }
// Create denominations by looping through inputs grouped by addresses // Create denominations by looping through inputs grouped by addresses
bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate) bool CCoinJoinClientSession::CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate)
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
@ -1577,7 +1574,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
bool fCreateMixingCollaterals = !mixingWallet.HasCollateralInputs(); bool fCreateMixingCollaterals = !mixingWallet.HasCollateralInputs();
for (const auto& item : vecTally) { for (const auto& item : vecTally) {
if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals)) continue; if (!CreateDenominated(fee_estimator, nBalanceToDenominate, item, fCreateMixingCollaterals)) continue;
return true; return true;
} }
@ -1586,7 +1583,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
} }
// Create denominations // Create denominations
bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals) bool CCoinJoinClientSession::CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
{ {
AssertLockHeld(mixingWallet.cs_wallet); AssertLockHeld(mixingWallet.cs_wallet);
@ -1604,7 +1601,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
return false; return false;
} }
CTransactionBuilder txBuilder(pwallet, tallyItem); CTransactionBuilder txBuilder(pwallet, tallyItem, fee_estimator);
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString()); LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
@ -1815,7 +1812,7 @@ void CCoinJoinClientQueueManager::DoMaintenance()
CheckQueue(); CheckQueue();
} }
void CCoinJoinClientManager::DoMaintenance(CTxMemPool& mempool, CConnman& connman) void CCoinJoinClientManager::DoMaintenance(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool)
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return; if (!CCoinJoinClientOptions::IsEnabled()) return;
if (m_mn_sync == nullptr) return; if (m_mn_sync == nullptr) return;
@ -1830,7 +1827,7 @@ void CCoinJoinClientManager::DoMaintenance(CTxMemPool& mempool, CConnman& connma
CheckTimeout(); CheckTimeout();
ProcessPendingDsaRequest(connman); ProcessPendingDsaRequest(connman);
if (nDoAutoNextRun == nTick) { if (nDoAutoNextRun == nTick) {
DoAutomaticDenominating(mempool, connman); DoAutomaticDenominating(connman, fee_estimator, mempool);
nDoAutoNextRun = nTick + COINJOIN_AUTO_TIMEOUT_MIN + GetRandInt(COINJOIN_AUTO_TIMEOUT_MAX - COINJOIN_AUTO_TIMEOUT_MIN); nDoAutoNextRun = nTick + COINJOIN_AUTO_TIMEOUT_MIN + GetRandInt(COINJOIN_AUTO_TIMEOUT_MAX - COINJOIN_AUTO_TIMEOUT_MIN);
} }
} }
@ -1867,14 +1864,13 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const
obj.pushKV("sessions", arrSessions); obj.pushKV("sessions", arrSessions);
} }
void DoCoinJoinMaintenance(CTxMemPool& mempool, CConnman& connman) void DoCoinJoinMaintenance(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool)
{ {
if (coinJoinClientQueueManager != nullptr) { if (coinJoinClientQueueManager != nullptr) {
coinJoinClientQueueManager->DoMaintenance(); coinJoinClientQueueManager->DoMaintenance();
} }
for (const auto& pair : coinJoinClientManagers) { for (const auto& pair : coinJoinClientManagers) {
pair.second->DoMaintenance(mempool, connman); pair.second->DoMaintenance(connman, fee_estimator, mempool);
} }
} }

View File

@ -18,6 +18,7 @@ using CDeterministicMNCPtr = std::shared_ptr<const CDeterministicMN>;
class CCoinJoinClientManager; class CCoinJoinClientManager;
class CCoinJoinClientQueueManager; class CCoinJoinClientQueueManager;
class CBlockPolicyEstimator;
class CConnman; class CConnman;
class CNode; class CNode;
class CTxMemPool; class CTxMemPool;
@ -88,12 +89,12 @@ private:
CWallet& mixingWallet; CWallet& mixingWallet;
/// Create denominations /// Create denominations
bool CreateDenominated(CAmount nBalanceToDenominate); bool CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate);
bool CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals); bool CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals);
/// Split up large inputs or make fee sized inputs /// Split up large inputs or make fee sized inputs
bool MakeCollateralAmounts(); bool MakeCollateralAmounts(const CBlockPolicyEstimator& fee_estimator);
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated); bool MakeCollateralAmounts(const CBlockPolicyEstimator& fee_estimator, const CompactTallyItem& tallyItem, bool fTryDenominated);
bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason); bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason);
@ -138,7 +139,7 @@ public:
bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const; bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
/// Passively run mixing in the background according to the configuration in settings /// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CTxMemPool& mempool, CConnman& connman, bool fDryRun = false) LOCKS_EXCLUDED(cs_coinjoin); bool DoAutomaticDenominating(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool, bool fDryRun = false) LOCKS_EXCLUDED(cs_coinjoin);
/// As a client, submit part of a future mixing transaction to a Masternode to start the process /// As a client, submit part of a future mixing transaction to a Masternode to start the process
bool SubmitDenominate(CConnman& connman); bool SubmitDenominate(CConnman& connman);
@ -221,7 +222,7 @@ public:
bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const LOCKS_EXCLUDED(cs_deqsessions); bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const LOCKS_EXCLUDED(cs_deqsessions);
/// Passively run mixing in the background according to the configuration in settings /// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CTxMemPool& mempool, CConnman& connman, bool fDryRun = false) LOCKS_EXCLUDED(cs_deqsessions); bool DoAutomaticDenominating(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool, bool fDryRun = false) LOCKS_EXCLUDED(cs_deqsessions);
bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman) LOCKS_EXCLUDED(cs_deqsessions); bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman) LOCKS_EXCLUDED(cs_deqsessions);
bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const LOCKS_EXCLUDED(cs_deqsessions); bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const LOCKS_EXCLUDED(cs_deqsessions);
@ -237,12 +238,12 @@ public:
void UpdatedBlockTip(const CBlockIndex* pindex); void UpdatedBlockTip(const CBlockIndex* pindex);
void DoMaintenance(CTxMemPool& mempool, CConnman& connman); void DoMaintenance(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool);
void GetJsonInfo(UniValue& obj) const LOCKS_EXCLUDED(cs_deqsessions); void GetJsonInfo(UniValue& obj) const LOCKS_EXCLUDED(cs_deqsessions);
}; };
void DoCoinJoinMaintenance(CTxMemPool& mempool, CConnman& connman); void DoCoinJoinMaintenance(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool);
#endif // BITCOIN_COINJOIN_CLIENT_H #endif // BITCOIN_COINJOIN_CLIENT_H

View File

@ -113,7 +113,6 @@ void CCoinJoinServer::ProcessDSQUEUE(const CNode& peer, CDataStream& vRecv)
vRecv >> dsq; vRecv >> dsq;
if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) { if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 100); Misbehaving(peer.GetId(), 100);
return; return;
} }
@ -123,7 +122,6 @@ void CCoinJoinServer::ProcessDSQUEUE(const CNode& peer, CDataStream& vRecv)
if (auto dmn = mnList.GetValidMN(dsq.m_protxHash)) { if (auto dmn = mnList.GetValidMN(dsq.m_protxHash)) {
dsq.masternodeOutpoint = dmn->collateralOutpoint; dsq.masternodeOutpoint = dmn->collateralOutpoint;
} else { } else {
LOCK(cs_main);
Misbehaving(peer.GetId(), 10); Misbehaving(peer.GetId(), 10);
return; return;
} }
@ -159,7 +157,6 @@ void CCoinJoinServer::ProcessDSQUEUE(const CNode& peer, CDataStream& vRecv)
} }
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 10); Misbehaving(peer.GetId(), 10);
return; return;
} }

View File

@ -107,7 +107,7 @@ bool CTransactionBuilderOutput::UpdateAmount(const CAmount nNewAmount)
return true; return true;
} }
CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn) : CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn, const CBlockPolicyEstimator& fee_estimator) :
pwallet(pwalletIn), pwallet(pwalletIn),
dummyReserveDestination(pwalletIn.get()), dummyReserveDestination(pwalletIn.get()),
tallyItem(tallyItemIn) tallyItem(tallyItemIn)
@ -115,7 +115,7 @@ CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, con
// Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not // Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
coinControl.m_discard_feerate = ::GetDiscardRate(*pwallet); coinControl.m_discard_feerate = ::GetDiscardRate(*pwallet);
// Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
coinControl.m_feerate = std::max(::feeEstimator.estimateSmartFee(int(pwallet->m_confirm_target), nullptr, true), pwallet->m_pay_tx_fee); coinControl.m_feerate = std::max(fee_estimator.estimateSmartFee(int(pwallet->m_confirm_target), nullptr, true), pwallet->m_pay_tx_fee);
// Change always goes back to origin // Change always goes back to origin
coinControl.destChange = tallyItemIn.txdest; coinControl.destChange = tallyItemIn.txdest;
// Only allow tallyItems inputs for tx creation // Only allow tallyItems inputs for tx creation

View File

@ -7,6 +7,7 @@
#include <wallet/wallet.h> #include <wallet/wallet.h>
class CBlockPolicyEstimator;
class CTransactionBuilder; class CTransactionBuilder;
struct bilingual_str; struct bilingual_str;
@ -100,7 +101,7 @@ class CTransactionBuilder
friend class CTransactionBuilderOutput; friend class CTransactionBuilderOutput;
public: public:
CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn); CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn, const CBlockPolicyEstimator& fee_estimator);
~CTransactionBuilder(); ~CTransactionBuilder();
/// Check it would be possible to add a single output with the amount nAmount. Returns true if its possible and false if not. /// Check it would be possible to add a single output with the amount nAmount. Returns true if its possible and false if not.
bool CouldAddOutput(CAmount nAmountOutput) const; bool CouldAddOutput(CAmount nAmountOutput) const;

View File

@ -10,6 +10,7 @@
class ChainstateManager; class ChainstateManager;
class CTxMemPool; class CTxMemPool;
class CBlockPolicyEstimator;
struct LLMQContext; struct LLMQContext;
struct NodeContext; struct NodeContext;
struct WalletContext; struct WalletContext;
@ -19,6 +20,7 @@ using CoreContext = std::variant<std::nullopt_t,
std::reference_wrapper<WalletContext>, std::reference_wrapper<WalletContext>,
std::reference_wrapper<CTxMemPool>, std::reference_wrapper<CTxMemPool>,
std::reference_wrapper<ChainstateManager>, std::reference_wrapper<ChainstateManager>,
std::reference_wrapper<CBlockPolicyEstimator>,
std::reference_wrapper<LLMQContext>>; std::reference_wrapper<LLMQContext>>;
template<typename T> template<typename T>

View File

@ -70,26 +70,22 @@ void CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, std::string_view ms
// only one MNAUTH allowed // only one MNAUTH allowed
if (!peer.GetVerifiedProRegTxHash().IsNull()) { if (!peer.GetVerifiedProRegTxHash().IsNull()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 100, "duplicate mnauth"); Misbehaving(peer.GetId(), 100, "duplicate mnauth");
return; return;
} }
if ((~peer.nServices) & (NODE_NETWORK | NODE_BLOOM)) { if ((~peer.nServices) & (NODE_NETWORK | NODE_BLOOM)) {
// either NODE_NETWORK or NODE_BLOOM bit is missing in node's services // either NODE_NETWORK or NODE_BLOOM bit is missing in node's services
LOCK(cs_main);
Misbehaving(peer.GetId(), 100, "mnauth from a node with invalid services"); Misbehaving(peer.GetId(), 100, "mnauth from a node with invalid services");
return; return;
} }
if (mnauth.proRegTxHash.IsNull()) { if (mnauth.proRegTxHash.IsNull()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 100, "empty mnauth proRegTxHash"); Misbehaving(peer.GetId(), 100, "empty mnauth proRegTxHash");
return; return;
} }
if (!mnauth.sig.IsValid()) { if (!mnauth.sig.IsValid()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), 100, "invalid mnauth signature"); Misbehaving(peer.GetId(), 100, "invalid mnauth signature");
return; return;
} }
@ -97,7 +93,6 @@ void CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, std::string_view ms
const auto mnList = deterministicMNManager->GetListAtChainTip(); const auto mnList = deterministicMNManager->GetListAtChainTip();
const auto dmn = mnList.GetMN(mnauth.proRegTxHash); const auto dmn = mnList.GetMN(mnauth.proRegTxHash);
if (!dmn) { if (!dmn) {
LOCK(cs_main);
// in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it // in case node was unlucky and not up to date, just let it be connected as a regular node, which gives it
// a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a // a chance to get up-to-date and thus realize that it's not a MN anymore. We still give it a
// low DoS score. // low DoS score.
@ -122,7 +117,6 @@ void CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, std::string_view ms
LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, peer.nVersion, peer.GetId()); LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, peer.nVersion, peer.GetId());
if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) { if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
LOCK(cs_main);
// Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a // Same as above, MN seems to not know its fate yet, so give it a chance to update. If this is a
// malicious node (DoSing us), it'll get banned soon. // malicious node (DoSing us), it'll get banned soon.
Misbehaving(peer.GetId(), 10, "mnauth signature verification failed"); Misbehaving(peer.GetId(), 10, "mnauth signature verification failed");

View File

@ -219,7 +219,6 @@ void CGovernanceManager::ProcessMessage(CNode& peer, CConnman& connman, std::str
} else { } else {
LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what()); LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what());
if ((exception.GetNodePenalty() != 0) && ::masternodeSync->IsSynced()) { if ((exception.GetNodePenalty() != 0) && ::masternodeSync->IsSynced()) {
LOCK(cs_main);
Misbehaving(peer.GetId(), exception.GetNodePenalty()); Misbehaving(peer.GetId(), exception.GetNodePenalty());
} }
return; return;
@ -625,7 +624,6 @@ void CGovernanceManager::SyncObjects(CNode& peer, CConnman& connman) const
if (netfulfilledman.HasFulfilledRequest(peer.addr, NetMsgType::MNGOVERNANCESYNC)) { if (netfulfilledman.HasFulfilledRequest(peer.addr, NetMsgType::MNGOVERNANCESYNC)) {
// Asking for the whole list multiple times in a short period of time is no good // Asking for the whole list multiple times in a short period of time is no good
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- peer already asked me for the list\n", __func__); LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- peer already asked me for the list\n", __func__);
LOCK(cs_main);
Misbehaving(peer.GetId(), 20); Misbehaving(peer.GetId(), 20);
return; return;
} }

View File

@ -120,7 +120,6 @@
#include <zmq/zmqrpc.h> #include <zmq/zmqrpc.h>
#endif #endif
static bool fFeeEstimatesInitialized = false;
static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_PROXYRANDOMIZE = true;
static const bool DEFAULT_REST_ENABLE = false; static const bool DEFAULT_REST_ENABLE = false;
static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false;
@ -136,8 +135,6 @@ static CDSNotificationInterface* pdsNotificationInterface = nullptr;
#define MIN_CORE_FILEDESCRIPTORS 150 #define MIN_CORE_FILEDESCRIPTORS 150
#endif #endif
static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map"; static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
/** /**
* The PID file facilities. * The PID file facilities.
@ -281,22 +278,14 @@ void PrepareShutdown(NodeContext& node)
node.peer_logic.reset(); node.peer_logic.reset();
node.connman.reset(); node.connman.reset();
node.banman.reset(); node.banman.reset();
node.addrman.reset();
if (node.mempool && node.mempool->IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { if (node.mempool && node.mempool->IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) {
DumpMempool(*node.mempool); DumpMempool(*node.mempool);
} }
if (fFeeEstimatesInitialized) // Drop transactions we were still watching, and record fee estimations.
{ if (node.fee_estimator) node.fee_estimator->Flush();
::feeEstimator.FlushUnconfirmed();
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_fileout(fsbridge::fopen(est_path, "wb"), SER_DISK, CLIENT_VERSION);
if (!est_fileout.IsNull())
::feeEstimator.Write(est_fileout);
else
LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string());
fFeeEstimatesInitialized = false;
}
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (node.chainman) { if (node.chainman) {
@ -405,6 +394,7 @@ void Shutdown(NodeContext& node)
globalVerifyHandle.reset(); globalVerifyHandle.reset();
ECC_Stop(); ECC_Stop();
node.mempool.reset(); node.mempool.reset();
node.fee_estimator.reset();
node.chainman = nullptr; node.chainman = nullptr;
node.scheduler.reset(); node.scheduler.reset();
@ -1761,28 +1751,33 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
// is not yet setup and may end up being set up twice if we // is not yet setup and may end up being set up twice if we
// need to reindex later. // need to reindex later.
// see Step 2: parameter interactions for more information about these
fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = args.GetBoolArg("-discover", true);
g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
assert(!node.addrman);
node.addrman = std::make_unique<CAddrMan>();
assert(!node.banman); assert(!node.banman);
node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME));
assert(!node.connman); assert(!node.connman);
node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max())); node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman);
assert(!node.fee_estimator);
// Don't initialize fee estimation with old data if we don't relay transactions,
// as they would never get updated.
if (g_relay_txes) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
// Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads,
// which are all started after this, may use it from the node context.
assert(!node.mempool); assert(!node.mempool);
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); int check_ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (node.mempool) { node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
if (ratio != 0) {
node.mempool->setSanityCheck(1.0 / ratio);
}
}
assert(!node.chainman); assert(!node.chainman);
node.chainman = &g_chainman; node.chainman = &g_chainman;
ChainstateManager& chainman = *Assert(node.chainman); ChainstateManager& chainman = *Assert(node.chainman);
node.peer_logic.reset(new PeerLogicValidation( node.peer_logic.reset(new PeerLogicValidation(
*node.connman, node.banman.get(), *node.scheduler, chainman, *node.mempool, node.llmq_ctx *node.connman, *node.addrman, node.banman.get(), *node.scheduler, chainman, *node.mempool, node.llmq_ctx
)); ));
RegisterValidationInterface(node.peer_logic.get()); RegisterValidationInterface(node.peer_logic.get());
@ -1894,11 +1889,6 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
} }
} }
// see Step 2: parameter interactions for more information about these
fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN);
fDiscover = args.GetBoolArg("-discover", true);
g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY);
for (const std::string& strAddr : args.GetArgs("-externalip")) { for (const std::string& strAddr : args.GetArgs("-externalip")) {
CService addrLocal; CService addrLocal;
if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid())
@ -2264,13 +2254,6 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
return false; return false;
} }
fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION);
// Allowed to fail as this file IS missing on first startup.
if (!est_filein.IsNull())
::feeEstimator.Read(est_filein);
fFeeEstimatesInitialized = true;
// ********************************************************* Step 8: start indexers // ********************************************************* Step 8: start indexers
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex); g_txindex = std::make_unique<TxIndex>(nTxIndexCache, false, fReindex);
@ -2325,7 +2308,9 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
::coinJoinServer = std::make_unique<CCoinJoinServer>(*node.mempool, *node.connman, ::masternodeSync); ::coinJoinServer = std::make_unique<CCoinJoinServer>(*node.mempool, *node.connman, ::masternodeSync);
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
::coinJoinClientQueueManager = std::make_unique<CCoinJoinClientQueueManager>(*node.connman, ::masternodeSync); if (g_relay_txes) {
::coinJoinClientQueueManager = std::make_unique<CCoinJoinClientQueueManager>(*node.connman, ::masternodeSync);
}
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
g_wallet_init_interface.InitCoinJoinSettings(); g_wallet_init_interface.InitCoinJoinSettings();
@ -2396,8 +2381,8 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*::coinJoinServer)), std::chrono::seconds{1}); node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*::coinJoinServer)), std::chrono::seconds{1});
node.scheduler->scheduleEvery(std::bind(&llmq::CDKGSessionManager::CleanupOldContributions, std::ref(*node.llmq_ctx->qdkgsman)), std::chrono::hours{1}); node.scheduler->scheduleEvery(std::bind(&llmq::CDKGSessionManager::CleanupOldContributions, std::ref(*node.llmq_ctx->qdkgsman)), std::chrono::hours{1});
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
} else if(CCoinJoinClientOptions::IsEnabled()) { } else if (g_relay_txes && CCoinJoinClientOptions::IsEnabled()) {
node.scheduler->scheduleEvery(std::bind(&DoCoinJoinMaintenance, std::ref(*node.mempool), std::ref(*node.connman)), std::chrono::seconds{1}); node.scheduler->scheduleEvery(std::bind(&DoCoinJoinMaintenance, std::ref(*node.connman), std::ref(*node.fee_estimator), std::ref(*node.mempool)), std::chrono::seconds{1});
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
} }

View File

@ -312,11 +312,13 @@ public:
} }
CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
{ {
return ::feeEstimator.estimateSmartFee(num_blocks, calc, conservative); if (!m_node.fee_estimator) return {};
return m_node.fee_estimator->estimateSmartFee(num_blocks, calc, conservative);
} }
unsigned int estimateMaxBlocks() override unsigned int estimateMaxBlocks() override
{ {
return ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE); if (!m_node.fee_estimator) return 0;
return m_node.fee_estimator->HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
} }
CFeeRate mempoolMinFee() override CFeeRate mempoolMinFee() override
{ {

View File

@ -332,15 +332,6 @@ public:
} }
} }
bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); } bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) override
{
FeeCalculation fee_calc;
CFeeRate result = ::feeEstimator.estimateSmartFee(num_blocks, &fee_calc, conservative);
if (returned_target) {
*returned_target = fee_calc.returnedTarget;
}
return result;
}
CFeeRate getDustRelayFee() override { return ::dustRelayFee; } CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
{ {

View File

@ -253,9 +253,6 @@ public:
//! Get network active. //! Get network active.
virtual bool getNetworkActive() = 0; virtual bool getNetworkActive() = 0;
//! Estimate smart fee.
virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, int* returned_target = nullptr) = 0;
//! Get dust relay fee. //! Get dust relay fee.
virtual CFeeRate getDustRelayFee() = 0; virtual CFeeRate getDustRelayFee() = 0;

View File

@ -55,14 +55,14 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
if (qc.IsNull()) { if (qc.IsNull()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- null commitment from peer=%d\n", __func__, peer.GetId()); LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- null commitment from peer=%d\n", __func__, peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100)); Misbehaving(peer.GetId(), 100);
return; return;
} }
if (!Params().HasLLMQ(qc.llmqType)) { if (!Params().HasLLMQ(qc.llmqType)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__,
ToUnderlying(qc.llmqType), peer.GetId()); ToUnderlying(qc.llmqType), peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100)); Misbehaving(peer.GetId(), 100);
return; return;
} }
auto type = qc.llmqType; auto type = qc.llmqType;
@ -125,7 +125,7 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- commitment for quorum %s:%d is not valid quorumIndex[%d] nversion[%d], peer=%d\n", LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- commitment for quorum %s:%d is not valid quorumIndex[%d] nversion[%d], peer=%d\n",
__func__, qc.quorumHash.ToString(), __func__, qc.quorumHash.ToString(),
ToUnderlying(qc.llmqType), qc.quorumIndex, qc.nVersion, peer.GetId()); ToUnderlying(qc.llmqType), qc.quorumIndex, qc.nVersion, peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100)); Misbehaving(peer.GetId(), 100);
return; return;
} }

View File

@ -125,7 +125,6 @@ void CChainLocksHandler::ProcessNewChainLock(const NodeId from, const llmq::CCha
if (!llmq::CSigningManager::VerifyRecoveredSig(Params().GetConsensus().llmqTypeChainLocks, *llmq::quorumManager, clsig.getHeight(), requestId, clsig.getBlockHash(), clsig.getSig())) { if (!llmq::CSigningManager::VerifyRecoveredSig(Params().GetConsensus().llmqTypeChainLocks, *llmq::quorumManager, clsig.getHeight(), requestId, clsig.getBlockHash(), clsig.getSig())) {
LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- invalid CLSIG (%s), peer=%d\n", __func__, clsig.ToString(), from); LogPrint(BCLog::CHAINLOCKS, "CChainLocksHandler::%s -- invalid CLSIG (%s), peer=%d\n", __func__, clsig.ToString(), from);
if (from != -1) { if (from != -1) {
LOCK(cs_main);
Misbehaving(from, 10); Misbehaving(from, 10);
} }
return; return;

View File

@ -429,7 +429,6 @@ bool ProcessPendingMessageBatch(CDKGSession& session, CDKGPendingMessages& pendi
if (!p.second) { if (!p.second) {
LogPrint(BCLog::LLMQ_DKG, "%s -- failed to deserialize message, peer=%d\n", __func__, nodeId); LogPrint(BCLog::LLMQ_DKG, "%s -- failed to deserialize message, peer=%d\n", __func__, nodeId);
{ {
LOCK(cs_main);
Misbehaving(nodeId, 100); Misbehaving(nodeId, 100);
} }
continue; continue;
@ -439,7 +438,6 @@ bool ProcessPendingMessageBatch(CDKGSession& session, CDKGPendingMessages& pendi
if (ban) { if (ban) {
LogPrint(BCLog::LLMQ_DKG, "%s -- banning node due to failed preverification, peer=%d\n", __func__, nodeId); LogPrint(BCLog::LLMQ_DKG, "%s -- banning node due to failed preverification, peer=%d\n", __func__, nodeId);
{ {
LOCK(cs_main);
Misbehaving(nodeId, 100); Misbehaving(nodeId, 100);
} }
} }
@ -470,7 +468,6 @@ bool ProcessPendingMessageBatch(CDKGSession& session, CDKGPendingMessages& pendi
session.ReceiveMessage(*p.second, ban); session.ReceiveMessage(*p.second, ban);
if (ban) { if (ban) {
LogPrint(BCLog::LLMQ_DKG, "%s -- banning node after ReceiveMessage failed, peer=%d\n", __func__, nodeId); LogPrint(BCLog::LLMQ_DKG, "%s -- banning node after ReceiveMessage failed, peer=%d\n", __func__, nodeId);
LOCK(cs_main);
Misbehaving(nodeId, 100); Misbehaving(nodeId, 100);
badNodes.emplace(nodeId); badNodes.emplace(nodeId);
} }

View File

@ -185,7 +185,6 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor
} }
if (vRecv.empty()) { if (vRecv.empty()) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
} }
@ -198,7 +197,6 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor
vRecv.Rewind(sizeof(uint8_t)); vRecv.Rewind(sizeof(uint8_t));
if (!Params().HasLLMQ(llmqType)) { if (!Params().HasLLMQ(llmqType)) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", ToUnderlying(llmqType)); LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", ToUnderlying(llmqType));
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
@ -219,7 +217,6 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor
if (quorumIndex == -1) { if (quorumIndex == -1) {
CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash)); CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(quorumHash));
if (pQuorumBaseBlockIndex == nullptr) { if (pQuorumBaseBlockIndex == nullptr) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- unknown quorumHash %s\n", quorumHash.ToString()); LogPrintf("CDKGSessionManager -- unknown quorumHash %s\n", quorumHash.ToString());
// NOTE: do not insta-ban for this, we might be lagging behind // NOTE: do not insta-ban for this, we might be lagging behind
Misbehaving(pfrom.GetId(), 10); Misbehaving(pfrom.GetId(), 10);
@ -227,7 +224,6 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor
} }
if (!utils::IsQuorumTypeEnabled(llmqType, quorum_manager, pQuorumBaseBlockIndex->pprev)) { if (!utils::IsQuorumTypeEnabled(llmqType, quorum_manager, pQuorumBaseBlockIndex->pprev)) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- llmqType [%d] quorums aren't active\n", ToUnderlying(llmqType)); LogPrintf("CDKGSessionManager -- llmqType [%d] quorums aren't active\n", ToUnderlying(llmqType));
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
@ -239,14 +235,12 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor
llmqParams.signingActiveQuorumCount - 1 : 0; llmqParams.signingActiveQuorumCount - 1 : 0;
if (quorumIndex > quorumIndexMax) { if (quorumIndex > quorumIndexMax) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- invalid quorumHash %s\n", quorumHash.ToString()); LogPrintf("CDKGSessionManager -- invalid quorumHash %s\n", quorumHash.ToString());
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
} }
if (!dkgSessionHandlers.count(std::make_pair(llmqType, quorumIndex))) { if (!dkgSessionHandlers.count(std::make_pair(llmqType, quorumIndex))) {
LOCK(cs_main);
LogPrintf("CDKGSessionManager -- no session handlers for quorumIndex [%d]\n", quorumIndex); LogPrintf("CDKGSessionManager -- no session handlers for quorumIndex [%d]\n", quorumIndex);
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;

View File

@ -788,7 +788,6 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom, cons
} }
if (!islock->TriviallyValid()) { if (!islock->TriviallyValid()) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
} }
@ -798,14 +797,14 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom, cons
const auto blockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(islock->cycleHash)); const auto blockIndex = WITH_LOCK(cs_main, return LookupBlockIndex(islock->cycleHash));
if (blockIndex == nullptr) { if (blockIndex == nullptr) {
// Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash // Maybe we don't have the block yet or maybe some peer spams invalid values for cycleHash
WITH_LOCK(cs_main, Misbehaving(pfrom.GetId(), 1)); Misbehaving(pfrom.GetId(), 1);
return; return;
} }
// Deterministic islocks MUST use rotation based llmq // Deterministic islocks MUST use rotation based llmq
auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend;
if (blockIndex->nHeight % GetLLMQParams(llmqType).dkgInterval != 0) { if (blockIndex->nHeight % GetLLMQParams(llmqType).dkgInterval != 0) {
WITH_LOCK(cs_main, Misbehaving(pfrom.GetId(), 100)); Misbehaving(pfrom.GetId(), 100);
return; return;
} }
} }

View File

@ -611,7 +611,6 @@ void CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, C
auto errorHandler = [&](const std::string& strError, int nScore = 10) { auto errorHandler = [&](const std::string& strError, int nScore = 10) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- %s: %s, from peer=%d\n", strFunc, msg_type, strError, pfrom.GetId()); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- %s: %s, from peer=%d\n", strFunc, msg_type, strError, pfrom.GetId());
if (nScore > 0) { if (nScore > 0) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), nScore); Misbehaving(pfrom.GetId(), nScore);
} }
}; };

View File

@ -577,7 +577,6 @@ void CSigningManager::ProcessMessageRecoveredSig(const CNode& pfrom, const std::
bool ban = false; bool ban = false;
if (!PreVerifyRecoveredSig(qman, *recoveredSig, ban)) { if (!PreVerifyRecoveredSig(qman, *recoveredSig, ban)) {
if (ban) { if (ban) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
} }
return; return;
@ -752,7 +751,6 @@ bool CSigningManager::ProcessPendingRecoveredSigs()
if (batchVerifier.badSources.count(nodeId)) { if (batchVerifier.badSources.count(nodeId)) {
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId); LogPrint(BCLog::LLMQ, "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId);
LOCK(cs_main);
Misbehaving(nodeId, 100); Misbehaving(nodeId, 100);
continue; continue;
} }

View File

@ -1402,7 +1402,6 @@ void CSigSharesManager::BanNode(NodeId nodeId)
} }
{ {
LOCK(cs_main);
Misbehaving(nodeId, 100); Misbehaving(nodeId, 100);
} }

View File

@ -2949,9 +2949,8 @@ void CConnman::SetNetworkActive(bool active)
uiInterface.NotifyNetworkActiveChanged(fNetworkActive); uiInterface.NotifyNetworkActiveChanged(fNetworkActive);
} }
CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In) : CConnman::CConnman(uint64_t nSeed0In, uint64_t nSeed1In, CAddrMan& addrman_in) :
addrman(Params().AllowMultiplePorts()), addrman(addrman_in), nSeed0(nSeed0In), nSeed1(nSeed1In)
nSeed0(nSeed0In), nSeed1(nSeed1In)
{ {
SetTryNewOutboundPeer(false); SetTryNewOutboundPeer(false);
@ -3309,11 +3308,7 @@ void CConnman::Stop()
void CConnman::DeleteNode(CNode* pnode) void CConnman::DeleteNode(CNode* pnode)
{ {
assert(pnode); assert(pnode);
bool fUpdateConnectionTime = false; m_msgproc->FinalizeNode(*pnode);
m_msgproc->FinalizeNode(pnode->GetId(), fUpdateConnectionTime);
if(fUpdateConnectionTime) {
addrman.Connected(pnode->addr);
}
delete pnode; delete pnode;
} }
@ -3323,26 +3318,6 @@ CConnman::~CConnman()
Stop(); Stop();
} }
size_t CConnman::GetAddressCount() const
{
return addrman.size();
}
void CConnman::SetServices(const CService &addr, ServiceFlags nServices)
{
addrman.SetServices(addr, nServices);
}
void CConnman::MarkAddressGood(const CAddress& addr)
{
addrman.Good(addr);
}
void CConnman::AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty)
{
addrman.Add(vAddr, addrFrom, nTimePenalty);
}
std::vector<CAddress> CConnman::GetAddresses() std::vector<CAddress> CConnman::GetAddresses()
{ {
return addrman.GetAddr(); return addrman.GetAddr();

View File

@ -213,7 +213,7 @@ public:
socketEventsMode = connOptions.socketEventsMode; socketEventsMode = connOptions.socketEventsMode;
} }
CConnman(uint64_t seed0, uint64_t seed1); CConnman(uint64_t seed0, uint64_t seed1, CAddrMan& addrman);
~CConnman(); ~CConnman();
bool Start(CScheduler& scheduler, const Options& options); bool Start(CScheduler& scheduler, const Options& options);
@ -399,10 +399,6 @@ public:
void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion = MIN_PEER_PROTO_VERSION); void RelayInvFiltered(CInv &inv, const uint256 &relatedTxHash, const int minProtoVersion = MIN_PEER_PROTO_VERSION);
// Addrman functions // Addrman functions
size_t GetAddressCount() const;
void SetServices(const CService &addr, ServiceFlags nServices);
void MarkAddressGood(const CAddress& addr);
void AddNewAddresses(const std::vector<CAddress>& vAddr, const CAddress& addrFrom, int64_t nTimePenalty = 0);
std::vector<CAddress> GetAddresses(); std::vector<CAddress> GetAddresses();
// This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding // This allows temporarily exceeding m_max_outbound_full_relay, with the goal of finding
@ -581,7 +577,7 @@ private:
std::vector<ListenSocket> vhListenSocket; std::vector<ListenSocket> vhListenSocket;
std::atomic<bool> fNetworkActive{true}; std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false}; bool fAddressesInitialized{false};
CAddrMan addrman; CAddrMan& addrman;
std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots); std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots);
CCriticalSection cs_vOneShots; CCriticalSection cs_vOneShots;
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
@ -709,7 +705,7 @@ public:
virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0; virtual bool ProcessMessages(CNode* pnode, std::atomic<bool>& interrupt) = 0;
virtual bool SendMessages(CNode* pnode) = 0; virtual bool SendMessages(CNode* pnode) = 0;
virtual void InitializeNode(CNode* pnode) = 0; virtual void InitializeNode(CNode* pnode) = 0;
virtual void FinalizeNode(NodeId id, bool& update_connection_time) = 0; virtual void FinalizeNode(const CNode& node) = 0;
protected: protected:
/** /**

View File

@ -266,14 +266,6 @@ namespace {
struct CNodeState { struct CNodeState {
//! The peer's address //! The peer's address
const CService address; const CService address;
//! Whether we have a fully established connection.
bool fCurrentlyConnected;
//! Accumulated misbehaviour score for this peer.
int nMisbehavior;
//! Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission).
bool m_should_discourage;
//! String name of this peer (debugging/logging purposes).
const std::string name;
//! The best known block we know this peer has announced. //! The best known block we know this peer has announced.
const CBlockIndex *pindexBestKnownBlock; const CBlockIndex *pindexBestKnownBlock;
//! The hash of the last unknown block this peer has announced. //! The hash of the last unknown block this peer has announced.
@ -410,13 +402,9 @@ struct CNodeState {
//! Whether this peer is a manual connection //! Whether this peer is a manual connection
bool m_is_manual_connection; bool m_is_manual_connection;
CNodeState(CAddress addrIn, std::string addrNameIn, bool is_inbound, bool is_manual) : CNodeState(CAddress addrIn, bool is_inbound, bool is_manual) :
address(addrIn), name(std::move(addrNameIn)), m_is_inbound(is_inbound), address(addrIn), m_is_inbound(is_inbound), m_is_manual_connection(is_manual)
m_is_manual_connection (is_manual)
{ {
fCurrentlyConnected = false;
nMisbehavior = 0;
m_should_discourage = false;
pindexBestKnownBlock = nullptr; pindexBestKnownBlock = nullptr;
hashLastUnknownBlock.SetNull(); hashLastUnknownBlock.SetNull();
pindexLastCommonBlock = nullptr; pindexLastCommonBlock = nullptr;
@ -453,6 +441,50 @@ static CNodeState *State(NodeId pnode) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
return &it->second; return &it->second;
} }
/**
* Data structure for an individual peer. This struct is not protected by
* cs_main since it does not contain validation-critical data.
*
* Memory is owned by shared pointers and this object is destructed when
* the refcount drops to zero.
*
* TODO: move most members from CNodeState to this structure.
* TODO: move remaining application-layer data members from CNode to this structure.
*/
struct Peer {
/** Same id as the CNode object for this peer */
const NodeId m_id{0};
/** Protects misbehavior data members */
Mutex m_misbehavior_mutex;
/** Accumulated misbehavior score for this peer */
int nMisbehavior GUARDED_BY(m_misbehavior_mutex){0};
/** Whether this peer should be disconnected and marked as discouraged (unless it has the noban permission). */
bool m_should_discourage GUARDED_BY(m_misbehavior_mutex){false};
Peer(NodeId id) : m_id(id) {}
};
using PeerRef = std::shared_ptr<Peer>;
/**
* Map of all Peer objects, keyed by peer id. This map is protected
* by the global g_peer_mutex. Once a shared pointer reference is
* taken, the lock may be released. Individual fields are protected by
* their own locks.
*/
Mutex g_peer_mutex;
static std::map<NodeId, PeerRef> g_peer_map GUARDED_BY(g_peer_mutex);
/** Get a shared pointer to the Peer object.
* May return nullptr if the Peer object can't be found. */
static PeerRef GetPeerRef(NodeId id)
{
LOCK(g_peer_mutex);
auto it = g_peer_map.find(id);
return it != g_peer_map.end() ? it->second : nullptr;
}
static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main) static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{ {
nPreferredDownload -= state->fPreferredDownload; nPreferredDownload -= state->fPreferredDownload;
@ -906,13 +938,17 @@ static bool IsOutboundDisconnectionCandidate(const CNode& node)
void PeerLogicValidation::InitializeNode(CNode *pnode) { void PeerLogicValidation::InitializeNode(CNode *pnode) {
CAddress addr = pnode->addr; CAddress addr = pnode->addr;
std::string addrName = pnode->GetAddrName();
NodeId nodeid = pnode->GetId(); NodeId nodeid = pnode->GetId();
{ {
LOCK(cs_main); LOCK(cs_main);
mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->fInbound, pnode->m_manual_connection)); mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, pnode->fInbound, pnode->m_manual_connection));
} }
if(!pnode->fInbound) {
PeerRef peer = std::make_shared<Peer>(nodeid);
LOCK(g_peer_mutex);
g_peer_map.emplace_hint(g_peer_map.end(), nodeid, std::move(peer));
}
if (!pnode->fInbound)
PushNodeVersion(*pnode, m_connman, GetTime()); PushNodeVersion(*pnode, m_connman, GetTime());
} }
@ -929,19 +965,24 @@ void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta); scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
} }
void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { void PeerLogicValidation::FinalizeNode(const CNode& node) {
fUpdateConnectionTime = false; NodeId nodeid = node.GetId();
int misbehavior{0};
LOCK(cs_main); LOCK(cs_main);
{
{
PeerRef peer = GetPeerRef(nodeid);
assert(peer != nullptr);
misbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->nMisbehavior);
LOCK(g_peer_mutex);
g_peer_map.erase(nodeid);
}
CNodeState *state = State(nodeid); CNodeState *state = State(nodeid);
assert(state != nullptr); assert(state != nullptr);
if (state->fSyncStarted) if (state->fSyncStarted)
nSyncStarted--; nSyncStarted--;
if (state->nMisbehavior == 0 && state->fCurrentlyConnected) {
fUpdateConnectionTime = true;
}
for (const QueuedBlock& entry : state->vBlocksInFlight) { for (const QueuedBlock& entry : state->vBlocksInFlight) {
mapBlocksInFlight.erase(entry.hash); mapBlocksInFlight.erase(entry.hash);
} }
@ -961,21 +1002,36 @@ void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTim
assert(nPeersWithValidatedDownloads == 0); assert(nPeersWithValidatedDownloads == 0);
assert(g_outbound_peers_with_protect_from_disconnect == 0); assert(g_outbound_peers_with_protect_from_disconnect == 0);
} }
} // cs_main
if (node.fSuccessfullyConnected && misbehavior == 0 && !node.m_block_relay_only_peer && !node.fInbound) {
// Only change visible addrman state for full outbound peers. We don't
// call Connected() for feeler connections since they don't have
// fSuccessfullyConnected set.
m_addrman.Connected(node.addr);
}
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid); LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
} }
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) { bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats) {
LOCK(cs_main); {
CNodeState *state = State(nodeid); LOCK(cs_main);
if (state == nullptr) CNodeState* state = State(nodeid);
return false; if (state == nullptr)
stats.nMisbehavior = state->nMisbehavior; return false;
stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1; stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;
stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1; stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;
for (const QueuedBlock& queue : state->vBlocksInFlight) { for (const QueuedBlock& queue : state->vBlocksInFlight) {
if (queue.pindex) if (queue.pindex)
stats.vHeightInFlight.push_back(queue.pindex->nHeight); stats.vHeightInFlight.push_back(queue.pindex->nHeight);
}
} }
PeerRef peer = GetPeerRef(nodeid);
if (peer == nullptr) return false;
stats.nMisbehavior = WITH_LOCK(peer->m_misbehavior_mutex, return peer->nMisbehavior);
return true; return true;
} }
@ -1125,33 +1181,35 @@ void static ProcessOrphanTx(CConnman& connman, CTxMemPool& mempool, std::set<uin
/** /**
* Increment peer's misbehavior score. If the new value surpasses banscore (specified on startup or by default), mark node to be discouraged, meaning the peer might be disconnected & added to the discouragement filter. * Increment peer's misbehavior score. If the new value surpasses banscore (specified on startup or by default), mark node to be discouraged, meaning the peer might be disconnected & added to the discouragement filter.
*/ */
void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message) EXCLUSIVE_LOCKS_REQUIRED(cs_main) void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message)
{ {
assert(howmuch > 0); assert(howmuch > 0);
CNodeState* const state = State(pnode); PeerRef peer = GetPeerRef(pnode);
if (state == nullptr) return; if (peer == nullptr) return;
state->nMisbehavior += howmuch; LOCK(peer->m_misbehavior_mutex);
peer->nMisbehavior += howmuch;
const int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD); const int banscore = gArgs.GetArg("-banscore", DEFAULT_BANSCORE_THRESHOLD);
const std::string message_prefixed = message.empty() ? "" : (": " + message); const std::string message_prefixed = message.empty() ? "" : (": " + message);
if (state->nMisbehavior >= banscore && state->nMisbehavior - howmuch < banscore) if (peer->nMisbehavior >= banscore && peer->nMisbehavior - howmuch < banscore)
{ {
LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s\n", pnode, state->nMisbehavior - howmuch, state->nMisbehavior, message_prefixed); LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d) DISCOURAGE THRESHOLD EXCEEDED%s\n", pnode, peer->nMisbehavior - howmuch, peer->nMisbehavior, message_prefixed);
state->m_should_discourage = true; peer->m_should_discourage = true;
statsClient.inc("misbehavior.banned", 1.0f); statsClient.inc("misbehavior.banned", 1.0f);
} else { } else {
LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s\n", pnode, state->nMisbehavior - howmuch, state->nMisbehavior, message_prefixed); LogPrint(BCLog::NET, "Misbehaving: peer=%d (%d -> %d)%s\n", pnode, peer->nMisbehavior - howmuch, peer->nMisbehavior, message_prefixed);
statsClient.count("misbehavior.amount", howmuch, 1.0); statsClient.count("misbehavior.amount", howmuch, 1.0);
} }
} }
bool IsBanned(NodeId pnode) bool IsBanned(NodeId pnode)
{ {
CNodeState *state = State(pnode); PeerRef peer = GetPeerRef(pnode);
if (state == nullptr) if (peer == nullptr)
return false; return false;
if (state->m_should_discourage) { LOCK(peer->m_misbehavior_mutex);
if (peer->m_should_discourage) {
return true; return true;
} }
return false; return false;
@ -1176,7 +1234,6 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
case ValidationInvalidReason::CONSENSUS: case ValidationInvalidReason::CONSENSUS:
case ValidationInvalidReason::BLOCK_MUTATED: case ValidationInvalidReason::BLOCK_MUTATED:
if (!via_compact_block) { if (!via_compact_block) {
LOCK(cs_main);
Misbehaving(nodeid, 100, message); Misbehaving(nodeid, 100, message);
return true; return true;
} }
@ -1200,21 +1257,14 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
case ValidationInvalidReason::BLOCK_INVALID_HEADER: case ValidationInvalidReason::BLOCK_INVALID_HEADER:
case ValidationInvalidReason::BLOCK_CHECKPOINT: case ValidationInvalidReason::BLOCK_CHECKPOINT:
case ValidationInvalidReason::BLOCK_INVALID_PREV: case ValidationInvalidReason::BLOCK_INVALID_PREV:
{ Misbehaving(nodeid, 100, message);
LOCK(cs_main);
Misbehaving(nodeid, 100, message);
}
return true; return true;
// Conflicting (but not necessarily invalid) data or different policy: // Conflicting (but not necessarily invalid) data or different policy:
case ValidationInvalidReason::BLOCK_MISSING_PREV: case ValidationInvalidReason::BLOCK_MISSING_PREV:
case ValidationInvalidReason::BLOCK_CHAINLOCK: case ValidationInvalidReason::BLOCK_CHAINLOCK:
case ValidationInvalidReason::TX_BAD_SPECIAL: case ValidationInvalidReason::TX_BAD_SPECIAL:
case ValidationInvalidReason::TX_CONFLICT_LOCK: case ValidationInvalidReason::TX_CONFLICT_LOCK:
{ Misbehaving(nodeid, 10, message);
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
LOCK(cs_main);
Misbehaving(nodeid, 10, message);
}
return true; return true;
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE: case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
case ValidationInvalidReason::BLOCK_TIME_FUTURE: case ValidationInvalidReason::BLOCK_TIME_FUTURE:
@ -1250,9 +1300,10 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para
(GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT);
} }
PeerLogicValidation::PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler &scheduler, ChainstateManager& chainman, CTxMemPool& pool, PeerLogicValidation::PeerLogicValidation(CConnman& connman, CAddrMan& addrman, BanMan* banman, CScheduler &scheduler, ChainstateManager& chainman, CTxMemPool& pool,
std::unique_ptr<LLMQContext>& llmq_ctx) std::unique_ptr<LLMQContext>& llmq_ctx)
: m_connman(connman), : m_connman(connman),
m_addrman(addrman),
m_banman(banman), m_banman(banman),
m_chainman(chainman), m_chainman(chainman),
m_mempool(pool), m_mempool(pool),
@ -1603,7 +1654,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connma
assert(nRelayNodes <= best.size()); assert(nRelayNodes <= best.size());
auto sortfunc = [&best, &hasher, nRelayNodes, addr](CNode* pnode) { auto sortfunc = [&best, &hasher, nRelayNodes, addr](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION && pnode->IsAddrRelayPeer() && pnode->IsAddrCompatible(addr)) { if (pnode->IsAddrRelayPeer() && pnode->IsAddrCompatible(addr)) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize(); uint64_t hashKey = CSipHasher(hasher).Write(pnode->GetId()).Finalize();
for (unsigned int i = 0; i < nRelayNodes; i++) { for (unsigned int i = 0; i < nRelayNodes; i++) {
if (hashKey > best[i].first) { if (hashKey > best[i].first) {
@ -1998,7 +2049,6 @@ inline void static SendBlockTransactions(const CBlock& block, const BlockTransac
BlockTransactions resp(req); BlockTransactions resp(req);
for (size_t i = 0; i < req.indexes.size(); i++) { for (size_t i = 0; i < req.indexes.size(); i++) {
if (req.indexes[i] >= block.vtx.size()) { if (req.indexes[i] >= block.vtx.size()) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "getblocktxn with out-of-bounds tx indices"); Misbehaving(pfrom.GetId(), 100, "getblocktxn with out-of-bounds tx indices");
return; return;
} }
@ -2570,7 +2620,6 @@ void PeerLogicValidation::ProcessMessage(
(msg_type == NetMsgType::FILTERLOAD || (msg_type == NetMsgType::FILTERLOAD ||
msg_type == NetMsgType::FILTERADD)) msg_type == NetMsgType::FILTERADD))
{ {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100); Misbehaving(pfrom.GetId(), 100);
return; return;
} }
@ -2579,7 +2628,6 @@ void PeerLogicValidation::ProcessMessage(
// Each connection can only send one version message // Each connection can only send one version message
if (pfrom.nVersion != 0) if (pfrom.nVersion != 0)
{ {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "redundant version message"); Misbehaving(pfrom.GetId(), 1, "redundant version message");
return; return;
} }
@ -2601,7 +2649,7 @@ void PeerLogicValidation::ProcessMessage(
nServices = ServiceFlags(nServiceInt); nServices = ServiceFlags(nServiceInt);
if (!pfrom.fInbound) if (!pfrom.fInbound)
{ {
m_connman.SetServices(pfrom.addr, nServices); m_addrman.SetServices(pfrom.addr, nServices);
} }
if (!pfrom.fInbound && !pfrom.fFeeler && !pfrom.m_manual_connection && !HasAllDesirableServiceFlags(nServices)) if (!pfrom.fInbound && !pfrom.fFeeler && !pfrom.m_manual_connection && !HasAllDesirableServiceFlags(nServices))
{ {
@ -2668,7 +2716,6 @@ void PeerLogicValidation::ProcessMessage(
if (Params().NetworkIDString() == CBaseChainParams::DEVNET) { if (Params().NetworkIDString() == CBaseChainParams::DEVNET) {
if (cleanSubVer.find(strprintf("devnet.%s", gArgs.GetDevNetName())) == std::string::npos) { if (cleanSubVer.find(strprintf("devnet.%s", gArgs.GetDevNetName())) == std::string::npos) {
LOCK(cs_main);
LogPrintf("connected to wrong devnet. Reported version is %s, expected devnet name is %s\n", cleanSubVer, gArgs.GetDevNetName()); LogPrintf("connected to wrong devnet. Reported version is %s, expected devnet name is %s\n", cleanSubVer, gArgs.GetDevNetName());
if (!pfrom.fInbound) if (!pfrom.fInbound)
Misbehaving(pfrom.GetId(), 100); // don't try to connect again Misbehaving(pfrom.GetId(), 100); // don't try to connect again
@ -2738,12 +2785,9 @@ void PeerLogicValidation::ProcessMessage(
} }
// Get recent addresses // Get recent addresses
if (pfrom.fOneShot || pfrom.nVersion >= CADDR_TIME_VERSION || m_connman.GetAddressCount() < 1000) m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR));
{ pfrom.fGetAddr = true;
m_connman.PushMessage(&pfrom, CNetMsgMaker(nSendVersion).Make(NetMsgType::GETADDR)); m_addrman.Good(pfrom.addr);
pfrom.fGetAddr = true;
}
m_connman.MarkAddressGood(pfrom.addr);
} }
std::string remoteAddr; std::string remoteAddr;
@ -2769,7 +2813,6 @@ void PeerLogicValidation::ProcessMessage(
if (pfrom.nVersion == 0) { if (pfrom.nVersion == 0) {
// Must have a version message before anything else // Must have a version message before anything else
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "non-version message before version handshake"); Misbehaving(pfrom.GetId(), 1, "non-version message before version handshake");
return; return;
} }
@ -2784,9 +2827,6 @@ void PeerLogicValidation::ProcessMessage(
pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION)); pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION));
if (!pfrom.fInbound) { if (!pfrom.fInbound) {
// Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main);
State(pfrom.GetId())->fCurrentlyConnected = true;
LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n", LogPrintf("New outbound peer connected: version: %d, blocks=%d, peer=%d%s (%s)\n",
pfrom.nVersion.load(), pfrom.nStartingHeight, pfrom.nVersion.load(), pfrom.nStartingHeight,
pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""), pfrom.GetId(), (fLogIPs ? strprintf(", peeraddr=%s", pfrom.addr.ToString()) : ""),
@ -2844,7 +2884,6 @@ void PeerLogicValidation::ProcessMessage(
if (!pfrom.fSuccessfullyConnected) { if (!pfrom.fSuccessfullyConnected) {
// Must have a verack message before anything else // Must have a verack message before anything else
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 1, "non-verack message before version handshake"); Misbehaving(pfrom.GetId(), 1, "non-verack message before version handshake");
return; return;
} }
@ -2882,16 +2921,11 @@ void PeerLogicValidation::ProcessMessage(
s >> vAddr; s >> vAddr;
// Don't want addr from older versions unless seeding
if (pfrom.nVersion < CADDR_TIME_VERSION && m_connman.GetAddressCount() > 1000)
return;
if (!pfrom.IsAddrRelayPeer()) { if (!pfrom.IsAddrRelayPeer()) {
return; return;
} }
if (vAddr.size() > 1000) if (vAddr.size() > 1000)
{ {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size())); Misbehaving(pfrom.GetId(), 20, strprintf("%s message size = %u", msg_type, vAddr.size()));
return; return;
} }
@ -2925,12 +2959,11 @@ void PeerLogicValidation::ProcessMessage(
if (fReachable) if (fReachable)
vAddrOk.push_back(addr); vAddrOk.push_back(addr);
} }
m_connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60); m_addrman.Add(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000) if (vAddr.size() < 1000)
pfrom.fGetAddr = false; pfrom.fGetAddr = false;
if (pfrom.fOneShot) if (pfrom.fOneShot)
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
statsClient.gauge("peers.knownAddresses", m_connman.GetAddressCount(), 1.0f);
return; return;
} }
@ -2981,7 +3014,6 @@ void PeerLogicValidation::ProcessMessage(
vRecv >> vInv; vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ) if (vInv.size() > MAX_INV_SZ)
{ {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("message inv size() = %u", vInv.size())); Misbehaving(pfrom.GetId(), 20, strprintf("message inv size() = %u", vInv.size()));
return; return;
} }
@ -3072,7 +3104,6 @@ void PeerLogicValidation::ProcessMessage(
vRecv >> vInv; vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ) if (vInv.size() > MAX_INV_SZ)
{ {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("message getdata size() = %u", vInv.size())); Misbehaving(pfrom.GetId(), 20, strprintf("message getdata size() = %u", vInv.size()));
return; return;
} }
@ -3756,7 +3787,6 @@ void PeerLogicValidation::ProcessMessage(
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks. // Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
unsigned int nCount = ReadCompactSize(vRecv); unsigned int nCount = ReadCompactSize(vRecv);
if (nCount > MAX_HEADERS_RESULTS) { if (nCount > MAX_HEADERS_RESULTS) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount)); Misbehaving(pfrom.GetId(), 20, strprintf("headers message size = %u", nCount));
return; return;
} }
@ -3958,7 +3988,6 @@ void PeerLogicValidation::ProcessMessage(
if (!filter.IsWithinSizeConstraints()) if (!filter.IsWithinSizeConstraints())
{ {
// There is no excuse for sending a too-large filter // There is no excuse for sending a too-large filter
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "too-large bloom filter"); Misbehaving(pfrom.GetId(), 100, "too-large bloom filter");
} }
else if (!pfrom.m_block_relay_only_peer) else if (!pfrom.m_block_relay_only_peer)
@ -3988,7 +4017,6 @@ void PeerLogicValidation::ProcessMessage(
} }
} }
if (bad) { if (bad) {
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, "bad filteradd message"); Misbehaving(pfrom.GetId(), 100, "bad filteradd message");
} }
return; return;
@ -4041,7 +4069,6 @@ void PeerLogicValidation::ProcessMessage(
if (msg_type == NetMsgType::MNLISTDIFF) { if (msg_type == NetMsgType::MNLISTDIFF) {
// we have never requested this // we have never requested this
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, strprintf("received not-requested mnlistdiff. peer=%d", pfrom.GetId())); Misbehaving(pfrom.GetId(), 100, strprintf("received not-requested mnlistdiff. peer=%d", pfrom.GetId()));
return; return;
} }
@ -4065,7 +4092,6 @@ void PeerLogicValidation::ProcessMessage(
if (msg_type == NetMsgType::QUORUMROTATIONINFO) { if (msg_type == NetMsgType::QUORUMROTATIONINFO) {
// we have never requested this // we have never requested this
LOCK(cs_main);
Misbehaving(pfrom.GetId(), 100, strprintf("received not-requested quorumrotationinfo. peer=%d", pfrom.GetId())); Misbehaving(pfrom.GetId(), 100, strprintf("received not-requested quorumrotationinfo. peer=%d", pfrom.GetId()));
return; return;
} }
@ -4142,15 +4168,17 @@ void PeerLogicValidation::ProcessMessage(
bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode) bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
{ {
const NodeId peer_id{pnode.GetId()}; const NodeId peer_id{pnode.GetId()};
PeerRef peer = GetPeerRef(peer_id);
if (peer == nullptr) return false;
{ {
LOCK(cs_main); LOCK(peer->m_misbehavior_mutex);
CNodeState& state = *State(peer_id);
// There's nothing to do if the m_should_discourage flag isn't set // There's nothing to do if the m_should_discourage flag isn't set
if (!state.m_should_discourage) return false; if (!peer->m_should_discourage) return false;
state.m_should_discourage = false; peer->m_should_discourage = false;
} // cs_main } // peer.m_misbehavior_mutex
if (pnode.HasPermission(PF_NOBAN)) { if (pnode.HasPermission(PF_NOBAN)) {
// We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag // We never disconnect or discourage peers for bad behavior if they have the NOBAN permission flag

View File

@ -11,6 +11,7 @@
#include <sync.h> #include <sync.h>
#include <validationinterface.h> #include <validationinterface.h>
class CAddrMan;
class CTxMemPool; class CTxMemPool;
class ChainstateManager; class ChainstateManager;
struct LLMQContext; struct LLMQContext;
@ -28,6 +29,7 @@ class PeerLogicValidation final : public CValidationInterface, public NetEventsI
private: private:
CConnman& m_connman; CConnman& m_connman;
BanMan* const m_banman; BanMan* const m_banman;
CAddrMan& m_addrman;
ChainstateManager& m_chainman; ChainstateManager& m_chainman;
CTxMemPool& m_mempool; CTxMemPool& m_mempool;
std::unique_ptr<LLMQContext>& m_llmq_ctx; std::unique_ptr<LLMQContext>& m_llmq_ctx;
@ -35,7 +37,7 @@ private:
bool MaybeDiscourageAndDisconnect(CNode& pnode); bool MaybeDiscourageAndDisconnect(CNode& pnode);
public: public:
PeerLogicValidation(CConnman& connman, BanMan* banman, CScheduler &scheduler, ChainstateManager& chainman, CTxMemPool& pool, PeerLogicValidation(CConnman& connman, CAddrMan& addrman, BanMan* banman, CScheduler &scheduler, ChainstateManager& chainman, CTxMemPool& pool,
std::unique_ptr<LLMQContext>& llmq_ctx); std::unique_ptr<LLMQContext>& llmq_ctx);
/** /**
@ -59,7 +61,7 @@ public:
/** Initialize a peer by adding it to mapNodeState and pushing a message requesting its version */ /** Initialize a peer by adding it to mapNodeState and pushing a message requesting its version */
void InitializeNode(CNode* pnode) override; void InitializeNode(CNode* pnode) override;
/** Handle removal of a peer by updating various state and removing it from mapNodeState */ /** Handle removal of a peer by updating various state and removing it from mapNodeState */
void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) override; void FinalizeNode(const CNode& node) override;
/** /**
* Process protocol messages received from a given node * Process protocol messages received from a given node
* *
@ -104,7 +106,7 @@ bool IsBanned(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Upstream moved this into net_processing.cpp (13417), however since we use Misbehaving in a number of dash specific // Upstream moved this into net_processing.cpp (13417), however since we use Misbehaving in a number of dash specific
// files such as mnauth.cpp and governance.cpp it makes sense to keep it in the header // files such as mnauth.cpp and governance.cpp it makes sense to keep it in the header
/** Increase a node's misbehavior score. */ /** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="") EXCLUSIVE_LOCKS_REQUIRED(cs_main); void Misbehaving(const NodeId pnode, const int howmuch, const std::string& message="");
void EraseObjectRequest(NodeId nodeId, const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void EraseObjectRequest(NodeId nodeId, const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
void RequestObject(NodeId nodeId, const CInv& inv, std::chrono::microseconds current_time, bool fForce=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main); void RequestObject(NodeId nodeId, const CInv& inv, std::chrono::microseconds current_time, bool fForce=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);

View File

@ -4,12 +4,14 @@
#include <node/context.h> #include <node/context.h>
#include <addrman.h>
#include <banman.h> #include <banman.h>
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <llmq/context.h> #include <llmq/context.h>
#include <evo/evodb.h> #include <evo/evodb.h>
#include <net.h> #include <net.h>
#include <net_processing.h> #include <net_processing.h>
#include <policy/fees.h>
#include <scheduler.h> #include <scheduler.h>
#include <txmempool.h> #include <txmempool.h>

View File

@ -12,6 +12,8 @@
class ArgsManager; class ArgsManager;
class BanMan; class BanMan;
class CAddrMan;
class CBlockPolicyEstimator;
class CConnman; class CConnman;
class CScheduler; class CScheduler;
class CTxMemPool; class CTxMemPool;
@ -36,8 +38,10 @@ class WalletClient;
//! any member functions. It should just be a collection of references that can //! any member functions. It should just be a collection of references that can
//! be used without pulling in unwanted dependencies or functionality. //! be used without pulling in unwanted dependencies or functionality.
struct NodeContext { struct NodeContext {
std::unique_ptr<CAddrMan> addrman;
std::unique_ptr<CConnman> connman; std::unique_ptr<CConnman> connman;
std::unique_ptr<CTxMemPool> mempool; std::unique_ptr<CTxMemPool> mempool;
std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
std::unique_ptr<PeerLogicValidation> peer_logic; std::unique_ptr<PeerLogicValidation> peer_logic;
ChainstateManager* chainman{nullptr}; // Currently a raw pointer because the memory is not managed by this struct ChainstateManager* chainman{nullptr}; // Currently a raw pointer because the memory is not managed by this struct
std::unique_ptr<BanMan> banman; std::unique_ptr<BanMan> banman;

View File

@ -10,6 +10,8 @@
#include <txmempool.h> #include <txmempool.h>
#include <util/system.h> #include <util/system.h>
static const char* FEE_ESTIMATES_FILENAME="fee_estimates.dat";
static constexpr double INF_FEERATE = 1e99; static constexpr double INF_FEERATE = 1e99;
std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) { std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon) {
@ -488,6 +490,7 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
{ {
static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero"); static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
size_t bucketIndex = 0; size_t bucketIndex = 0;
for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) { for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
buckets.push_back(bucketBoundary); buckets.push_back(bucketBoundary);
bucketMap[bucketBoundary] = bucketIndex; bucketMap[bucketBoundary] = bucketIndex;
@ -499,6 +502,13 @@ CBlockPolicyEstimator::CBlockPolicyEstimator()
feeStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE); feeStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE);
shortStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE); shortStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE);
longStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE); longStats = std::make_unique<TxConfirmStats>(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE);
// If the fee estimation file is present, read recorded estimations
fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Read(est_file)) {
LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", est_filepath.string());
}
} }
CBlockPolicyEstimator::~CBlockPolicyEstimator() CBlockPolicyEstimator::~CBlockPolicyEstimator()
@ -854,6 +864,15 @@ CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation
return CFeeRate(llround(median)); return CFeeRate(llround(median));
} }
void CBlockPolicyEstimator::Flush() {
FlushUnconfirmed();
fs::path est_filepath = GetDataDir() / FEE_ESTIMATES_FILENAME;
CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
if (est_file.IsNull() || !Write(est_file)) {
LogPrintf("Failed to write fee estimates to %s\n", est_filepath.string());
}
}
bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
{ {

View File

@ -222,6 +222,9 @@ public:
/** Calculation of highest target that estimates are tracked for */ /** Calculation of highest target that estimates are tracked for */
unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const; unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const;
/** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */
void Flush();
private: private:
mutable CCriticalSection m_cs_fee_estimator; mutable CCriticalSection m_cs_fee_estimator;

View File

@ -408,7 +408,13 @@ public:
READWRITE(nVersion); READWRITE(nVersion);
} }
if ((s.GetType() & SER_DISK) || if ((s.GetType() & SER_DISK) ||
(nVersion >= CADDR_TIME_VERSION && !(s.GetType() & SER_GETHASH))) { (nVersion != INIT_PROTO_VERSION && !(s.GetType() & SER_GETHASH))) {
// The only time we serialize a CAddress object without nTime is in
// the initial VERSION messages which contain two CAddress records.
// At that point, the serialization version is INIT_PROTO_VERSION.
// After the version handshake, serialization version is >=
// MIN_PEER_PROTO_VERSION and all ADDR messages are serialized with
// nTime.
READWRITE(obj.nTime); READWRITE(obj.nTime);
} }
if (nVersion & ADDRV2_FORMAT) { if (nVersion & ADDRV2_FORMAT) {

View File

@ -20,6 +20,7 @@
#include <node/coinstats.h> #include <node/coinstats.h>
#include <node/context.h> #include <node/context.h>
#include <node/utxo_snapshot.h> #include <node/utxo_snapshot.h>
#include <policy/fees.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <primitives/transaction.h> #include <primitives/transaction.h>
#include <rpc/server.h> #include <rpc/server.h>
@ -91,6 +92,15 @@ ChainstateManager& EnsureChainman(const CoreContext& context)
return *node.chainman; return *node.chainman;
} }
CBlockPolicyEstimator& EnsureFeeEstimator(const CoreContext& context)
{
NodeContext& node = EnsureNodeContext(context);
if (!node.fee_estimator) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled");
}
return *node.fee_estimator;
}
LLMQContext& EnsureLLMQContext(const CoreContext& context) LLMQContext& EnsureLLMQContext(const CoreContext& context)
{ {
NodeContext& node = EnsureNodeContext(context); NodeContext& node = EnsureNodeContext(context);

View File

@ -16,6 +16,7 @@ extern RecursiveMutex cs_main;
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CBlockPolicyEstimator;
class CTxMemPool; class CTxMemPool;
class ChainstateManager; class ChainstateManager;
class UniValue; class UniValue;
@ -55,8 +56,9 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
void CalculatePercentilesBySize(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_size); void CalculatePercentilesBySize(CAmount result[NUM_GETBLOCKSTATS_PERCENTILES], std::vector<std::pair<CAmount, int64_t>>& scores, int64_t total_size);
NodeContext& EnsureNodeContext(const CoreContext& context); NodeContext& EnsureNodeContext(const CoreContext& context);
LLMQContext& EnsureLLMQContext(const CoreContext& context);
CTxMemPool& EnsureMemPool(const CoreContext& context); CTxMemPool& EnsureMemPool(const CoreContext& context);
ChainstateManager& EnsureChainman(const CoreContext& context); ChainstateManager& EnsureChainman(const CoreContext& context);
CBlockPolicyEstimator& EnsureFeeEstimator(const CoreContext& context);
LLMQContext& EnsureLLMQContext(const CoreContext& context);
#endif #endif

View File

@ -64,7 +64,7 @@ static UniValue coinjoin(const JSONRPCRequest& request)
const NodeContext& node = EnsureNodeContext(request.context); const NodeContext& node = EnsureNodeContext(request.context);
CTxMemPool& mempool = EnsureMemPool(request.context); CTxMemPool& mempool = EnsureMemPool(request.context);
bool result = it->second->DoAutomaticDenominating(mempool, *node.connman); bool result = it->second->DoAutomaticDenominating(*node.connman, *node.fee_estimator, mempool);
return "Mixing " + (result ? "started successfully" : ("start failed: " + it->second->GetStatuses().original + ", will retry")); return "Mixing " + (result ? "started successfully" : ("start failed: " + it->second->GetStatuses().original + ", will retry"));
} }

View File

@ -1096,7 +1096,10 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
RPCTypeCheckArgument(request.params[0], UniValue::VNUM); RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
bool conservative = true; bool conservative = true;
if (!request.params[1].isNull()) { if (!request.params[1].isNull()) {
@ -1110,7 +1113,7 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
UniValue errors(UniValue::VARR); UniValue errors(UniValue::VARR);
FeeCalculation feeCalc; FeeCalculation feeCalc;
CFeeRate feeRate = ::feeEstimator.estimateSmartFee(conf_target, &feeCalc, conservative); CFeeRate feeRate = fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative);
if (feeRate != CFeeRate(0)) { if (feeRate != CFeeRate(0)) {
result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK())); result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
} else { } else {
@ -1178,7 +1181,10 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
RPCTypeCheckArgument(request.params[0], UniValue::VNUM); RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
unsigned int max_target = ::feeEstimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
CBlockPolicyEstimator& fee_estimator = EnsureFeeEstimator(request.context);
unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target); unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
double threshold = 0.95; double threshold = 0.95;
if (!request.params[1].isNull()) { if (!request.params[1].isNull()) {
@ -1195,9 +1201,9 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
EstimationResult buckets; EstimationResult buckets;
// Only output results for horizons which track the target // Only output results for horizons which track the target
if (conf_target > ::feeEstimator.HighestTargetTracked(horizon)) continue; if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue;
feeRate = ::feeEstimator.estimateRawFee(conf_target, threshold, horizon, &buckets); feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
UniValue horizon_result(UniValue::VOBJ); UniValue horizon_result(UniValue::VOBJ);
UniValue errors(UniValue::VARR); UniValue errors(UniValue::VARR);
UniValue passbucket(UniValue::VOBJ); UniValue passbucket(UniValue::VOBJ);

View File

@ -130,7 +130,6 @@ void CSporkManager::ProcessSpork(const CNode& peer, CConnman& connman, CDataStre
} }
if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) { if (spork.nTimeSigned > GetAdjustedTime() + 2 * 60 * 60) {
LOCK(cs_main);
LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: too far into the future\n"); LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: too far into the future\n");
Misbehaving(peer.GetId(), 100); Misbehaving(peer.GetId(), 100);
return; return;
@ -139,7 +138,6 @@ void CSporkManager::ProcessSpork(const CNode& peer, CConnman& connman, CDataStre
auto opt_keyIDSigner = spork.GetSignerKeyID(); auto opt_keyIDSigner = spork.GetSignerKeyID();
if (opt_keyIDSigner == std::nullopt || WITH_LOCK(cs, return !setSporkPubKeyIDs.count(*opt_keyIDSigner))) { if (opt_keyIDSigner == std::nullopt || WITH_LOCK(cs, return !setSporkPubKeyIDs.count(*opt_keyIDSigner))) {
LOCK(cs_main);
LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: invalid signature\n"); LogPrint(BCLog::SPORK, "CSporkManager::ProcessSpork -- ERROR: invalid signature\n");
Misbehaving(peer.GetId(), 100); Misbehaving(peer.GetId(), 100);
return; return;

View File

@ -80,9 +80,9 @@ BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
// work. // work.
BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction) BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
{ {
auto connman = std::make_unique<CConnman>(0x1337, 0x1337); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = std::make_unique<PeerLogicValidation>( auto peerLogic = std::make_unique<PeerLogicValidation>(
*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *connman, *m_node.addrman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
// Mock an outbound peer // Mock an outbound peer
@ -133,8 +133,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
BOOST_CHECK(dummyNode1.fDisconnect == true); BOOST_CHECK(dummyNode1.fDisconnect == true);
SetMockTime(0); SetMockTime(0);
bool dummy; peerLogic->FinalizeNode(dummyNode1);
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
} }
static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman) static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman)
@ -153,9 +152,9 @@ static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidat
BOOST_AUTO_TEST_CASE(stale_tip_peer_management) BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
{ {
auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337); auto connman = std::make_unique<CConnmanTest>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = std::make_unique<PeerLogicValidation>( auto peerLogic = std::make_unique<PeerLogicValidation>(
*connman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *connman, *m_node.addrman, nullptr, *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
const Consensus::Params& consensusParams = Params().GetConsensus(); const Consensus::Params& consensusParams = Params().GetConsensus();
@ -217,9 +216,8 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true); BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
BOOST_CHECK(vNodes.back()->fDisconnect == false); BOOST_CHECK(vNodes.back()->fDisconnect == false);
bool dummy;
for (const CNode *node : vNodes) { for (const CNode *node : vNodes) {
peerLogic->FinalizeNode(node->GetId(), dummy); peerLogic->FinalizeNode(*node);
} }
connman->ClearNodes(); connman->ClearNodes();
@ -228,9 +226,9 @@ BOOST_AUTO_TEST_CASE(stale_tip_peer_management)
BOOST_AUTO_TEST_CASE(DoS_banning) BOOST_AUTO_TEST_CASE(DoS_banning)
{ {
auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(0x1337, 0x1337); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = std::make_unique<PeerLogicValidation>( auto peerLogic = std::make_unique<PeerLogicValidation>(
*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
banman->ClearBanned(); banman->ClearBanned();
@ -240,10 +238,7 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
peerLogic->InitializeNode(&dummyNode1); peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1; dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true; dummyNode1.fSuccessfullyConnected = true;
{ Misbehaving(dummyNode1.GetId(), 100); // Should get banned
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 100); // Should get banned
}
{ {
LOCK(dummyNode1.cs_sendProcessing); LOCK(dummyNode1.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode1)); BOOST_CHECK(peerLogic->SendMessages(&dummyNode1));
@ -257,37 +252,30 @@ BOOST_AUTO_TEST_CASE(DoS_banning)
peerLogic->InitializeNode(&dummyNode2); peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1; dummyNode2.nVersion = 1;
dummyNode2.fSuccessfullyConnected = true; dummyNode2.fSuccessfullyConnected = true;
{ Misbehaving(dummyNode2.GetId(), 50);
LOCK(cs_main);
Misbehaving(dummyNode2.GetId(), 50);
}
{ {
LOCK(dummyNode2.cs_sendProcessing); LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2)); BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
} }
BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not banned yet... BOOST_CHECK(!banman->IsDiscouraged(addr2)); // 2 not banned yet...
BOOST_CHECK(banman->IsDiscouraged(addr1)); // ... but 1 still should be BOOST_CHECK(banman->IsDiscouraged(addr1)); // ... but 1 still should be
{ Misbehaving(dummyNode2.GetId(), 50);
LOCK(cs_main);
Misbehaving(dummyNode2.GetId(), 50);
}
{ {
LOCK(dummyNode2.cs_sendProcessing); LOCK(dummyNode2.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode2)); BOOST_CHECK(peerLogic->SendMessages(&dummyNode2));
} }
BOOST_CHECK(banman->IsDiscouraged(addr2)); BOOST_CHECK(banman->IsDiscouraged(addr2));
bool dummy; peerLogic->FinalizeNode(dummyNode1);
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy); peerLogic->FinalizeNode(dummyNode2);
peerLogic->FinalizeNode(dummyNode2.GetId(), dummy);
} }
BOOST_AUTO_TEST_CASE(DoS_banscore) BOOST_AUTO_TEST_CASE(DoS_banscore)
{ {
auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(0x1337, 0x1337); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = std::make_unique<PeerLogicValidation>( auto peerLogic = std::make_unique<PeerLogicValidation>(
*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
banman->ClearBanned(); banman->ClearBanned();
@ -299,7 +287,6 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
dummyNode1.nVersion = 1; dummyNode1.nVersion = 1;
dummyNode1.fSuccessfullyConnected = true; dummyNode1.fSuccessfullyConnected = true;
{ {
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 100); Misbehaving(dummyNode1.GetId(), 100);
} }
{ {
@ -308,7 +295,6 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
} }
BOOST_CHECK(!banman->IsDiscouraged(addr1)); BOOST_CHECK(!banman->IsDiscouraged(addr1));
{ {
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 10); Misbehaving(dummyNode1.GetId(), 10);
} }
{ {
@ -317,7 +303,6 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
} }
BOOST_CHECK(!banman->IsDiscouraged(addr1)); BOOST_CHECK(!banman->IsDiscouraged(addr1));
{ {
LOCK(cs_main);
Misbehaving(dummyNode1.GetId(), 1); Misbehaving(dummyNode1.GetId(), 1);
} }
{ {
@ -327,16 +312,15 @@ BOOST_AUTO_TEST_CASE(DoS_banscore)
BOOST_CHECK(banman->IsDiscouraged(addr1)); BOOST_CHECK(banman->IsDiscouraged(addr1));
gArgs.ForceSetArg("-banscore", ToString(DEFAULT_BANSCORE_THRESHOLD)); gArgs.ForceSetArg("-banscore", ToString(DEFAULT_BANSCORE_THRESHOLD));
bool dummy; peerLogic->FinalizeNode(dummyNode1);
peerLogic->FinalizeNode(dummyNode1.GetId(), dummy);
} }
BOOST_AUTO_TEST_CASE(DoS_bantime) BOOST_AUTO_TEST_CASE(DoS_bantime)
{ {
auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); auto banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
auto connman = std::make_unique<CConnman>(0x1337, 0x1337); auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
auto peerLogic = std::make_unique<PeerLogicValidation>( auto peerLogic = std::make_unique<PeerLogicValidation>(
*connman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *connman, *m_node.addrman, banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
banman->ClearBanned(); banman->ClearBanned();
@ -350,18 +334,14 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
dummyNode.nVersion = 1; dummyNode.nVersion = 1;
dummyNode.fSuccessfullyConnected = true; dummyNode.fSuccessfullyConnected = true;
{ Misbehaving(dummyNode.GetId(), 100);
LOCK(cs_main);
Misbehaving(dummyNode.GetId(), 100);
}
{ {
LOCK(dummyNode.cs_sendProcessing); LOCK(dummyNode.cs_sendProcessing);
BOOST_CHECK(peerLogic->SendMessages(&dummyNode)); BOOST_CHECK(peerLogic->SendMessages(&dummyNode));
} }
BOOST_CHECK(banman->IsDiscouraged(addr)); BOOST_CHECK(banman->IsDiscouraged(addr));
bool dummy; peerLogic->FinalizeNode(dummyNode);
peerLogic->FinalizeNode(dummyNode.GetId(), dummy);
} }
static CTransactionRef RandomOrphan() static CTransactionRef RandomOrphan()

View File

@ -23,116 +23,94 @@ void initialize_connman()
FUZZ_TARGET_INIT(connman, initialize_connman) FUZZ_TARGET_INIT(connman, initialize_connman)
{ {
FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; CAddrMan addrman;
CAddress random_address; CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman};
CNetAddr random_netaddr; CNetAddr random_netaddr;
CNode random_node = ConsumeNode(fuzzed_data_provider); CNode random_node = ConsumeNode(fuzzed_data_provider);
CService random_service;
CSubNet random_subnet; CSubNet random_subnet;
std::string random_string; std::string random_string;
while (fuzzed_data_provider.ConsumeBool()) { while (fuzzed_data_provider.ConsumeBool()) {
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 28)) { switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 23)) {
case 0: case 0:
random_address = ConsumeAddress(fuzzed_data_provider);
break;
case 1:
random_netaddr = ConsumeNetAddr(fuzzed_data_provider); random_netaddr = ConsumeNetAddr(fuzzed_data_provider);
break; break;
case 2: case 1:
random_service = ConsumeService(fuzzed_data_provider);
break;
case 3:
random_subnet = ConsumeSubNet(fuzzed_data_provider); random_subnet = ConsumeSubNet(fuzzed_data_provider);
break; break;
case 4: case 2:
random_string = fuzzed_data_provider.ConsumeRandomLengthString(64); random_string = fuzzed_data_provider.ConsumeRandomLengthString(64);
break; break;
case 5: { case 3:
std::vector<CAddress> addresses;
while (fuzzed_data_provider.ConsumeBool()) {
addresses.push_back(ConsumeAddress(fuzzed_data_provider));
}
// Limit nTimePenalty to int32_t to avoid signed integer overflow
(void)connman.AddNewAddresses(addresses, ConsumeAddress(fuzzed_data_provider), fuzzed_data_provider.ConsumeIntegral<int32_t>());
break;
}
case 6:
connman.AddNode(random_string); connman.AddNode(random_string);
break; break;
case 7: case 4:
connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); connman.CheckIncomingNonce(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
break; break;
case 8: case 5:
connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>()); connman.DisconnectNode(fuzzed_data_provider.ConsumeIntegral<NodeId>());
break; break;
case 9: case 6:
connman.DisconnectNode(random_netaddr); connman.DisconnectNode(random_netaddr);
break; break;
case 10: case 7:
connman.DisconnectNode(random_string); connman.DisconnectNode(random_string);
break; break;
case 11: case 8:
connman.DisconnectNode(random_subnet); connman.DisconnectNode(random_subnet);
break; break;
case 12: case 9:
connman.ForEachNode([](auto) {}); connman.ForEachNode([](auto) {});
break; break;
case 13: case 10:
connman.ForEachNodeThen([](auto) {}, []() {}); connman.ForEachNodeThen([](auto) {}, []() {});
break; break;
case 14: case 11:
(void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); }); (void)connman.ForNode(fuzzed_data_provider.ConsumeIntegral<NodeId>(), [&](auto) { return fuzzed_data_provider.ConsumeBool(); });
break; break;
case 15: case 12:
(void)connman.GetAddresses(); (void)connman.GetAddresses();
break; break;
case 16: { case 13: {
(void)connman.GetAddresses(); (void)connman.GetAddresses();
break; break;
} }
case 17: case 14:
(void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); (void)connman.GetDeterministicRandomizer(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
break; break;
case 18: case 15:
(void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL})); (void)connman.GetNodeCount(fuzzed_data_provider.PickValueInArray({CConnman::CONNECTIONS_NONE, CConnman::CONNECTIONS_IN, CConnman::CONNECTIONS_OUT, CConnman::CONNECTIONS_ALL}));
break; break;
case 19: case 16:
connman.MarkAddressGood(random_address);
break;
case 20:
(void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool()); (void)connman.OutboundTargetReached(fuzzed_data_provider.ConsumeBool());
break; break;
case 21: case 17:
// Limit now to int32_t to avoid signed integer overflow // Limit now to int32_t to avoid signed integer overflow
(void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>()); (void)connman.PoissonNextSendInbound(fuzzed_data_provider.ConsumeIntegral<int32_t>(), fuzzed_data_provider.ConsumeIntegral<int>());
break; break;
case 22: { case 18: {
CSerializedNetMsg serialized_net_msg; CSerializedNetMsg serialized_net_msg;
serialized_net_msg.command = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE); serialized_net_msg.command = fuzzed_data_provider.ConsumeRandomLengthString(CMessageHeader::COMMAND_SIZE);
serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider); serialized_net_msg.data = ConsumeRandomLengthByteVector(fuzzed_data_provider);
connman.PushMessage(&random_node, std::move(serialized_net_msg)); connman.PushMessage(&random_node, std::move(serialized_net_msg));
break; break;
} }
case 23: case 19:
connman.RemoveAddedNode(random_string); connman.RemoveAddedNode(random_string);
break; break;
case 24: { case 20: {
const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider); const std::vector<bool> asmap = ConsumeRandomLengthBitVector(fuzzed_data_provider);
if (SanityCheckASMap(asmap)) { if (SanityCheckASMap(asmap)) {
connman.SetAsmap(asmap); connman.SetAsmap(asmap);
} }
break; break;
} }
case 25: case 21:
connman.SetBestHeight(fuzzed_data_provider.ConsumeIntegral<int>()); connman.SetBestHeight(fuzzed_data_provider.ConsumeIntegral<int>());
break; break;
case 26: case 22:
connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool()); connman.SetNetworkActive(fuzzed_data_provider.ConsumeBool());
break; break;
case 27: case 23:
connman.SetServices(random_service, static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()));
break;
case 28:
connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool()); connman.SetTryNewOutboundPeer(fuzzed_data_provider.ConsumeBool());
break; break;
} }

View File

@ -52,7 +52,8 @@ FUZZ_TARGET_INIT(net, initialize_net)
while (fuzzed_data_provider.ConsumeBool()) { while (fuzzed_data_provider.ConsumeBool()) {
switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 12)) { switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 12)) {
case 0: { case 0: {
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>()}; CAddrMan addrman;
CConnman connman{fuzzed_data_provider.ConsumeIntegral<uint64_t>(), fuzzed_data_provider.ConsumeIntegral<uint64_t>(), addrman};
node.CloseSocketDisconnect(&connman); node.CloseSocketDisconnect(&connman);
break; break;
} }

View File

@ -4,6 +4,7 @@
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <addrman.h>
#include <banman.h> #include <banman.h>
#include <chainparams.h> #include <chainparams.h>
#include <consensus/consensus.h> #include <consensus/consensus.h>
@ -28,6 +29,7 @@
#include <net.h> #include <net.h>
#include <net_processing.h> #include <net_processing.h>
#include <noui.h> #include <noui.h>
#include <policy/fees.h>
#include <pow.h> #include <pow.h>
#include <rpc/blockchain.h> #include <rpc/blockchain.h>
#include <rpc/register.h> #include <rpc/register.h>
@ -130,11 +132,12 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve
SetupNetworking(); SetupNetworking();
InitSignatureCache(); InitSignatureCache();
InitScriptExecutionCache(); InitScriptExecutionCache();
m_node.addrman = std::make_unique<CAddrMan>();
m_node.chain = interfaces::MakeChain(m_node); m_node.chain = interfaces::MakeChain(m_node);
g_wallet_init_interface.Construct(m_node); g_wallet_init_interface.Construct(m_node);
fCheckBlockIndex = true; fCheckBlockIndex = true;
m_node.evodb = std::make_unique<CEvoDB>(1 << 20, true, true); m_node.evodb = std::make_unique<CEvoDB>(1 << 20, true, true);
connman = std::make_unique<CConnman>(0x1337, 0x1337); connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman);
deterministicMNManager.reset(new CDeterministicMNManager(*m_node.evodb, *connman)); deterministicMNManager.reset(new CDeterministicMNManager(*m_node.evodb, *connman));
llmq::quorumSnapshotManager.reset(new llmq::CQuorumSnapshotManager(*m_node.evodb)); llmq::quorumSnapshotManager.reset(new llmq::CQuorumSnapshotManager(*m_node.evodb));
static bool noui_connected = false; static bool noui_connected = false;
@ -169,12 +172,12 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve
pblocktree.reset(new CBlockTreeDB(1 << 20, true)); pblocktree.reset(new CBlockTreeDB(1 << 20, true));
m_node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); m_node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
m_node.mempool->setSanityCheck(1.0); m_node.mempool = std::make_unique<CTxMemPool>(m_node.fee_estimator.get(), 1);
m_node.chainman = &::g_chainman; m_node.chainman = &::g_chainman;
m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests. m_node.connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman); // Deterministic randomness for tests.
::sporkManager = std::make_unique<CSporkManager>(); ::sporkManager = std::make_unique<CSporkManager>();
::governance = std::make_unique<CGovernanceManager>(); ::governance = std::make_unique<CGovernanceManager>();
@ -210,10 +213,11 @@ ChainTestingSetup::~ChainTestingSetup()
::governance.reset(); ::governance.reset();
::sporkManager.reset(); ::sporkManager.reset();
m_node.connman.reset(); m_node.connman.reset();
m_node.addrman.reset();
m_node.args = nullptr;
m_node.banman.reset(); m_node.banman.reset();
UnloadBlockIndex(m_node.mempool.get()); UnloadBlockIndex(m_node.mempool.get());
m_node.mempool.reset(); m_node.mempool.reset();
m_node.args = nullptr;
m_node.scheduler.reset(); m_node.scheduler.reset();
m_node.llmq_ctx.reset(); m_node.llmq_ctx.reset();
m_node.chainman->Reset(); m_node.chainman->Reset();
@ -241,7 +245,7 @@ TestingSetup::TestingSetup(const std::string& chainName, const std::vector<const
m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME); m_node.banman = std::make_unique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
m_node.peer_logic = std::make_unique<PeerLogicValidation>( m_node.peer_logic = std::make_unique<PeerLogicValidation>(
*m_node.connman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx *m_node.connman, *m_node.addrman, m_node.banman.get(), *m_node.scheduler, *m_node.chainman, *m_node.mempool, m_node.llmq_ctx
); );
{ {
CConnman::Options options; CConnman::Options options;

View File

@ -334,15 +334,10 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
assert(int(nSigOpCountWithAncestors) >= 0); assert(int(nSigOpCountWithAncestors) >= 0);
} }
CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator) CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator, int check_ratio)
: nTransactionsUpdated(0), minerPolicyEstimator(estimator), m_epoch(0), m_has_epoch_guard(false) : m_check_ratio(check_ratio), minerPolicyEstimator(estimator)
{ {
_clear(); //lock free clear _clear(); //lock free clear
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
nCheckFrequency = 0;
} }
bool CTxMemPool::isSpent(const COutPoint& outpoint) const bool CTxMemPool::isSpent(const COutPoint& outpoint) const
@ -776,7 +771,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem
if (it2 != mapTx.end()) if (it2 != mapTx.end())
continue; continue;
const Coin &coin = pcoins->AccessCoin(txin.prevout); const Coin &coin = pcoins->AccessCoin(txin.prevout);
if (nCheckFrequency != 0) assert(!coin.IsSpent()); if (m_check_ratio != 0) assert(!coin.IsSpent());
if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) { if (coin.IsSpent() || (coin.IsCoinBase() && ((signed long)nMemPoolHeight) - coin.nHeight < COINBASE_MATURITY)) {
txToRemove.insert(it); txToRemove.insert(it);
break; break;
@ -1035,13 +1030,11 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
void CTxMemPool::check(const CCoinsViewCache *pcoins) const void CTxMemPool::check(const CCoinsViewCache *pcoins) const
{ {
if (m_check_ratio == 0) return;
if (GetRand(m_check_ratio) >= 1) return;
LOCK(cs); LOCK(cs);
if (nCheckFrequency == 0)
return;
if (GetRand(std::numeric_limits<uint32_t>::max()) >= nCheckFrequency)
return;
LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size()); LogPrint(BCLog::MEMPOOL, "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
uint64_t checkTotal = 0; uint64_t checkTotal = 0;

View File

@ -449,8 +449,8 @@ public:
class CTxMemPool class CTxMemPool
{ {
private: private:
uint32_t nCheckFrequency GUARDED_BY(cs); //!< Value n means that n times in 2^32 we check. const int m_check_ratio; //!< Value n means that 1 times in n we check.
std::atomic<unsigned int> nTransactionsUpdated; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
CBlockPolicyEstimator* minerPolicyEstimator; CBlockPolicyEstimator* minerPolicyEstimator;
uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes uint64_t totalTxSize; //!< sum of all mempool tx' byte sizes
@ -459,8 +459,8 @@ private:
mutable int64_t lastRollingFeeUpdate; mutable int64_t lastRollingFeeUpdate;
mutable bool blockSinceLastRollingFeeBump; mutable bool blockSinceLastRollingFeeBump;
mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially mutable double rollingMinimumFeeRate; //!< minimum fee to get into the pool, decreases exponentially
mutable uint64_t m_epoch; mutable uint64_t m_epoch{0};
mutable bool m_has_epoch_guard; mutable bool m_has_epoch_guard{false};
void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs); void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
@ -581,8 +581,14 @@ public:
std::map<uint256, CAmount> mapDeltas; std::map<uint256, CAmount> mapDeltas;
/** Create a new CTxMemPool. /** Create a new CTxMemPool.
* Sanity checks will be off by default for performance, because otherwise
* accepting transactions becomes O(N^2) where N is the number of transactions
* in the pool.
*
* @param[in] estimator is used to estimate appropriate transaction fees.
* @param[in] check_ratio is the ratio used to determine how often sanity checks will run.
*/ */
explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr); explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr, int check_ratio = 0);
/** /**
* If sanity-checking is turned on, check makes sure the pool is * If sanity-checking is turned on, check makes sure the pool is
@ -591,7 +597,6 @@ public:
* check does nothing. * check does nothing.
*/ */
void check(const CCoinsViewCache *pcoins) const; void check(const CCoinsViewCache *pcoins) const;
void setSanityCheck(double dFrequency = 1.0) { LOCK(cs); nCheckFrequency = static_cast<uint32_t>(dFrequency * 4294967295.0); }
// addUnchecked must updated state for all ancestors of a given transaction, // addUnchecked must updated state for all ancestors of a given transaction,
// to track size/count of descendant transactions. First version of // to track size/count of descendant transactions. First version of

View File

@ -21,7 +21,6 @@
#include <index/txindex.h> #include <index/txindex.h>
#include <logging.h> #include <logging.h>
#include <logging/timer.h> #include <logging/timer.h>
#include <policy/fees.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <policy/settings.h> #include <policy/settings.h>
#include <pow.h> #include <pow.h>
@ -154,8 +153,6 @@ arith_uint256 nMinimumChainWork;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CBlockPolicyEstimator feeEstimator;
// Internal stuff // Internal stuff
namespace { namespace {
CBlockIndex* pindexBestInvalid = nullptr; CBlockIndex* pindexBestInvalid = nullptr;

View File

@ -50,7 +50,6 @@ class CChainParams;
class CInv; class CInv;
class CConnman; class CConnman;
class CScriptCheck; class CScriptCheck;
class CBlockPolicyEstimator;
class CTxMemPool; class CTxMemPool;
class CValidationState; class CValidationState;
class ChainstateManager; class ChainstateManager;
@ -128,7 +127,6 @@ struct BlockHasher
}; };
extern CCriticalSection cs_main; extern CCriticalSection cs_main;
extern CBlockPolicyEstimator feeEstimator;
typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap; typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
typedef std::unordered_multimap<uint256, CBlockIndex*, BlockHasher> PrevBlockMap; typedef std::unordered_multimap<uint256, CBlockIndex*, BlockHasher> PrevBlockMap;
extern Mutex g_best_block_mutex; extern Mutex g_best_block_mutex;

View File

@ -22,10 +22,6 @@ static const int MIN_PEER_PROTO_VERSION = 70215;
//! minimum proto version of masternode to accept in DKGs //! minimum proto version of masternode to accept in DKGs
static const int MIN_MASTERNODE_PROTO_VERSION = 70221; static const int MIN_MASTERNODE_PROTO_VERSION = 70221;
//! nTime field added to CAddress, starting with this version;
//! if possible, avoid requesting addresses nodes older than this
static const int CADDR_TIME_VERSION = 31402;
//! protocol version is included in MNAUTH starting with this version //! protocol version is included in MNAUTH starting with this version
static const int MNAUTH_NODE_VER_VERSION = 70218; static const int MNAUTH_NODE_VER_VERSION = 70218;

View File

@ -129,7 +129,8 @@ public:
CTransactionBuilderTestSetup() CTransactionBuilderTestSetup()
{ {
CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()));
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
chain = interfaces::MakeChain(node); chain = interfaces::MakeChain(node);
wallet = std::make_unique<CWallet>(chain.get(), "", CreateMockWalletDatabase()); wallet = std::make_unique<CWallet>(chain.get(), "", CreateMockWalletDatabase());
bool firstRun; bool firstRun;
@ -229,7 +230,7 @@ BOOST_FIXTURE_TEST_CASE(CTransactionBuilderTest, CTransactionBuilderTestSetup)
// Tests with single outpoint tallyItem // Tests with single outpoint tallyItem
{ {
CompactTallyItem tallyItem = GetTallyItem({4999}); CompactTallyItem tallyItem = GetTallyItem({4999});
CTransactionBuilder txBuilder(wallet, tallyItem); CTransactionBuilder txBuilder(wallet, tallyItem, *m_node.fee_estimator);
BOOST_CHECK_EQUAL(txBuilder.CountOutputs(), 0); BOOST_CHECK_EQUAL(txBuilder.CountOutputs(), 0);
BOOST_CHECK_EQUAL(txBuilder.GetAmountInitial(), tallyItem.nAmount); BOOST_CHECK_EQUAL(txBuilder.GetAmountInitial(), tallyItem.nAmount);
@ -266,7 +267,7 @@ BOOST_FIXTURE_TEST_CASE(CTransactionBuilderTest, CTransactionBuilderTestSetup)
// Tests with multiple outpoint tallyItem // Tests with multiple outpoint tallyItem
{ {
CompactTallyItem tallyItem = GetTallyItem({10000, 20000, 30000, 40000, 50000}); CompactTallyItem tallyItem = GetTallyItem({10000, 20000, 30000, 40000, 50000});
CTransactionBuilder txBuilder(wallet, tallyItem); CTransactionBuilder txBuilder(wallet, tallyItem, *m_node.fee_estimator);
std::vector<CTransactionBuilderOutput*> vecOutputs; std::vector<CTransactionBuilderOutput*> vecOutputs;
bilingual_str strResult; bilingual_str strResult;

View File

@ -88,7 +88,8 @@ BOOST_FIXTURE_TEST_CASE(scan_for_wallet_transactions, TestChain100Setup)
CBlockIndex* newTip = ::ChainActive().Tip(); CBlockIndex* newTip = ::ChainActive().Tip();
NodeContext node; NodeContext node;
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
// Verify ScanForWalletTransactions accommodates a null start block. // Verify ScanForWalletTransactions accommodates a null start block.
@ -189,7 +190,8 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
CBlockIndex* newTip = ::ChainActive().Tip(); CBlockIndex* newTip = ::ChainActive().Tip();
NodeContext node; NodeContext node;
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
// Prune the older block file. // Prune the older block file.
@ -260,7 +262,8 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); m_coinbase_txns.emplace_back(CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
NodeContext node; NodeContext node;
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
std::string backup_file = (GetDataDir() / "wallet.backup").string(); std::string backup_file = (GetDataDir() / "wallet.backup").string();
@ -393,7 +396,8 @@ BOOST_FIXTURE_TEST_CASE(rpc_getaddressinfo, TestChain100Setup)
BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(coin_mark_dirty_immature_credit, TestChain100Setup)
{ {
NodeContext node; NodeContext node;
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase()); CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
@ -1123,7 +1127,8 @@ BOOST_FIXTURE_TEST_CASE(select_coins_grouped_by_addresses, ListCoinsTestingSetup
BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(wallet_disableprivkeys, TestChain100Setup)
{ {
NodeContext node; NodeContext node;
node.mempool = std::make_unique<CTxMemPool>(&::feeEstimator); node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get());
auto chain = interfaces::MakeChain(node); auto chain = interfaces::MakeChain(node);
std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase()); std::shared_ptr<CWallet> wallet = std::make_shared<CWallet>(chain.get(), "", CreateDummyWalletDatabase());
wallet->SetMinVersion(FEATURE_LATEST); wallet->SetMinVersion(FEATURE_LATEST);

View File

@ -13,6 +13,7 @@ from test_framework.util import (
assert_equal, assert_equal,
assert_greater_than, assert_greater_than,
assert_greater_than_or_equal, assert_greater_than_or_equal,
assert_raises_rpc_error,
satoshi_round, satoshi_round,
) )
@ -259,5 +260,11 @@ class EstimateFeeTest(BitcoinTestFramework):
self.log.info("Final estimates after emptying mempools") self.log.info("Final estimates after emptying mempools")
check_estimates(self.nodes[1], self.fees_per_kb) check_estimates(self.nodes[1], self.fees_per_kb)
self.log.info("Testing that fee estimation is disabled in blocksonly.")
self.restart_node(0, ["-blocksonly"])
assert_raises_rpc_error(-32603, "Fee estimation disabled",
self.nodes[0].estimatesmartfee, 2)
if __name__ == '__main__': if __name__ == '__main__':
EstimateFeeTest().main() EstimateFeeTest().main()

View File

@ -255,7 +255,7 @@ class CAddress:
self.ip = "0.0.0.0" self.ip = "0.0.0.0"
self.port = 0 self.port = 0
def deserialize(self, f, with_time=True): def deserialize(self, f, *, with_time=True):
"""Deserialize from addrv1 format (pre-BIP155)""" """Deserialize from addrv1 format (pre-BIP155)"""
if with_time: if with_time:
# VERSION messages serialize CAddress objects without time # VERSION messages serialize CAddress objects without time
@ -267,7 +267,7 @@ class CAddress:
self.ip = socket.inet_ntoa(f.read(4)) self.ip = socket.inet_ntoa(f.read(4))
self.port = struct.unpack(">H", f.read(2))[0] self.port = struct.unpack(">H", f.read(2))[0]
def serialize(self, with_time=True): def serialize(self, *, with_time=True):
"""Serialize in addrv1 format (pre-BIP155)""" """Serialize in addrv1 format (pre-BIP155)"""
assert self.net == self.NET_IPV4 assert self.net == self.NET_IPV4
r = b"" r = b""
@ -1371,10 +1371,10 @@ class msg_version:
self.nServices = struct.unpack("<Q", f.read(8))[0] self.nServices = struct.unpack("<Q", f.read(8))[0]
self.nTime = struct.unpack("<q", f.read(8))[0] self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress() self.addrTo = CAddress()
self.addrTo.deserialize(f, False) self.addrTo.deserialize(f, with_time=False)
self.addrFrom = CAddress() self.addrFrom = CAddress()
self.addrFrom.deserialize(f, False) self.addrFrom.deserialize(f, with_time=False)
self.nNonce = struct.unpack("<Q", f.read(8))[0] self.nNonce = struct.unpack("<Q", f.read(8))[0]
self.strSubVer = deser_string(f) self.strSubVer = deser_string(f)
@ -1394,8 +1394,8 @@ class msg_version:
r += struct.pack("<i", self.nVersion) r += struct.pack("<i", self.nVersion)
r += struct.pack("<Q", self.nServices) r += struct.pack("<Q", self.nServices)
r += struct.pack("<q", self.nTime) r += struct.pack("<q", self.nTime)
r += self.addrTo.serialize(False) r += self.addrTo.serialize(with_time=False)
r += self.addrFrom.serialize(False) r += self.addrFrom.serialize(with_time=False)
r += struct.pack("<Q", self.nNonce) r += struct.pack("<Q", self.nNonce)
r += ser_string(self.strSubVer) r += ser_string(self.strSubVer)
r += struct.pack("<i", self.nStartingHeight) r += struct.pack("<i", self.nStartingHeight)

View File

@ -75,7 +75,6 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
"llmq/chainlocks -> validation -> llmq/chainlocks" "llmq/chainlocks -> validation -> llmq/chainlocks"
"coinjoin/coinjoin -> llmq/chainlocks -> net -> coinjoin/coinjoin" "coinjoin/coinjoin -> llmq/chainlocks -> net -> coinjoin/coinjoin"
"evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns" "evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns"
"policy/fees -> txmempool -> validation -> policy/fees"
"policy/policy -> policy/settings -> policy/policy" "policy/policy -> policy/settings -> policy/policy"
"evo/specialtxman -> validation -> evo/specialtxman" "evo/specialtxman -> validation -> evo/specialtxman"