Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/bitcoin.cpp
// Copyright (c) 2017-2020 The Bitcoin developers | // Copyright (c) 2017-2020 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <seeder/bitcoin.h> | #include <seeder/bitcoin.h> | ||||
#include <chainparams.h> | #include <chainparams.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <netbase.h> | #include <netbase.h> | ||||
#include <primitives/blockhash.h> | #include <primitives/blockhash.h> | ||||
#include <seeder/db.h> | #include <seeder/db.h> | ||||
#include <seeder/messagewriter.h> | #include <seeder/messagewriter.h> | ||||
#include <serialize.h> | #include <serialize.h> | ||||
#include <uint256.h> | #include <uint256.h> | ||||
#include <util/time.h> | #include <util/time.h> | ||||
#include <validation.h> | |||||
#include <algorithm> | #include <algorithm> | ||||
#define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL | #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL | ||||
void CSeederNode::Send() { | void CSeederNode::Send() { | ||||
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (strCommand == NetMsgType::ADDR && vAddr) { | ||||
addr.nTime = now - 5 * 86400; | addr.nTime = now - 5 * 86400; | ||||
} | } | ||||
if (addr.nTime > now - 604800) { | if (addr.nTime > now - 604800) { | ||||
vAddr->push_back(addr); | vAddr->push_back(addr); | ||||
} | } | ||||
// tfm::format(std::cout, "%s: added address %s (#%i)\n", | // tfm::format(std::cout, "%s: added address %s (#%i)\n", | ||||
// ToString(you), | // ToString(you), | ||||
// addr.ToString(), (int)(vAddr->size())); | // addr.ToString(), (int)(vAddr->size())); | ||||
if (vAddr->size() > ADDR_SOFT_CAP) { | if (vAddr->size() > ADDR_SOFT_CAP) { | ||||
deadalnix: There is clearly some duplication here. You main issue comes from the fact that message… | |||||
doneAfter = 1; | // Seeder is finished with a node after it has received | ||||
// ADDR_SOFT_CAP addrs from a node AND after the seeder has | |||||
// checked the node's chain | |||||
if (checkpointState != CheckpointState::NotChecked) { | |||||
// Note that we do not ban until after addrs are received | |||||
// so that we can still crawl the network effectively. | |||||
if (checkpointState == CheckpointState::NotFound) { | |||||
ban = 100000; | |||||
} | |||||
doneAfter = checkpointState == CheckpointState::HasLatest; | |||||
return PeerMessagingState::Finished; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
return PeerMessagingState::AwaitingMessages; | |||||
} | |||||
// A node in the process of IBD-ing will not send this message and | |||||
// therefore will timeout waiting for the checkpoint. | |||||
if (strCommand == NetMsgType::HEADERS && vAddr) { | |||||
std::vector<CBlockHeader> headers; | |||||
recv >> headers; | |||||
const CChainParams &chainParams = Params(); | |||||
doneAfter = 0; | |||||
checkpointState = CheckpointState::NotFound; | |||||
if (headers.size() > MAX_HEADERS_RESULTS) { | |||||
tfm::format(std::cout, | |||||
"%s: Misbehaving: oversized HEADERS message\n", | |||||
ToString(you)); | |||||
ban = 100000; | |||||
return PeerMessagingState::Finished; | return PeerMessagingState::Finished; | ||||
} | } | ||||
if (headers.size() == 0) { | |||||
// This is an ambiguous situation where either the peer only has | |||||
// the genesis block or has exactly up to the checkpoint. Either | |||||
// way, the peer should be marked bad but not banned. | |||||
checkpointState = CheckpointState::IncompleteChain; | |||||
} else if (chainParams.Checkpoints().mapCheckpoints.rbegin()->second == | |||||
headers[0].hashPrevBlock) { | |||||
// The hashPrevBlock of the first header received should be the hash | |||||
// of the checkpoint if the node is following the correct chain. | |||||
doneAfter = GetTime() + GetTimeout(); | |||||
checkpointState = CheckpointState::HasLatest; | |||||
} | |||||
// Seeder is finished with a node after it has received ADDR_SOFT_CAP | |||||
// addrs from a node AND after the seeder has checked the node's chain | |||||
if (vAddr->size() > ADDR_SOFT_CAP) { | |||||
deadalnixUnsubmitted Not Done Inline ActionsSee previous comment. It is hard to justify doing anything with he address soft cap in the processing of received headers. While I understand that the seeder is a mess to begin with, making it worse should be avoided. deadalnix: See previous comment. It is hard to justify doing anything with he address soft cap in the… | |||||
// Note that we do not ban until after addrs are received | |||||
// so that we can still crawl the network effectively. | |||||
if (checkpointState == CheckpointState::NotFound) { | |||||
ban = 100000; | |||||
} | |||||
doneAfter = checkpointState == CheckpointState::HasLatest; | |||||
return PeerMessagingState::Finished; | |||||
} | } | ||||
return PeerMessagingState::AwaitingMessages; | return PeerMessagingState::AwaitingMessages; | ||||
} | } | ||||
return PeerMessagingState::AwaitingMessages; | return PeerMessagingState::AwaitingMessages; | ||||
} | } | ||||
bool CSeederNode::ProcessMessages() { | bool CSeederNode::ProcessMessages() { | ||||
if (vRecv.empty()) { | if (vRecv.empty()) { | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | do { | ||||
// strCommand); | // strCommand); | ||||
} while (1); | } while (1); | ||||
return false; | return false; | ||||
} | } | ||||
CSeederNode::CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn) | CSeederNode::CSeederNode(const CService &ip, std::vector<CAddress> *vAddrIn) | ||||
: sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), | : sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), | ||||
nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), | nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), | ||||
doneAfter(0), you(ip, ServiceFlags(NODE_NETWORK)) { | doneAfter(0), you(ip, ServiceFlags(NODE_NETWORK)), | ||||
checkpointState(CheckpointState::NotChecked) { | |||||
if (GetTime() > 1329696000) { | if (GetTime() > 1329696000) { | ||||
vSend.SetVersion(209); | vSend.SetVersion(209); | ||||
vRecv.SetVersion(209); | vRecv.SetVersion(209); | ||||
} | } | ||||
} | } | ||||
bool CSeederNode::Run() { | bool CSeederNode::Run() { | ||||
// FIXME: This logic is duplicated with CConnman::ConnectNode for no | // FIXME: This logic is duplicated with CConnman::ConnectNode for no | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | while (now = GetTime(), ban == 0 && (doneAfter == 0 || doneAfter > now) && | ||||
ProcessMessages(); | ProcessMessages(); | ||||
Send(); | Send(); | ||||
} | } | ||||
if (sock == INVALID_SOCKET) { | if (sock == INVALID_SOCKET) { | ||||
res = false; | res = false; | ||||
} | } | ||||
close(sock); | close(sock); | ||||
sock = INVALID_SOCKET; | sock = INVALID_SOCKET; | ||||
return (ban == 0) && res; | return (ban == 0) && res && (checkpointState == CheckpointState::HasLatest); | ||||
} | } |
There is clearly some duplication here. You main issue comes from the fact that message parsing/processing is intermingled with the logic of the seeder's state machine. This is just bound to cause problems. For instance, if the remote node send response out of order - which is allowed by the protocol - then this won't be good. I think some refactoring is in order.