diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_SEEDER_BITCOIN_H #define BITCOIN_SEEDER_BITCOIN_H +#include #include #include diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp --- a/src/seeder/bitcoin.cpp +++ b/src/seeder/bitcoin.cpp @@ -172,6 +172,21 @@ return false; } + // Node has chainparams and should not be filtered out + if (strCommand == NetMsgType::HEADERS) { + // fprintf(stderr, "%s: not banned\n", ToString(you).c_str()); + GotVersion(); + return false; + } + + // Chain params not found, so we ban the node + if (strCommand == NetMsgType::NOTFOUND) { + // fprintf(stderr, "%s: chainparams not found, banned\n", + // ToString(you).c_str()); + ban = 100000; + return false; + } + return false; } diff --git a/src/seeder/test/seeder_tests.cpp b/src/seeder/test/seeder_tests.cpp --- a/src/seeder/test/seeder_tests.cpp +++ b/src/seeder/test/seeder_tests.cpp @@ -4,6 +4,7 @@ #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite +#include #include #include #include @@ -42,6 +43,10 @@ static const std::string VERACK_COMMAND = "verack"; static const std::string VERSION_COMMAND = "version"; static const std::string ADDR_COMMAND = "addr"; +static const std::string SENDHEADERS_COMMAND = "sendheaders"; +static const std::string HEADERS_COMMAND = "headers"; +static const std::string EMPTY_HEADERS_COMMAND = "emptyheaders"; +static const uint8_t HEADERS_TXN_COUNT = 0; static const std::string SEED = "seed.bitcoinabc.org"; static const uint32_t VERACK_PAYLOAD = 0; @@ -100,10 +105,18 @@ } else if (strCommand == VERACK_COMMAND) { CreateVerackMessage(); return CSeederNode::ProcessMessage(VERACK_COMMAND, message); - } else { - // strCommand == ADDR_COMMAND + } else if (strCommand == ADDR_COMMAND) { CreateAddrMessage(); return CSeederNode::ProcessMessage(ADDR_COMMAND, message); + } else if (strCommand == EMPTY_HEADERS_COMMAND) { + CreateHeadersMessage(true); + // Calls ProcessMessage() on an empty headers message, but the + // message is still a headers message with a headers command + return CSeederNode::ProcessMessage(HEADERS_COMMAND, message); + } else { + // strCommand == HEADERS_COMMAND + CreateHeadersMessage(false); + return CSeederNode::ProcessMessage(HEADERS_COMMAND, message); } } @@ -163,6 +176,38 @@ memcpy(header.pchChecksum, &hash, header.CHECKSUM_SIZE); } + void CreateHeadersMessage(bool emptyMessage) { + CDataStream payload(SER_NETWORK, 0); + payload.SetVersion(nVersion); + uint8_t messageSize = emptyMessage ? 0 : 1; + payload << messageSize; + // The actual headers can be garbage data, Seeder only cares that it got + // a specific type of message and the size. + uint256 garbageHash = Hash(payload.begin(), payload.end()); + uint32_t garbageTimeStamp = 0; + uint32_t garbageBits = 0; + uint32_t garbageNonce = 0; + payload << nVersion; + // prev_block + payload << garbageHash; + // merkle_root + payload << garbageHash; + // timestamp + payload << garbageTimeStamp; + // bits + payload << garbageBits; + // nonce + payload << garbageNonce; + // txn_count + payload << HEADERS_TXN_COUNT; + message.erase(message.begin(), message.end()); + message += payload; + + header.nMessageSize = payload.size(); + uint256 hash = Hash(payload.begin(), payload.end()); + memcpy(header.pchChecksum, &hash, header.CHECKSUM_SIZE); + } + std::vector vAddr; int32_t nVersion; CDataStream message; @@ -339,4 +384,28 @@ BOOST_CHECK_EQUAL(1001, testNode.getAddrListSize()); } +BOOST_AUTO_TEST_CASE(seeder_node_headers_test_happy_path) { + CNetAddr ip; + LookupHost(SEED.c_str(), ip, true); + const CService service(ip, MAINNET_PORT); + CAddress addr(service, ServiceFlags()); + std::vector vAddr(1, addr); + TestCSeederNode testNode(service, vAddr); + + bool ret = testNode.TestProcessMessage(HEADERS_COMMAND); + BOOST_CHECK_EQUAL(ret, false); +} + +BOOST_AUTO_TEST_CASE(seeder_node_empty_headers_test) { + CNetAddr ip; + LookupHost(SEED.c_str(), ip, true); + const CService service(ip, MAINNET_PORT); + CAddress addr(service, ServiceFlags()); + std::vector vAddr(1, addr); + TestCSeederNode testNode(service, vAddr); + + bool ret = testNode.TestProcessMessage(EMPTY_HEADERS_COMMAND); + BOOST_CHECK_EQUAL(ret, false); +} + BOOST_AUTO_TEST_SUITE_END()