Skip to content

Commit e75c39c

Browse files
committed
Check that tx_relay is initialized before access
1 parent c4aa2ba commit e75c39c

File tree

3 files changed

+133
-116
lines changed

3 files changed

+133
-116
lines changed

src/net.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,11 @@ void CNode::copyStats(CNodeStats &stats)
499499
X(nServices);
500500
X(addr);
501501
X(addrBind);
502-
{
502+
if (m_tx_relay != nullptr) {
503503
LOCK(m_tx_relay->cs_filter);
504504
stats.fRelayTxes = m_tx_relay->fRelayTxes;
505+
} else {
506+
stats.fRelayTxes = false;
505507
}
506508
X(nLastSend);
507509
X(nLastRecv);
@@ -528,9 +530,11 @@ void CNode::copyStats(CNodeStats &stats)
528530
}
529531
X(m_legacyWhitelisted);
530532
X(m_permissionFlags);
531-
{
533+
if (m_tx_relay != nullptr) {
532534
LOCK(m_tx_relay->cs_feeFilter);
533535
stats.minFeeFilter = m_tx_relay->minFeeFilter;
536+
} else {
537+
stats.minFeeFilter = 0;
534538
}
535539

536540
// It is common for nodes with good ping times to suddenly become lagged,
@@ -818,11 +822,17 @@ bool CConnman::AttemptToEvictConnection()
818822
continue;
819823
if (node->fDisconnect)
820824
continue;
821-
LOCK(node->m_tx_relay->cs_filter);
825+
bool peer_relay_txes = false;
826+
bool peer_filter_not_null = false;
827+
if (node->m_tx_relay != nullptr) {
828+
LOCK(node->m_tx_relay->cs_filter);
829+
peer_relay_txes = node->m_tx_relay->fRelayTxes;
830+
peer_filter_not_null = node->m_tx_relay->pfilter != nullptr;
831+
}
822832
NodeEvictionCandidate candidate = {node->GetId(), node->nTimeConnected, node->nMinPingUsecTime,
823833
node->nLastBlockTime, node->nLastTXTime,
824834
HasAllDesirableServiceFlags(node->nServices),
825-
node->m_tx_relay->fRelayTxes, node->m_tx_relay->pfilter != nullptr, node->addr, node->nKeyedNetGroup,
835+
peer_relay_txes, peer_filter_not_null, node->addr, node->nKeyedNetGroup,
826836
node->m_prefer_evict};
827837
vEvictionCandidates.push_back(candidate);
828838
}

src/net.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,15 +848,15 @@ class CNode
848848

