Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 1,612 Lines • ▼ Show 20 Lines | if (send && pindex->nStatus.hasData()) { | ||||
} | } | ||||
if (inv.type == MSG_BLOCK) { | if (inv.type == MSG_BLOCK) { | ||||
connman->PushMessage(pfrom, | connman->PushMessage(pfrom, | ||||
msgMaker.Make(NetMsgType::BLOCK, *pblock)); | msgMaker.Make(NetMsgType::BLOCK, *pblock)); | ||||
} else if (inv.type == MSG_FILTERED_BLOCK) { | } else if (inv.type == MSG_FILTERED_BLOCK) { | ||||
bool sendMerkleBlock = false; | bool sendMerkleBlock = false; | ||||
CMerkleBlock merkleBlock; | CMerkleBlock merkleBlock; | ||||
{ | { | ||||
LOCK(pfrom->m_tx_relay.cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
if (pfrom->m_tx_relay.pfilter) { | if (pfrom->m_tx_relay->pfilter) { | ||||
sendMerkleBlock = true; | sendMerkleBlock = true; | ||||
merkleBlock = | merkleBlock = | ||||
CMerkleBlock(*pblock, *pfrom->m_tx_relay.pfilter); | CMerkleBlock(*pblock, *pfrom->m_tx_relay->pfilter); | ||||
} | } | ||||
} | } | ||||
if (sendMerkleBlock) { | if (sendMerkleBlock) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); | pfrom, msgMaker.Make(NetMsgType::MERKLEBLOCK, merkleBlock)); | ||||
// CMerkleBlock just contains hashes, so also push any | // CMerkleBlock just contains hashes, so also push any | ||||
// transactions in the block the client did not see. This avoids | // transactions in the block the client did not see. This avoids | ||||
// hurting performance by pointlessly requiring a round-trip. | // hurting performance by pointlessly requiring a round-trip. | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); | ||||
bool push = false; | bool push = false; | ||||
auto mi = mapRelay.find(inv.hash); | auto mi = mapRelay.find(inv.hash); | ||||
int nSendFlags = 0; | int nSendFlags = 0; | ||||
if (mi != mapRelay.end()) { | if (mi != mapRelay.end()) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second)); | ||||
push = true; | push = true; | ||||
} else if (pfrom->m_tx_relay.timeLastMempoolReq) { | } else if (pfrom->m_tx_relay->timeLastMempoolReq) { | ||||
auto txinfo = g_mempool.info(TxId(inv.hash)); | auto txinfo = g_mempool.info(TxId(inv.hash)); | ||||
// To protect privacy, do not answer getdata using the mempool | // To protect privacy, do not answer getdata using the mempool | ||||
// when that TX couldn't have been INVed in reply to a MEMPOOL | // when that TX couldn't have been INVed in reply to a MEMPOOL | ||||
// request. | // request. | ||||
if (txinfo.tx && | if (txinfo.tx && | ||||
txinfo.nTime <= pfrom->m_tx_relay.timeLastMempoolReq) { | txinfo.nTime <= pfrom->m_tx_relay->timeLastMempoolReq) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pfrom, | pfrom, | ||||
msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx)); | ||||
push = true; | push = true; | ||||
} | } | ||||
} | } | ||||
if (!push) { | if (!push) { | ||||
vNotFound.push_back(inv); | vNotFound.push_back(inv); | ||||
▲ Show 20 Lines • Show All 577 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::VERSION) { | ||||
!(nServices & NODE_NETWORK_LIMITED)); | !(nServices & NODE_NETWORK_LIMITED)); | ||||
// set nodes not capable of serving the complete blockchain history as | // set nodes not capable of serving the complete blockchain history as | ||||
// "limited nodes" | // "limited nodes" | ||||
pfrom->m_limited_node = | pfrom->m_limited_node = | ||||
(!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED)); | (!(nServices & NODE_NETWORK) && (nServices & NODE_NETWORK_LIMITED)); | ||||
{ | { | ||||
LOCK(pfrom->m_tx_relay.cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
// set to true after we get the first filter* message | // set to true after we get the first filter* message | ||||
pfrom->m_tx_relay.fRelayTxes = fRelay; | pfrom->m_tx_relay->fRelayTxes = fRelay; | ||||
} | } | ||||
// Change version | // Change version | ||||
pfrom->SetSendVersion(nSendVersion); | pfrom->SetSendVersion(nSendVersion); | ||||
pfrom->nVersion = nVersion; | pfrom->nVersion = nVersion; | ||||
// Potentially mark this peer as a preferred download peer. | // Potentially mark this peer as a preferred download peer. | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 1,262 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::MEMPOOL) { | ||||
"mempool request with bandwidth limit reached, " | "mempool request with bandwidth limit reached, " | ||||
"disconnect peer=%d\n", | "disconnect peer=%d\n", | ||||
pfrom->GetId()); | pfrom->GetId()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
LOCK(pfrom->m_tx_relay.cs_tx_inventory); | LOCK(pfrom->m_tx_relay->cs_tx_inventory); | ||||
pfrom->m_tx_relay.fSendMempool = true; | pfrom->m_tx_relay->fSendMempool = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::PING) { | if (strCommand == NetMsgType::PING) { | ||||
if (pfrom->nVersion > BIP0031_VERSION) { | if (pfrom->nVersion > BIP0031_VERSION) { | ||||
uint64_t nonce = 0; | uint64_t nonce = 0; | ||||
vRecv >> nonce; | vRecv >> nonce; | ||||
// Echo the message back with the nonce. This allows for two useful | // Echo the message back with the nonce. This allows for two useful | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::FILTERLOAD) { | ||||
CBloomFilter filter; | CBloomFilter filter; | ||||
vRecv >> filter; | vRecv >> filter; | ||||
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); | LOCK(cs_main); | ||||
Misbehaving(pfrom, 100, "oversized-bloom-filter"); | Misbehaving(pfrom, 100, "oversized-bloom-filter"); | ||||
} else { | } else { | ||||
LOCK(pfrom->m_tx_relay.cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
pfrom->m_tx_relay.pfilter.reset(new CBloomFilter(filter)); | pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter)); | ||||
pfrom->m_tx_relay.pfilter->UpdateEmptyFull(); | pfrom->m_tx_relay->pfilter->UpdateEmptyFull(); | ||||
pfrom->m_tx_relay.fRelayTxes = true; | pfrom->m_tx_relay->fRelayTxes = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FILTERADD) { | if (strCommand == NetMsgType::FILTERADD) { | ||||
std::vector<uint8_t> vData; | std::vector<uint8_t> vData; | ||||
vRecv >> vData; | vRecv >> vData; | ||||
// Nodes must NEVER send a data item > 520 bytes (the max size for a | // Nodes must NEVER send a data item > 520 bytes (the max size for a | ||||
// script data object, and thus, the maximum size any matched object can | // script data object, and thus, the maximum size any matched object can | ||||
// have) in a filteradd message. | // have) in a filteradd message. | ||||
bool bad = false; | bool bad = false; | ||||
if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { | if (vData.size() > MAX_SCRIPT_ELEMENT_SIZE) { | ||||
bad = true; | bad = true; | ||||
} else { | } else { | ||||
LOCK(pfrom->m_tx_relay.cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
if (pfrom->m_tx_relay.pfilter) { | if (pfrom->m_tx_relay->pfilter) { | ||||
pfrom->m_tx_relay.pfilter->insert(vData); | pfrom->m_tx_relay->pfilter->insert(vData); | ||||
} else { | } else { | ||||
bad = true; | bad = true; | ||||
} | } | ||||
} | } | ||||
if (bad) { | if (bad) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// The structure of this code doesn't really allow for a good error | // The structure of this code doesn't really allow for a good error | ||||
// code. We'll go generic. | // code. We'll go generic. | ||||
Misbehaving(pfrom, 100, "invalid-filteradd"); | Misbehaving(pfrom, 100, "invalid-filteradd"); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FILTERCLEAR) { | if (strCommand == NetMsgType::FILTERCLEAR) { | ||||
LOCK(pfrom->m_tx_relay.cs_filter); | LOCK(pfrom->m_tx_relay->cs_filter); | ||||
if (pfrom->GetLocalServices() & NODE_BLOOM) { | if (pfrom->GetLocalServices() & NODE_BLOOM) { | ||||
pfrom->m_tx_relay.pfilter.reset(new CBloomFilter()); | pfrom->m_tx_relay->pfilter.reset(new CBloomFilter()); | ||||
} | } | ||||
pfrom->m_tx_relay.fRelayTxes = true; | pfrom->m_tx_relay->fRelayTxes = true; | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::FEEFILTER) { | if (strCommand == NetMsgType::FEEFILTER) { | ||||
Amount newFeeFilter = Amount::zero(); | Amount newFeeFilter = Amount::zero(); | ||||
vRecv >> newFeeFilter; | vRecv >> newFeeFilter; | ||||
if (MoneyRange(newFeeFilter)) { | if (MoneyRange(newFeeFilter)) { | ||||
{ | { | ||||
LOCK(pfrom->m_tx_relay.cs_feeFilter); | LOCK(pfrom->m_tx_relay->cs_feeFilter); | ||||
pfrom->m_tx_relay.minFeeFilter = newFeeFilter; | pfrom->m_tx_relay->minFeeFilter = newFeeFilter; | ||||
} | } | ||||
LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", | LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", | ||||
CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); | CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
if (strCommand == NetMsgType::NOTFOUND) { | if (strCommand == NetMsgType::NOTFOUND) { | ||||
▲ Show 20 Lines • Show All 763 Lines • ▼ Show 20 Lines | std::vector<CInv> vInv; | ||||
vInv.push_back(CInv(MSG_BLOCK, hash)); | vInv.push_back(CInv(MSG_BLOCK, hash)); | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
} | } | ||||
pto->vInventoryBlockToSend.clear(); | pto->vInventoryBlockToSend.clear(); | ||||
LOCK(pto->m_tx_relay.cs_tx_inventory); | LOCK(pto->m_tx_relay->cs_tx_inventory); | ||||
// Check whether periodic sends should happen | // Check whether periodic sends should happen | ||||
bool fSendTrickle = pto->HasPermission(PF_NOBAN); | bool fSendTrickle = pto->HasPermission(PF_NOBAN); | ||||
if (pto->m_tx_relay.nNextInvSend < nNow) { | if (pto->m_tx_relay->nNextInvSend < nNow) { | ||||
fSendTrickle = true; | fSendTrickle = true; | ||||
if (pto->fInbound) { | if (pto->fInbound) { | ||||
pto->m_tx_relay.nNextInvSend = connman->PoissonNextSendInbound( | pto->m_tx_relay->nNextInvSend = connman->PoissonNextSendInbound( | ||||
nNow, INVENTORY_BROADCAST_INTERVAL); | nNow, INVENTORY_BROADCAST_INTERVAL); | ||||
} else { | } else { | ||||
// Use half the delay for outbound peers, as there is less | // Use half the delay for outbound peers, as there is less | ||||
// privacy concern for them. | // privacy concern for them. | ||||
pto->m_tx_relay.nNextInvSend = | pto->m_tx_relay->nNextInvSend = | ||||
PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1); | PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1); | ||||
} | } | ||||
} | } | ||||
// Time to send but the peer has requested we not relay transactions. | // Time to send but the peer has requested we not relay transactions. | ||||
if (fSendTrickle) { | if (fSendTrickle) { | ||||
LOCK(pto->m_tx_relay.cs_filter); | LOCK(pto->m_tx_relay->cs_filter); | ||||
if (!pto->m_tx_relay.fRelayTxes) { | if (!pto->m_tx_relay->fRelayTxes) { | ||||
pto->m_tx_relay.setInventoryTxToSend.clear(); | pto->m_tx_relay->setInventoryTxToSend.clear(); | ||||
} | } | ||||
} | } | ||||
// Respond to BIP35 mempool requests | // Respond to BIP35 mempool requests | ||||
if (fSendTrickle && pto->m_tx_relay.fSendMempool) { | if (fSendTrickle && pto->m_tx_relay->fSendMempool) { | ||||
auto vtxinfo = g_mempool.infoAll(); | auto vtxinfo = g_mempool.infoAll(); | ||||
pto->m_tx_relay.fSendMempool = false; | pto->m_tx_relay->fSendMempool = false; | ||||
Amount filterrate = Amount::zero(); | Amount filterrate = Amount::zero(); | ||||
{ | { | ||||
LOCK(pto->m_tx_relay.cs_feeFilter); | LOCK(pto->m_tx_relay->cs_feeFilter); | ||||
filterrate = pto->m_tx_relay.minFeeFilter; | filterrate = pto->m_tx_relay->minFeeFilter; | ||||
} | } | ||||
LOCK(pto->m_tx_relay.cs_filter); | LOCK(pto->m_tx_relay->cs_filter); | ||||
for (const auto &txinfo : vtxinfo) { | for (const auto &txinfo : vtxinfo) { | ||||
const TxId &txid = txinfo.tx->GetId(); | const TxId &txid = txinfo.tx->GetId(); | ||||
CInv inv(MSG_TX, txid); | CInv inv(MSG_TX, txid); | ||||
pto->m_tx_relay.setInventoryTxToSend.erase(txid); | pto->m_tx_relay->setInventoryTxToSend.erase(txid); | ||||
if (filterrate != Amount::zero() && | if (filterrate != Amount::zero() && | ||||
txinfo.feeRate.GetFeePerK() < filterrate) { | txinfo.feeRate.GetFeePerK() < filterrate) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->m_tx_relay.pfilter && | if (pto->m_tx_relay->pfilter && | ||||
!pto->m_tx_relay.pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | !pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | ||||
*txinfo.tx)) { | |||||
continue; | continue; | ||||
} | } | ||||
pto->m_tx_relay.filterInventoryKnown.insert(txid); | pto->m_tx_relay->filterInventoryKnown.insert(txid); | ||||
vInv.push_back(inv); | vInv.push_back(inv); | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
connman->PushMessage(pto, | connman->PushMessage(pto, | ||||
msgMaker.Make(NetMsgType::INV, vInv)); | msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
} | } | ||||
pto->m_tx_relay.timeLastMempoolReq = GetTime(); | pto->m_tx_relay->timeLastMempoolReq = GetTime(); | ||||
} | } | ||||
// Determine transactions to relay | // Determine transactions to relay | ||||
if (fSendTrickle) { | if (fSendTrickle) { | ||||
// Produce a vector with all candidates for sending | // Produce a vector with all candidates for sending | ||||
std::vector<std::set<TxId>::iterator> vInvTx; | std::vector<std::set<TxId>::iterator> vInvTx; | ||||
vInvTx.reserve(pto->m_tx_relay.setInventoryTxToSend.size()); | vInvTx.reserve(pto->m_tx_relay->setInventoryTxToSend.size()); | ||||
for (std::set<TxId>::iterator it = | for (std::set<TxId>::iterator it = | ||||
pto->m_tx_relay.setInventoryTxToSend.begin(); | pto->m_tx_relay->setInventoryTxToSend.begin(); | ||||
it != pto->m_tx_relay.setInventoryTxToSend.end(); it++) { | it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) { | ||||
vInvTx.push_back(it); | vInvTx.push_back(it); | ||||
} | } | ||||
Amount filterrate = Amount::zero(); | Amount filterrate = Amount::zero(); | ||||
{ | { | ||||
LOCK(pto->m_tx_relay.cs_feeFilter); | LOCK(pto->m_tx_relay->cs_feeFilter); | ||||
filterrate = pto->m_tx_relay.minFeeFilter; | filterrate = pto->m_tx_relay->minFeeFilter; | ||||
} | } | ||||
// Topologically and fee-rate sort the inventory we send for privacy | // Topologically and fee-rate sort the inventory we send for privacy | ||||
// and priority reasons. A heap is used so that not all items need | // and priority reasons. A heap is used so that not all items need | ||||
// sorting if only a few are being sent. | // sorting if only a few are being sent. | ||||
CompareInvMempoolOrder compareInvMempoolOrder(&g_mempool); | CompareInvMempoolOrder compareInvMempoolOrder(&g_mempool); | ||||
std::make_heap(vInvTx.begin(), vInvTx.end(), | std::make_heap(vInvTx.begin(), vInvTx.end(), | ||||
compareInvMempoolOrder); | compareInvMempoolOrder); | ||||
// No reason to drain out at many times the network's capacity, | // No reason to drain out at many times the network's capacity, | ||||
// especially since we have many peers and some will draw much | // especially since we have many peers and some will draw much | ||||
// shorter delays. | // shorter delays. | ||||
unsigned int nRelayedTransactions = 0; | unsigned int nRelayedTransactions = 0; | ||||
LOCK(pto->m_tx_relay.cs_filter); | LOCK(pto->m_tx_relay->cs_filter); | ||||
while (!vInvTx.empty() && | while (!vInvTx.empty() && | ||||
nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | nRelayedTransactions < INVENTORY_BROADCAST_MAX_PER_MB * | ||||
config.GetMaxBlockSize() / | config.GetMaxBlockSize() / | ||||
1000000) { | 1000000) { | ||||
// Fetch the top element from the heap | // Fetch the top element from the heap | ||||
std::pop_heap(vInvTx.begin(), vInvTx.end(), | std::pop_heap(vInvTx.begin(), vInvTx.end(), | ||||
compareInvMempoolOrder); | compareInvMempoolOrder); | ||||
std::set<TxId>::iterator it = vInvTx.back(); | std::set<TxId>::iterator it = vInvTx.back(); | ||||
vInvTx.pop_back(); | vInvTx.pop_back(); | ||||
const TxId txid = *it; | const TxId txid = *it; | ||||
// Remove it from the to-be-sent set | // Remove it from the to-be-sent set | ||||
pto->m_tx_relay.setInventoryTxToSend.erase(it); | pto->m_tx_relay->setInventoryTxToSend.erase(it); | ||||
// Check if not in the filter already | // Check if not in the filter already | ||||
if (pto->m_tx_relay.filterInventoryKnown.contains(txid)) { | if (pto->m_tx_relay->filterInventoryKnown.contains(txid)) { | ||||
continue; | continue; | ||||
} | } | ||||
// Not in the mempool anymore? don't bother sending it. | // Not in the mempool anymore? don't bother sending it. | ||||
auto txinfo = g_mempool.info(txid); | auto txinfo = g_mempool.info(txid); | ||||
if (!txinfo.tx) { | if (!txinfo.tx) { | ||||
continue; | continue; | ||||
} | } | ||||
if (filterrate != Amount::zero() && | if (filterrate != Amount::zero() && | ||||
txinfo.feeRate.GetFeePerK() < filterrate) { | txinfo.feeRate.GetFeePerK() < filterrate) { | ||||
continue; | continue; | ||||
} | } | ||||
if (pto->m_tx_relay.pfilter && | if (pto->m_tx_relay->pfilter && | ||||
!pto->m_tx_relay.pfilter->IsRelevantAndUpdate(*txinfo.tx)) { | !pto->m_tx_relay->pfilter->IsRelevantAndUpdate( | ||||
*txinfo.tx)) { | |||||
continue; | continue; | ||||
} | } | ||||
// Send | // Send | ||||
vInv.push_back(CInv(MSG_TX, txid)); | vInv.push_back(CInv(MSG_TX, txid)); | ||||
nRelayedTransactions++; | nRelayedTransactions++; | ||||
{ | { | ||||
// Expire old relay messages | // Expire old relay messages | ||||
while (!vRelayExpiration.empty() && | while (!vRelayExpiration.empty() && | ||||
Show All 9 Lines | std::vector<CInv> vInv; | ||||
nNow + 15 * 60 * 1000000, ret.first)); | nNow + 15 * 60 * 1000000, ret.first)); | ||||
} | } | ||||
} | } | ||||
if (vInv.size() == MAX_INV_SZ) { | if (vInv.size() == MAX_INV_SZ) { | ||||
connman->PushMessage(pto, | connman->PushMessage(pto, | ||||
msgMaker.Make(NetMsgType::INV, vInv)); | msgMaker.Make(NetMsgType::INV, vInv)); | ||||
vInv.clear(); | vInv.clear(); | ||||
} | } | ||||
pto->m_tx_relay.filterInventoryKnown.insert(txid); | pto->m_tx_relay->filterInventoryKnown.insert(txid); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!vInv.empty()) { | if (!vInv.empty()) { | ||||
connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | connman->PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
} | } | ||||
// Detect whether we're stalling | // Detect whether we're stalling | ||||
▲ Show 20 Lines • Show All 191 Lines • ▼ Show 20 Lines | if (pto->nVersion >= FEEFILTER_VERSION && | ||||
!pto->HasPermission(PF_FORCERELAY)) { | !pto->HasPermission(PF_FORCERELAY)) { | ||||
Amount currentFilter = | Amount currentFilter = | ||||
g_mempool | g_mempool | ||||
.GetMinFee( | .GetMinFee( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFeePerK(); | .GetFeePerK(); | ||||
int64_t timeNow = GetTimeMicros(); | int64_t timeNow = GetTimeMicros(); | ||||
if (timeNow > pto->m_tx_relay.nextSendTimeFeeFilter) { | if (timeNow > pto->m_tx_relay->nextSendTimeFeeFilter) { | ||||
static CFeeRate default_feerate = | static CFeeRate default_feerate = | ||||
CFeeRate(DEFAULT_MIN_RELAY_TX_FEE_PER_KB); | CFeeRate(DEFAULT_MIN_RELAY_TX_FEE_PER_KB); | ||||
static FeeFilterRounder filterRounder(default_feerate); | static FeeFilterRounder filterRounder(default_feerate); | ||||
Amount filterToSend = filterRounder.round(currentFilter); | Amount filterToSend = filterRounder.round(currentFilter); | ||||
filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); | filterToSend = std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); | ||||
if (filterToSend != pto->m_tx_relay.lastSentFeeFilter) { | if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) { | ||||
connman->PushMessage( | connman->PushMessage( | ||||
pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); | pto, msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); | ||||
pto->m_tx_relay.lastSentFeeFilter = filterToSend; | pto->m_tx_relay->lastSentFeeFilter = filterToSend; | ||||
} | } | ||||
pto->m_tx_relay.nextSendTimeFeeFilter = | pto->m_tx_relay->nextSendTimeFeeFilter = | ||||
PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); | PoissonNextSend(timeNow, AVG_FEEFILTER_BROADCAST_INTERVAL); | ||||
} | } | ||||
// If the fee filter has changed substantially and it's still more than | // If the fee filter has changed substantially and it's still more than | ||||
// MAX_FEEFILTER_CHANGE_DELAY until scheduled broadcast, then move the | // MAX_FEEFILTER_CHANGE_DELAY until scheduled broadcast, then move the | ||||
// broadcast to within MAX_FEEFILTER_CHANGE_DELAY. | // broadcast to within MAX_FEEFILTER_CHANGE_DELAY. | ||||
else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < | else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < | ||||
pto->m_tx_relay.nextSendTimeFeeFilter && | pto->m_tx_relay->nextSendTimeFeeFilter && | ||||
(currentFilter < 3 * pto->m_tx_relay.lastSentFeeFilter / 4 || | (currentFilter < 3 * pto->m_tx_relay->lastSentFeeFilter / 4 || | ||||
currentFilter > 4 * pto->m_tx_relay.lastSentFeeFilter / 3)) { | currentFilter > 4 * pto->m_tx_relay->lastSentFeeFilter / 3)) { | ||||
pto->m_tx_relay.nextSendTimeFeeFilter = | pto->m_tx_relay->nextSendTimeFeeFilter = | ||||
timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; | timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; | ||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
class CNetProcessingCleanup { | class CNetProcessingCleanup { | ||||
public: | public: | ||||
CNetProcessingCleanup() {} | CNetProcessingCleanup() {} | ||||
~CNetProcessingCleanup() { | ~CNetProcessingCleanup() { | ||||
// orphan transactions | // orphan transactions | ||||
mapOrphanTransactions.clear(); | mapOrphanTransactions.clear(); | ||||
mapOrphanTransactionsByPrev.clear(); | mapOrphanTransactionsByPrev.clear(); | ||||
} | } | ||||
} instance_of_cnetprocessingcleanup; | } instance_of_cnetprocessingcleanup; |