Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 684 Lines • ▼ Show 20 Lines | if (itInFlight != mapBlocksInFlight.end()) { | ||||
if (state->nBlocksInFlightValidHeaders == 0 && | if (state->nBlocksInFlightValidHeaders == 0 && | ||||
itInFlight->second.second->fValidatedHeaders) { | itInFlight->second.second->fValidatedHeaders) { | ||||
// Last validated block on the queue was received. | // Last validated block on the queue was received. | ||||
nPeersWithValidatedDownloads--; | nPeersWithValidatedDownloads--; | ||||
} | } | ||||
if (state->vBlocksInFlight.begin() == itInFlight->second.second) { | if (state->vBlocksInFlight.begin() == itInFlight->second.second) { | ||||
// First block on the queue was received, update the start download | // First block on the queue was received, update the start download | ||||
// time for the next one | // time for the next one | ||||
state->nDownloadingSince = | state->nDownloadingSince = std::max( | ||||
std::max(state->nDownloadingSince, GetTimeMicros()); | state->nDownloadingSince, | ||||
count_microseconds(GetTime<std::chrono::microseconds>())); | |||||
} | } | ||||
state->vBlocksInFlight.erase(itInFlight->second.second); | state->vBlocksInFlight.erase(itInFlight->second.second); | ||||
state->nBlocksInFlight--; | state->nBlocksInFlight--; | ||||
state->nStallingSince = 0; | state->nStallingSince = 0; | ||||
mapBlocksInFlight.erase(itInFlight); | mapBlocksInFlight.erase(itInFlight); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 32 Lines | std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert( | ||||
state->vBlocksInFlight.end(), | state->vBlocksInFlight.end(), | ||||
{hash, pindex, pindex != nullptr, | {hash, pindex, pindex != nullptr, | ||||
std::unique_ptr<PartiallyDownloadedBlock>( | std::unique_ptr<PartiallyDownloadedBlock>( | ||||
pit ? new PartiallyDownloadedBlock(config, &mempool) : nullptr)}); | pit ? new PartiallyDownloadedBlock(config, &mempool) : nullptr)}); | ||||
state->nBlocksInFlight++; | state->nBlocksInFlight++; | ||||
state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; | state->nBlocksInFlightValidHeaders += it->fValidatedHeaders; | ||||
if (state->nBlocksInFlight == 1) { | if (state->nBlocksInFlight == 1) { | ||||
// We're starting a block download (batch) from this peer. | // We're starting a block download (batch) from this peer. | ||||
state->nDownloadingSince = GetTimeMicros(); | state->nDownloadingSince = GetTime<std::chrono::microseconds>().count(); | ||||
} | } | ||||
if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) { | if (state->nBlocksInFlightValidHeaders == 1 && pindex != nullptr) { | ||||
nPeersWithValidatedDownloads++; | nPeersWithValidatedDownloads++; | ||||
} | } | ||||
itInFlight = mapBlocksInFlight | itInFlight = mapBlocksInFlight | ||||
.insert(std::make_pair(hash, std::make_pair(nodeid, it))) | .insert(std::make_pair(hash, std::make_pair(nodeid, it))) | ||||
▲ Show 20 Lines • Show All 3,545 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::PONG) { | ||||
// Only process pong message if there is an outstanding ping (old | // Only process pong message if there is an outstanding ping (old | ||||
// ping without nonce should never pong) | // ping without nonce should never pong) | ||||
if (pfrom.nPingNonceSent != 0) { | if (pfrom.nPingNonceSent != 0) { | ||||
if (nonce == pfrom.nPingNonceSent) { | if (nonce == pfrom.nPingNonceSent) { | ||||
// Matching pong received, this ping is no longer | // Matching pong received, this ping is no longer | ||||
// outstanding | // outstanding | ||||
bPingFinished = true; | bPingFinished = true; | ||||
const auto ping_time = ping_end - pfrom.m_ping_start.load(); | const auto ping_time = ping_end - pfrom.m_ping_start.load(); | ||||
if (ping_time.count() > 0) { | if (ping_time.count() >= 0) { | ||||
// Successful ping time measurement, replace previous | // Successful ping time measurement, replace previous | ||||
pfrom.nPingUsecTime = count_microseconds(ping_time); | pfrom.nPingUsecTime = count_microseconds(ping_time); | ||||
pfrom.nMinPingUsecTime = | pfrom.nMinPingUsecTime = | ||||
std::min(pfrom.nMinPingUsecTime.load(), | std::min(pfrom.nMinPingUsecTime.load(), | ||||
count_microseconds(ping_time)); | count_microseconds(ping_time)); | ||||
} else { | } else { | ||||
// This should never happen | // This should never happen | ||||
sProblem = "Timing mishap"; | sProblem = "Timing mishap"; | ||||
▲ Show 20 Lines • Show All 590 Lines • ▼ Show 20 Lines | bool PeerManager::SendMessages(const Config &config, CNode *pto, | ||||
} | } | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CNodeState &state = *State(pto->GetId()); | CNodeState &state = *State(pto->GetId()); | ||||
// Address refresh broadcast | // Address refresh broadcast | ||||
int64_t nNow = GetTimeMicros(); | |||||
auto current_time = GetTime<std::chrono::microseconds>(); | auto current_time = GetTime<std::chrono::microseconds>(); | ||||
if (pto->IsAddrRelayPeer() && | if (pto->IsAddrRelayPeer() && | ||||
!::ChainstateActive().IsInitialBlockDownload() && | !::ChainstateActive().IsInitialBlockDownload() && | ||||
pto->m_next_local_addr_send < current_time) { | pto->m_next_local_addr_send < current_time) { | ||||
AdvertiseLocal(pto); | AdvertiseLocal(pto); | ||||
pto->m_next_local_addr_send = PoissonNextSend( | pto->m_next_local_addr_send = PoissonNextSend( | ||||
current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); | current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL); | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { | if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { | ||||
// Only actively request headers from a single peer, unless we're | // Only actively request headers from a single peer, unless we're | ||||
// close to today. | // close to today. | ||||
if ((nSyncStarted == 0 && fFetch) || | if ((nSyncStarted == 0 && fFetch) || | ||||
pindexBestHeader->GetBlockTime() > | pindexBestHeader->GetBlockTime() > | ||||
GetAdjustedTime() - 24 * 60 * 60) { | GetAdjustedTime() - 24 * 60 * 60) { | ||||
state.fSyncStarted = true; | state.fSyncStarted = true; | ||||
state.nHeadersSyncTimeout = | state.nHeadersSyncTimeout = | ||||
GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + | count_microseconds(current_time) + | ||||
HEADERS_DOWNLOAD_TIMEOUT_BASE + | |||||
HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * | HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * | ||||
(GetAdjustedTime() - pindexBestHeader->GetBlockTime()) / | (GetAdjustedTime() - pindexBestHeader->GetBlockTime()) / | ||||
(consensusParams.nPowTargetSpacing); | (consensusParams.nPowTargetSpacing); | ||||
nSyncStarted++; | nSyncStarted++; | ||||
const CBlockIndex *pindexStart = pindexBestHeader; | const CBlockIndex *pindexStart = pindexBestHeader; | ||||
/** | /** | ||||
* If possible, start at the block preceding the currently best | * If possible, start at the block preceding the currently best | ||||
* known header. This ensures that we always get a non-empty | * known header. This ensures that we always get a non-empty | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
// 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 < current_time) { | if (pto->m_tx_relay->nNextInvSend < current_time) { | ||||
fSendTrickle = true; | fSendTrickle = true; | ||||
if (pto->IsInboundConn()) { | if (pto->IsInboundConn()) { | ||||
pto->m_tx_relay->nNextInvSend = | pto->m_tx_relay->nNextInvSend = | ||||
std::chrono::microseconds{ | std::chrono::microseconds{ | ||||
m_connman.PoissonNextSendInbound( | m_connman.PoissonNextSendInbound( | ||||
nNow, INVENTORY_BROADCAST_INTERVAL)}; | count_microseconds(current_time), | ||||
INVENTORY_BROADCAST_INTERVAL)}; | |||||
} else { | } else { | ||||
// Skip delay for outbound peers, as there is less | // Skip delay for outbound peers, as there is less | ||||
// privacy concern for them. | // privacy concern for them. | ||||
pto->m_tx_relay->nNextInvSend = current_time; | pto->m_tx_relay->nNextInvSend = current_time; | ||||
} | } | ||||
} | } | ||||
// Time to send but the peer has requested we not relay | // Time to send but the peer has requested we not relay | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
// Send | // Send | ||||
State(pto->GetId()) | State(pto->GetId()) | ||||
->m_recently_announced_invs.insert(txid); | ->m_recently_announced_invs.insert(txid); | ||||
addInvAndMaybeFlush(MSG_TX, txid); | addInvAndMaybeFlush(MSG_TX, txid); | ||||
nRelayedTransactions++; | nRelayedTransactions++; | ||||
{ | { | ||||
// Expire old relay messages | // Expire old relay messages | ||||
while (!vRelayExpiration.empty() && | while (!vRelayExpiration.empty() && | ||||
vRelayExpiration.front().first < nNow) { | vRelayExpiration.front().first < | ||||
count_microseconds(current_time)) { | |||||
mapRelay.erase(vRelayExpiration.front().second); | mapRelay.erase(vRelayExpiration.front().second); | ||||
vRelayExpiration.pop_front(); | vRelayExpiration.pop_front(); | ||||
} | } | ||||
auto ret = mapRelay.insert( | auto ret = mapRelay.insert( | ||||
std::make_pair(txid, std::move(txinfo.tx))); | std::make_pair(txid, std::move(txinfo.tx))); | ||||
if (ret.second) { | if (ret.second) { | ||||
vRelayExpiration.push_back(std::make_pair( | vRelayExpiration.push_back(std::make_pair( | ||||
nNow + | count_microseconds(current_time) + | ||||
std::chrono::microseconds{ | std::chrono::microseconds{ | ||||
RELAY_TX_CACHE_TIME} | RELAY_TX_CACHE_TIME} | ||||
.count(), | .count(), | ||||
ret.first)); | ret.first)); | ||||
} | } | ||||
} | } | ||||
pto->m_tx_relay->filterInventoryKnown.insert(txid); | pto->m_tx_relay->filterInventoryKnown.insert(txid); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (!vInv.empty()) { | if (!vInv.empty()) { | ||||
m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::INV, vInv)); | ||||
} | } | ||||
// Detect whether we're stalling | // Detect whether we're stalling | ||||
current_time = GetTime<std::chrono::microseconds>(); | current_time = GetTime<std::chrono::microseconds>(); | ||||
// nNow is the current system time (GetTimeMicros is not mockable) and | |||||
// should be replaced by the mockable current_time eventually | |||||
nNow = GetTimeMicros(); | |||||
if (state.nStallingSince && | if (state.nStallingSince && | ||||
state.nStallingSince < nNow - 1000000 * BLOCK_STALLING_TIMEOUT) { | state.nStallingSince < count_microseconds(current_time) - | ||||
1000000 * BLOCK_STALLING_TIMEOUT) { | |||||
// Stalling only triggers when the block download window cannot | // Stalling only triggers when the block download window cannot | ||||
// move. During normal steady state, the download window should be | // move. During normal steady state, the download window should be | ||||
// much larger than the to-be-downloaded set of blocks, so | // much larger than the to-be-downloaded set of blocks, so | ||||
// disconnection should only happen during initial block download. | // disconnection should only happen during initial block download. | ||||
LogPrintf("Peer=%d is stalling block download, disconnecting\n", | LogPrintf("Peer=%d is stalling block download, disconnecting\n", | ||||
pto->GetId()); | pto->GetId()); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
// In case there is a block that has been in flight from this peer for 2 | // In case there is a block that has been in flight from this peer for 2 | ||||
// + 0.5 * N times the block interval (with N the number of peers from | // + 0.5 * N times the block interval (with N the number of peers from | ||||
// which we're downloading validated blocks), disconnect due to timeout. | // which we're downloading validated blocks), disconnect due to timeout. | ||||
// We compensate for other peers to prevent killing off peers due to our | // We compensate for other peers to prevent killing off peers due to our | ||||
// own downstream link being saturated. We only count validated | // own downstream link being saturated. We only count validated | ||||
// in-flight blocks so peers can't advertise non-existing block hashes | // in-flight blocks so peers can't advertise non-existing block hashes | ||||
// to unreasonably increase our timeout. | // to unreasonably increase our timeout. | ||||
if (state.vBlocksInFlight.size() > 0) { | if (state.vBlocksInFlight.size() > 0) { | ||||
QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); | QueuedBlock &queuedBlock = state.vBlocksInFlight.front(); | ||||
int nOtherPeersWithValidatedDownloads = | int nOtherPeersWithValidatedDownloads = | ||||
nPeersWithValidatedDownloads - | nPeersWithValidatedDownloads - | ||||
(state.nBlocksInFlightValidHeaders > 0); | (state.nBlocksInFlightValidHeaders > 0); | ||||
if (nNow > state.nDownloadingSince + | if (count_microseconds(current_time) > | ||||
state.nDownloadingSince + | |||||
consensusParams.nPowTargetSpacing * | consensusParams.nPowTargetSpacing * | ||||
(BLOCK_DOWNLOAD_TIMEOUT_BASE + | (BLOCK_DOWNLOAD_TIMEOUT_BASE + | ||||
BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * | BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * | ||||
nOtherPeersWithValidatedDownloads)) { | nOtherPeersWithValidatedDownloads)) { | ||||
LogPrintf("Timeout downloading block %s from peer=%d, " | LogPrintf("Timeout downloading block %s from peer=%d, " | ||||
"disconnecting\n", | "disconnecting\n", | ||||
queuedBlock.hash.ToString(), pto->GetId()); | queuedBlock.hash.ToString(), pto->GetId()); | ||||
pto->fDisconnect = true; | pto->fDisconnect = true; | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// Check for headers sync timeouts | // Check for headers sync timeouts | ||||
if (state.fSyncStarted && | if (state.fSyncStarted && | ||||
state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { | state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) { | ||||
// Detect whether this is a stalling initial-headers-sync peer | // Detect whether this is a stalling initial-headers-sync peer | ||||
if (pindexBestHeader->GetBlockTime() <= | if (pindexBestHeader->GetBlockTime() <= | ||||
GetAdjustedTime() - 24 * 60 * 60) { | GetAdjustedTime() - 24 * 60 * 60) { | ||||
if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && | if (count_microseconds(current_time) > | ||||
state.nHeadersSyncTimeout && | |||||
nSyncStarted == 1 && | |||||
(nPreferredDownload - state.fPreferredDownload >= 1)) { | (nPreferredDownload - state.fPreferredDownload >= 1)) { | ||||
// Disconnect a (non-whitelisted) peer if it is our only | // Disconnect a (non-whitelisted) peer if it is our only | ||||
// sync peer, and we have others we could be using instead. | // sync peer, and we have others we could be using instead. | ||||
// Note: If all our peers are inbound, then we won't | // Note: If all our peers are inbound, then we won't | ||||
// disconnect our sync peer for stalling; we have bigger | // disconnect our sync peer for stalling; we have bigger | ||||
// problems if we can't get any outbound peers. | // problems if we can't get any outbound peers. | ||||
if (!pto->HasPermission(PF_NOBAN)) { | if (!pto->HasPermission(PF_NOBAN)) { | ||||
LogPrintf("Timeout downloading headers from peer=%d, " | LogPrintf("Timeout downloading headers from peer=%d, " | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
pindex->GetBlockHash(), consensusParams, | pindex->GetBlockHash(), consensusParams, | ||||
pindex); | pindex); | ||||
LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", | LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", | ||||
pindex->GetBlockHash().ToString(), pindex->nHeight, | pindex->GetBlockHash().ToString(), pindex->nHeight, | ||||
pto->GetId()); | pto->GetId()); | ||||
} | } | ||||
if (state.nBlocksInFlight == 0 && staller != -1) { | if (state.nBlocksInFlight == 0 && staller != -1) { | ||||
if (State(staller)->nStallingSince == 0) { | if (State(staller)->nStallingSince == 0) { | ||||
State(staller)->nStallingSince = nNow; | State(staller)->nStallingSince = | ||||
count_microseconds(current_time); | |||||
LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); | LogPrint(BCLog::NET, "Stall started peer=%d\n", staller); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// | // | ||||
// Message: getdata (transactions) | // Message: getdata (transactions) | ||||
// | // | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | if (pingSend) { | ||||
gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | gArgs.GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && | ||||
!pto->HasPermission(PF_FORCERELAY)) { | !pto->HasPermission(PF_FORCERELAY)) { | ||||
Amount currentFilter = | Amount currentFilter = | ||||
m_mempool | m_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(); | |||||
static FeeFilterRounder g_filter_rounder{ | static FeeFilterRounder g_filter_rounder{ | ||||
CFeeRate{DEFAULT_MIN_RELAY_TX_FEE_PER_KB}}; | CFeeRate{DEFAULT_MIN_RELAY_TX_FEE_PER_KB}}; | ||||
if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) { | if (m_chainman.ActiveChainstate().IsInitialBlockDownload()) { | ||||
// Received tx-inv messages are discarded when the active | // Received tx-inv messages are discarded when the active | ||||
// chainstate is in IBD, so tell the peer to not send them. | // chainstate is in IBD, so tell the peer to not send them. | ||||
currentFilter = MAX_MONEY; | currentFilter = MAX_MONEY; | ||||
} else { | } else { | ||||
static const Amount MAX_FILTER{ | static const Amount MAX_FILTER{ | ||||
g_filter_rounder.round(MAX_MONEY)}; | g_filter_rounder.round(MAX_MONEY)}; | ||||
if (pto->m_tx_relay->lastSentFeeFilter == MAX_FILTER) { | if (pto->m_tx_relay->lastSentFeeFilter == MAX_FILTER) { | ||||
// Send the current filter if we sent MAX_FILTER previously | // Send the current filter if we sent MAX_FILTER previously | ||||
// and made it out of IBD. | // and made it out of IBD. | ||||
pto->m_tx_relay->nextSendTimeFeeFilter = timeNow - 1; | pto->m_tx_relay->nextSendTimeFeeFilter = | ||||
count_microseconds(current_time) - 1; | |||||
} | } | ||||
} | } | ||||
if (timeNow > pto->m_tx_relay->nextSendTimeFeeFilter) { | if (count_microseconds(current_time) > | ||||
pto->m_tx_relay->nextSendTimeFeeFilter) { | |||||
Amount filterToSend = g_filter_rounder.round(currentFilter); | Amount filterToSend = g_filter_rounder.round(currentFilter); | ||||
filterToSend = | filterToSend = | ||||
std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); | std::max(filterToSend, ::minRelayTxFee.GetFeePerK()); | ||||
if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) { | if (filterToSend != pto->m_tx_relay->lastSentFeeFilter) { | ||||
m_connman.PushMessage( | m_connman.PushMessage( | ||||
pto, | pto, | ||||
msgMaker.Make(NetMsgType::FEEFILTER, filterToSend)); | 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(count_microseconds(current_time), | ||||
AVG_FEEFILTER_BROADCAST_INTERVAL); | |||||
} | } | ||||
// If the fee filter has changed substantially and it's still more | // If the fee filter has changed substantially and it's still more | ||||
// than MAX_FEEFILTER_CHANGE_DELAY until scheduled broadcast, then | // than MAX_FEEFILTER_CHANGE_DELAY until scheduled broadcast, then | ||||
// move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. | // move the broadcast to within MAX_FEEFILTER_CHANGE_DELAY. | ||||
else if (timeNow + MAX_FEEFILTER_CHANGE_DELAY * 1000000 < | else if (count_microseconds(current_time) + | ||||
MAX_FEEFILTER_CHANGE_DELAY * 1000000 < | |||||
pto->m_tx_relay->nextSendTimeFeeFilter && | pto->m_tx_relay->nextSendTimeFeeFilter && | ||||
(currentFilter < | (currentFilter < | ||||
3 * pto->m_tx_relay->lastSentFeeFilter / 4 || | 3 * pto->m_tx_relay->lastSentFeeFilter / 4 || | ||||
currentFilter > | currentFilter > | ||||
4 * pto->m_tx_relay->lastSentFeeFilter / 3)) { | 4 * pto->m_tx_relay->lastSentFeeFilter / 3)) { | ||||
pto->m_tx_relay->nextSendTimeFeeFilter = | pto->m_tx_relay->nextSendTimeFeeFilter = | ||||
timeNow + GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; | count_microseconds(current_time) + | ||||
GetRandInt(MAX_FEEFILTER_CHANGE_DELAY) * 1000000; | |||||
} | } | ||||
} | } | ||||
} // release cs_main | } // release cs_main | ||||
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(); | ||||
} | } | ||||
}; | }; | ||||
static CNetProcessingCleanup instance_of_cnetprocessingcleanup; | static CNetProcessingCleanup instance_of_cnetprocessingcleanup; |