849849
void AddInventoryKnown(const CInv& inv)
850850
{
851-
{
851+
if (m_tx_relay != nullptr) {
852852
LOCK(m_tx_relay->cs_tx_inventory);
853853
m_tx_relay->filterInventoryKnown.insert(inv.hash);
854854
}
855855
}
856856

857857
void PushInventory(const CInv& inv)
858858
{
859-
if (inv.type == MSG_TX) {
859+
if (inv.type == MSG_TX && m_tx_relay != nullptr) {
860860
LOCK(m_tx_relay->cs_tx_inventory);
861861
if (!m_tx_relay->filterInventoryKnown.contains(inv.hash)) {
862862
m_tx_relay->setInventoryTxToSend.insert(inv.hash);

src/net_processing.cpp

Lines changed: 117 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
14481448
{
14491449
bool sendMerkleBlock = false;
14501450
CMerkleBlock merkleBlock;
1451-
{
1451+
if (pfrom->m_tx_relay != nullptr) {
14521452
LOCK(pfrom->m_tx_relay->cs_filter);
14531453
if (pfrom->m_tx_relay->pfilter) {
14541454
sendMerkleBlock = true;
@@ -1512,7 +1512,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
15121512
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
15131513
std::vector<CInv> vNotFound;
15141514
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
1515-
{
1515+
if (pfrom->m_tx_relay != nullptr) {
15161516
LOCK(cs_main);
15171517

15181518
while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
@@ -1995,7 +1995,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
19951995
// set nodes not capable of serving the complete blockchain history as "limited nodes"
19961996
pfrom->m_limited_node = (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED));
19971997

1998-
{
1998+
if (pfrom->m_tx_relay != nullptr) {
19991999
LOCK(pfrom->m_tx_relay->cs_filter);
20002000
pfrom->m_tx_relay->fRelayTxes = fRelay; // set to true after we get the first filter* message
20012001
}
@@ -3030,8 +3030,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
30303030
return true;
30313031
}
30323032

3033-
LOCK(pfrom->m_tx_relay->cs_tx_inventory);
3034-
pfrom->m_tx_relay->fSendMempool = true;
3033+
if (pfrom->m_tx_relay != nullptr) {
3034+
LOCK(pfrom->m_tx_relay->cs_tx_inventory);
3035+
pfrom->m_tx_relay->fSendMempool = true;
3036+
}
30353037
return true;
30363038
}
30373039

@@ -3122,7 +3124,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
31223124
LOCK(cs_main);
31233125
Misbehaving(pfrom->GetId(), 100);
31243126
}
3125-
else
3127+
else if (pfrom->m_tx_relay != nullptr)
31263128
{
31273129
LOCK(pfrom->m_tx_relay->cs_filter);
31283130
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter));
@@ -3141,7 +3143,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
31413143
bool bad = false;
31423144
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) {
31433145
bad = true;
3144-
} else {
3146+
} else if (pfrom->m_tx_relay != nullptr) {
31453147
LOCK(pfrom->m_tx_relay->cs_filter);
31463148
if (pfrom->m_tx_relay->pfilter) {
31473149
pfrom->m_tx_relay->pfilter->insert(vData);
@@ -3157,6 +3159,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
31573159
}
31583160

31593161
if (strCommand == NetMsgType::FILTERCLEAR) {
3162+
if (pfrom->m_tx_relay == nullptr) {
3163+
return true;
3164+
}
31603165
LOCK(pfrom->m_tx_relay->cs_filter);
31613166
if (pfrom->GetLocalServices() & NODE_BLOOM) {
31623167
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter());
@@ -3169,7 +3174,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
31693174
CAmount newFeeFilter = 0;
31703175
vRecv >> newFeeFilter;
31713176
if (MoneyRange(newFeeFilter)) {
3172-
{
3177+
if (pfrom->m_tx_relay != nullptr) {
31733178
LOCK(pfrom->m_tx_relay->cs_feeFilter);
31743179
pfrom->m_tx_relay->minFeeFilter = newFeeFilter;
31753180
}
@@ -3791,121 +3796,123 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
37913796
}
37923797
pto->vInventoryBlockToSend.clear();
37933798

3794-
LOCK(pto->m_tx_relay->cs_tx_inventory);
3795-
// Check whether periodic sends should happen
3796-
bool fSendTrickle = pto->HasPermission(PF_NOBAN);
3797-
if (pto->m_tx_relay->nNextInvSend < nNow) {
3798-
fSendTrickle = true;
3799-
if (pto->fInbound) {
3800-
pto->m_tx_relay->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL);
3801-
} else {
3802-
// Use half the delay for outbound peers, as there is less privacy concern for them.
3803-
pto->m_tx_relay->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1);
3799+
if (pto->m_tx_relay != nullptr) {
3800+
LOCK(pto->m_tx_relay->cs_tx_inventory);
3801+
// Check whether periodic sends should happen
3802+
bool fSendTrickle = pto->HasPermission(PF_NOBAN);
3803+
if (pto->m_tx_relay->nNextInvSend < nNow) {
3804+
fSendTrickle = true;
3805+
if (pto->fInbound) {
3806+
pto->m_tx_relay->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL);
3807+
} else {
3808+
// Use half the delay for outbound peers, as there is less privacy concern for them.
3809+
pto->m_tx_relay->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1);
3810+
}
38043811
}
3805-
}
3806-
3807-
// Time to send but the peer has requested we not relay transactions.
3808-
if (fSendTrickle) {
3809-
LOCK(pto->m_tx_relay->cs_filter);
3810-
if (!pto->m_tx_relay->fRelayTxes) pto->m_tx_relay->setInventoryTxToSend.clear();
3811-
}
38123812

3813-
// Respond to BIP35 mempool requests
3814-
if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
3815-
auto vtxinfo = mempool.infoAll();
3816-
pto->m_tx_relay->fSendMempool = false;
3817-
CAmount filterrate = 0;
3818-
{
3819-
LOCK(pto->m_tx_relay->cs_feeFilter);
3820-
filterrate = pto->m_tx_relay->minFeeFilter;
3813+
// Time to send but the peer has requested we not relay transactions.
3814+
if (fSendTrickle) {
3815+
LOCK(pto->m_tx_relay->cs_filter);
3816+
if (!pto->m_tx_relay->fRelayTxes) pto->m_tx_relay->setInventoryTxToSend.clear();
38213817
}
38223818

3823-
LOCK(pto->m_tx_relay->cs_filter);
3824-
3825-
for (const auto& txinfo : vtxinfo) {
3826-
const uint256& hash = txinfo.tx->GetHash();
3827-
CInv inv(MSG_TX, hash);
3828-
pto->m_tx_relay->setInventoryTxToSend.erase(hash);
3829-
if (filterrate) {
3830-
if (txinfo.feeRate.GetFeePerK() < filterrate)
3831-
continue;
3832-
}
3833-
if (pto->m_tx_relay->pfilter) {
3834-
if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
3819+
// Respond to BIP35 mempool requests
3820+
if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
3821+
auto vtxinfo = mempool.infoAll();
3822+
pto->m_tx_relay->fSendMempool = false;
3823+
CAmount filterrate = 0;
3824+
{
3825+
LOCK(pto->m_tx_relay->cs_feeFilter);
3826+
filterrate = pto->m_tx_relay->minFeeFilter;
38353827
}
3836-
pto->m_tx_relay->filterInventoryKnown.insert(hash);
3837-
vInv.push_back(inv);
3838-
if (vInv.size() == MAX_INV_SZ) {
3839-
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
3840-
vInv.clear();
3828+
3829+
LOCK(pto->m_tx_relay->cs_filter);
3830+
3831+
for (const auto& txinfo : vtxinfo) {
3832+
const uint256& hash = txinfo.tx->GetHash();
3833+
CInv inv(MSG_TX, hash);
3834+
pto->m_tx_relay->setInventoryTxToSend.erase(hash);
3835+
if (filterrate) {
3836+
if (txinfo.feeRate.GetFeePerK() < filterrate)
3837+
continue;
3838+
}
3839+
if (pto->m_tx_relay->pfilter) {
3840+
if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
3841+
}
3842+
pto->m_tx_relay->filterInventoryKnown.insert(hash);
3843+
vInv.push_back(inv);
3844+
if (vInv.size() == MAX_INV_SZ) {
3845+
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
3846+
vInv.clear();
3847+
}
38413848
}
3849+
pto->m_tx_relay->timeLastMempoolReq = GetTime();
38423850
}
3843-
pto->m_tx_relay->timeLastMempoolReq = GetTime();
3844-
}
38453851

3846-
// Determine transactions to relay
3847-
if (fSendTrickle) {
3848-
// Produce a vector with all candidates for sending
3849-
std::vector<std::set<uint256>::iterator> vInvTx;
3850-
vInvTx.reserve(pto->m_tx_relay->setInventoryTxToSend.size());
3851-
for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
3852-
vInvTx.push_back(it);
3853-
}
3854-
CAmount filterrate = 0;
3855-
{
3856-
LOCK(pto->m_tx_relay->cs_feeFilter);
3857-
filterrate = pto->m_tx_relay->minFeeFilter;
3858-
}
3859-
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
3860-
// A heap is used so that not all items need sorting if only a few are being sent.
3861-
CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
3862-
std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
3863-
// No reason to drain out at many times the network's capacity,
3864-
// especially since we have many peers and some will draw much shorter delays.
3865-
unsigned int nRelayedTransactions = 0;
3866-
LOCK(pto->m_tx_relay->cs_filter);
3867-
while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
3868-
// Fetch the top element from the heap
3869-
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
3870-
std::set<uint256>::iterator it = vInvTx.back();
3871-
vInvTx.pop_back();
3872-
uint256 hash = *it;
3873-
// Remove it from the to-be-sent set
3874-
pto->m_tx_relay->setInventoryTxToSend.erase(it);
3875-
// Check if not in the filter already
3876-
if (pto->m_tx_relay->filterInventoryKnown.contains(hash)) {
3877-
continue;
3878-
}
3879-
// Not in the mempool anymore? don't bother sending it.
3880-
auto txinfo = mempool.info(hash);
3881-
if (!txinfo.tx) {
3882-
continue;
3852+
// Determine transactions to relay
3853+
if (fSendTrickle) {
3854+
// Produce a vector with all candidates for sending
3855+
std::vector<std::set<uint256>::iterator> vInvTx;
3856+
vInvTx.reserve(pto->m_tx_relay->setInventoryTxToSend.size());
3857+
for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
3858+
vInvTx.push_back(it);
38833859
}
3884-
if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
3885-
continue;
3886-
}
3887-
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
3888-
// Send
3889-
vInv.push_back(CInv(MSG_TX, hash));
3890-
nRelayedTransactions++;
3860+
CAmount filterrate = 0;
38913861
{
3892-
// Expire old relay messages
3893-
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
3894-
{
3895-
mapRelay.erase(vRelayExpiration.front().second);
3896-
vRelayExpiration.pop_front();
3862+
LOCK(pto->m_tx_relay->cs_feeFilter);
3863+
filterrate = pto->m_tx_relay->minFeeFilter;
3864+
}
3865+
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
3866+
// A heap is used so that not all items need sorting if only a few are being sent.
3867+
CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
3868+
std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
3869+
// No reason to drain out at many times the network's capacity,
3870+
// especially since we have many peers and some will draw much shorter delays.
3871+
unsigned int nRelayedTransactions = 0;
3872+
LOCK(pto->m_tx_relay->cs_filter);
3873+
while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
3874+
// Fetch the top element from the heap
3875+
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
3876+
std::set<uint256>::iterator it = vInvTx.back();
3877+
vInvTx.pop_back();
3878+
uint256 hash = *it;
3879+
// Remove it from the to-be-sent set
3880+
pto->m_tx_relay->setInventoryTxToSend.erase(it);
3881+
// Check if not in the filter already
3882+
if (pto->m_tx_relay->filterInventoryKnown.contains(hash)) {
3883+
continue;
3884+
}
3885+
// Not in the mempool anymore? don't bother sending it.
3886+
auto txinfo = mempool.info(hash);
3887+
if (!txinfo.tx) {
3888+
continue;
3889+
}
3890+
if (filterrate && txinfo.feeRate.GetFeePerK() < filterrate) {
3891+
continue;
38973892
}
3893+
if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
3894+
// Send
3895+
vInv.push_back(CInv(MSG_TX, hash));
3896+
nRelayedTransactions++;
3897+
{
3898+
// Expire old relay messages
3899+
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < nNow)
3900+
{
3901+
mapRelay.erase(vRelayExpiration.front().second);
3902+
vRelayExpiration.pop_front();
3903+
}
38983904

3899-
auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
3900-
if (ret.second) {
3901-
vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
3905+
auto ret = mapRelay.insert(std::make_pair(hash, std::move(txinfo.tx)));
3906+
if (ret.second) {
3907+
vRelayExpiration.push_back(std::make_pair(nNow + 15 * 60 * 1000000, ret.first));
3908+
}
39023909
}
3910+
if (vInv.size() == MAX_INV_SZ) {
3911+
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
3912+
vInv.clear();
3913+
}
3914+
pto->m_tx_relay->filterInventoryKnown.insert(hash);
39033915
}
3904-
if (vInv.size() == MAX_INV_SZ) {
3905-
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv));
3906-
vInv.clear();
3907-
}
3908-
pto->m_tx_relay->filterInventoryKnown.insert(hash);
39093916
}
39103917
}
39113918
}
@@ -4066,7 +4073,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
40664073
// Message: feefilter
40674074
//
40684075
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
4069-
if (pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
4076+
if (pto->m_tx_relay != nullptr && pto->nVersion >= FEEFILTER_VERSION && gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
40704077
!pto->HasPermission(PF_FORCERELAY)) {
40714078
CAmount currentFilter = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
40724079
int64_t timeNow = GetTimeMicros();

0 commit comments

Comments
 (0)