Changeset View
Changeset View
Standalone View
Standalone View
src/net_processing.cpp
Show First 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Average delay between feefilter broadcasts in seconds. | * Average delay between feefilter broadcasts in seconds. | ||||
*/ | */ | ||||
static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; | static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; | ||||
/** | /** | ||||
* Maximum feefilter broadcast delay after significant change. | * Maximum feefilter broadcast delay after significant change. | ||||
*/ | */ | ||||
static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; | static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; | ||||
/** | |||||
* Maximum number of cf hashes that may be requested with one getcfheaders. See | |||||
* BIP 157. | |||||
*/ | |||||
static constexpr uint32_t MAX_GETCFHEADERS_SIZE = 2000; | |||||
// Internal stuff | // Internal stuff | ||||
namespace { | namespace { | ||||
/** Number of nodes with fSyncStarted. */ | /** Number of nodes with fSyncStarted. */ | ||||
int nSyncStarted GUARDED_BY(cs_main) = 0; | int nSyncStarted GUARDED_BY(cs_main) = 0; | ||||
/** | /** | ||||
* Sources of received blocks, saved to be able to punish them when processing | * Sources of received blocks, saved to be able to punish them when processing | ||||
▲ Show 20 Lines • Show All 2,059 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Validation logic for compact filters request handling. | * Validation logic for compact filters request handling. | ||||
* | * | ||||
* May disconnect from the peer in the case of a bad request. | * May disconnect from the peer in the case of a bad request. | ||||
* | * | ||||
* @param[in] pfrom The peer that we received the request from | * @param[in] pfrom The peer that we received the request from | ||||
* @param[in] chain_params Chain parameters | * @param[in] chain_params Chain parameters | ||||
* @param[in] filter_type The filter type the request is for. Must be | * @param[in] filter_type The filter type the request is for. Must be | ||||
* basic filters. | * basic filters. | ||||
* @param[in] start_height The start height for the request | |||||
* @param[in] stop_hash The stop_hash for the request | * @param[in] stop_hash The stop_hash for the request | ||||
* @param[in] max_height_diff The maximum number of items permitted to | |||||
* request, as specified in BIP 157 | |||||
* @param[out] stop_index The CBlockIndex for the stop_hash block, if the | * @param[out] stop_index The CBlockIndex for the stop_hash block, if the | ||||
* request can be serviced. | * request can be serviced. | ||||
* @param[out] filter_index The filter index, if the request can be | * @param[out] filter_index The filter index, if the request can be | ||||
* serviced. | * serviced. | ||||
* @return True if the request can be serviced. | * @return True if the request can be serviced. | ||||
*/ | */ | ||||
static bool PrepareBlockFilterRequest(CNode *pfrom, | static bool PrepareBlockFilterRequest( | ||||
const CChainParams &chain_params, | CNode *pfrom, const CChainParams &chain_params, BlockFilterType filter_type, | ||||
BlockFilterType filter_type, | uint32_t start_height, const BlockHash &stop_hash, uint32_t max_height_diff, | ||||
const BlockHash &stop_hash, | const CBlockIndex *&stop_index, BlockFilterIndex *&filter_index) { | ||||
const CBlockIndex *&stop_index, | |||||
BlockFilterIndex *&filter_index) { | |||||
const bool supported_filter_type = | const bool supported_filter_type = | ||||
(filter_type == BlockFilterType::BASIC && | (filter_type == BlockFilterType::BASIC && | ||||
gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)); | gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)); | ||||
if (!supported_filter_type) { | if (!supported_filter_type) { | ||||
LogPrint(BCLog::NET, | LogPrint(BCLog::NET, | ||||
"peer %d requested unsupported block filter type: %d\n", | "peer %d requested unsupported block filter type: %d\n", | ||||
pfrom->GetId(), static_cast<uint8_t>(filter_type)); | pfrom->GetId(), static_cast<uint8_t>(filter_type)); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
Show All 10 Lines | if (!supported_filter_type) { | ||||
!BlockRequestAllowed(stop_index, chain_params.GetConsensus())) { | !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) { | ||||
LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n", | LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n", | ||||
pfrom->GetId(), stop_hash.ToString()); | pfrom->GetId(), stop_hash.ToString()); | ||||
pfrom->fDisconnect = true; | pfrom->fDisconnect = true; | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
uint32_t stop_height = stop_index->nHeight; | |||||
if (start_height > stop_height) { | |||||
LogPrint( | |||||
BCLog::NET, | |||||
"peer %d sent invalid getcfilters/getcfheaders with " /* Continued | |||||
*/ | |||||
"start height %d and stop height %d\n", | |||||
pfrom->GetId(), start_height, stop_height); | |||||
pfrom->fDisconnect = true; | |||||
return false; | |||||
} | |||||
if (stop_height - start_height >= max_height_diff) { | |||||
LogPrint(BCLog::NET, | |||||
"peer %d requested too many cfilters/cfheaders: %d / %d\n", | |||||
pfrom->GetId(), stop_height - start_height + 1, | |||||
max_height_diff); | |||||
pfrom->fDisconnect = true; | |||||
return false; | |||||
} | |||||
filter_index = GetBlockFilterIndex(filter_type); | filter_index = GetBlockFilterIndex(filter_type); | ||||
if (!filter_index) { | if (!filter_index) { | ||||
LogPrint(BCLog::NET, "Filter index for supported type %s not found\n", | LogPrint(BCLog::NET, "Filter index for supported type %s not found\n", | ||||
BlockFilterTypeName(filter_type)); | BlockFilterTypeName(filter_type)); | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Handle a cfheaders request. | |||||
* | |||||
* May disconnect from the peer in the case of a bad request. | |||||
* | |||||
* @param[in] pfrom The peer that we received the request from | |||||
* @param[in] vRecv The raw message received | |||||
* @param[in] chain_params Chain parameters | |||||
* @param[in] connman Pointer to the connection manager | |||||
*/ | |||||
static void ProcessGetCFHeaders(CNode *pfrom, CDataStream &vRecv, | |||||
const CChainParams &chain_params, | |||||
CConnman *connman) { | |||||
uint8_t filter_type_ser; | |||||
uint32_t start_height; | |||||
BlockHash stop_hash; | |||||
vRecv >> filter_type_ser >> start_height >> stop_hash; | |||||
const BlockFilterType filter_type = | |||||
static_cast<BlockFilterType>(filter_type_ser); | |||||
const CBlockIndex *stop_index; | |||||
BlockFilterIndex *filter_index; | |||||
if (!PrepareBlockFilterRequest( | |||||
pfrom, chain_params, filter_type, start_height, stop_hash, | |||||
MAX_GETCFHEADERS_SIZE, stop_index, filter_index)) { | |||||
return; | |||||
} | |||||
uint256 prev_header; | |||||
if (start_height > 0) { | |||||
const CBlockIndex *const prev_block = | |||||
stop_index->GetAncestor(static_cast<int>(start_height - 1)); | |||||
if (!filter_index->LookupFilterHeader(prev_block, prev_header)) { | |||||
LogPrint(BCLog::NET, | |||||
"Failed to find block filter header in index: " | |||||
"filter_type=%s, block_hash=%s\n", | |||||
BlockFilterTypeName(filter_type), | |||||
prev_block->GetBlockHash().ToString()); | |||||
return; | |||||
} | |||||
} | |||||
std::vector<uint256> filter_hashes; | |||||
if (!filter_index->LookupFilterHashRange(start_height, stop_index, | |||||
filter_hashes)) { | |||||
LogPrint(BCLog::NET, | |||||
"Failed to find block filter hashes in index: filter_type=%s, " | |||||
"start_height=%d, stop_hash=%s\n", | |||||
BlockFilterTypeName(filter_type), start_height, | |||||
stop_hash.ToString()); | |||||
return; | |||||
} | |||||
CSerializedNetMsg msg = | |||||
CNetMsgMaker(pfrom->GetSendVersion()) | |||||
.Make(NetMsgType::CFHEADERS, filter_type_ser, | |||||
stop_index->GetBlockHash(), prev_header, filter_hashes); | |||||
connman->PushMessage(pfrom, std::move(msg)); | |||||
} | |||||
/** | |||||
* Handle a getcfcheckpt request. | * Handle a getcfcheckpt request. | ||||
* | * | ||||
* May disconnect from the peer in the case of a bad request. | * May disconnect from the peer in the case of a bad request. | ||||
* | * | ||||
* @param[in] pfrom The peer that we received the request from | * @param[in] pfrom The peer that we received the request from | ||||
* @param[in] vRecv The raw message received | * @param[in] vRecv The raw message received | ||||
* @param[in] chain_params Chain parameters | * @param[in] chain_params Chain parameters | ||||
* @param[in] connman Pointer to the connection manager | * @param[in] connman Pointer to the connection manager | ||||
*/ | */ | ||||
static void ProcessGetCFCheckPt(CNode *pfrom, CDataStream &vRecv, | static void ProcessGetCFCheckPt(CNode *pfrom, CDataStream &vRecv, | ||||
const CChainParams &chain_params, | const CChainParams &chain_params, | ||||
CConnman *connman) { | CConnman *connman) { | ||||
uint8_t filter_type_ser; | uint8_t filter_type_ser; | ||||
BlockHash stop_hash; | BlockHash stop_hash; | ||||
vRecv >> filter_type_ser >> stop_hash; | vRecv >> filter_type_ser >> stop_hash; | ||||
const BlockFilterType filter_type = | const BlockFilterType filter_type = | ||||
static_cast<BlockFilterType>(filter_type_ser); | static_cast<BlockFilterType>(filter_type_ser); | ||||
const CBlockIndex *stop_index; | const CBlockIndex *stop_index; | ||||
BlockFilterIndex *filter_index; | BlockFilterIndex *filter_index; | ||||
if (!PrepareBlockFilterRequest(pfrom, chain_params, filter_type, stop_hash, | if (!PrepareBlockFilterRequest( | ||||
pfrom, chain_params, filter_type, /*start_height=*/0, stop_hash, | |||||
/*max_height_diff=*/std::numeric_limits<uint32_t>::max(), | |||||
stop_index, filter_index)) { | stop_index, filter_index)) { | ||||
return; | return; | ||||
} | } | ||||
std::vector<uint256> headers(stop_index->nHeight / CFCHECKPT_INTERVAL); | std::vector<uint256> headers(stop_index->nHeight / CFCHECKPT_INTERVAL); | ||||
// Populate headers. | // Populate headers. | ||||
const CBlockIndex *block_index = stop_index; | const CBlockIndex *block_index = stop_index; | ||||
for (int i = headers.size() - 1; i >= 0; i--) { | for (int i = headers.size() - 1; i >= 0; i--) { | ||||
▲ Show 20 Lines • Show All 1,633 Lines • ▼ Show 20 Lines | if (msg_type == NetMsgType::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 (msg_type == NetMsgType::GETCFHEADERS) { | |||||
ProcessGetCFHeaders(pfrom, vRecv, chainparams, connman); | |||||
return true; | |||||
} | |||||
if (msg_type == NetMsgType::GETCFCHECKPT) { | if (msg_type == NetMsgType::GETCFCHECKPT) { | ||||
ProcessGetCFCheckPt(pfrom, vRecv, chainparams, connman); | ProcessGetCFCheckPt(pfrom, vRecv, chainparams, connman); | ||||
return true; | return true; | ||||
} | } | ||||
if (msg_type == NetMsgType::NOTFOUND) { | if (msg_type == NetMsgType::NOTFOUND) { | ||||
// Remove the NOTFOUND transactions from the peer | // Remove the NOTFOUND transactions from the peer | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
▲ Show 20 Lines • Show All 1,126 Lines • Show Last 20 Lines |