Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/test/seeder_tests.cpp
// Copyright (c) 2019 The Bitcoin developers | // Copyright (c) 2019 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. | ||||
#define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | ||||
#include <chainparamsconstants.h> | |||||
#include <hash.h> | #include <hash.h> | ||||
#include <netbase.h> | #include <netbase.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <seeder/bitcoin.h> | #include <seeder/bitcoin.h> | ||||
#include <seeder/db.h> | #include <seeder/db.h> | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
#include <serialize.h> | #include <serialize.h> | ||||
#include <streams.h> | #include <streams.h> | ||||
Show All 22 Lines | |||||
static const uint16_t QUESTION_CLASS = 1; | static const uint16_t QUESTION_CLASS = 1; | ||||
static const uint16_t QUESTION_TYPE = 1; | static const uint16_t QUESTION_TYPE = 1; | ||||
static const uint8_t END_OF_NAME_FIELD = 0; | static const uint8_t END_OF_NAME_FIELD = 0; | ||||
static const size_t MAX_LABEL_LENGTH = 63; | static const size_t MAX_LABEL_LENGTH = 63; | ||||
static const unsigned short MAINNET_PORT = 8333; | static const unsigned short MAINNET_PORT = 8333; | ||||
static const std::string VERACK_COMMAND = "verack"; | static const std::string VERACK_COMMAND = "verack"; | ||||
static const std::string VERSION_COMMAND = "version"; | static const std::string VERSION_COMMAND = "version"; | ||||
static const std::string ADDR_COMMAND = "addr"; | 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"; | |||||
deadalnix: This is not a message that exists. | |||||
static const uint8_t HEADERS_TXN_COUNT = 0; | |||||
static const std::string SEED = "seed.bitcoinabc.org"; | static const std::string SEED = "seed.bitcoinabc.org"; | ||||
static const uint32_t VERACK_PAYLOAD = 0; | static const uint32_t VERACK_PAYLOAD = 0; | ||||
// Builds dummy DNS query message | // Builds dummy DNS query message | ||||
std::array<uint8_t, BUFFER_LENGTH> | std::array<uint8_t, BUFFER_LENGTH> | ||||
CreateDNSQuestion(const std::string &qualifierName) { | CreateDNSQuestion(const std::string &qualifierName) { | ||||
std::stringstream querryhex; | std::stringstream querryhex; | ||||
querryhex.clear(); | querryhex.clear(); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | public: | ||||
bool TestProcessMessage(const std::string &strCommand) { | bool TestProcessMessage(const std::string &strCommand) { | ||||
if (strCommand == VERSION_COMMAND) { | if (strCommand == VERSION_COMMAND) { | ||||
CreateVersionMessage(); | CreateVersionMessage(); | ||||
return CSeederNode::ProcessMessage(VERSION_COMMAND, message); | return CSeederNode::ProcessMessage(VERSION_COMMAND, message); | ||||
} else if (strCommand == VERACK_COMMAND) { | } else if (strCommand == VERACK_COMMAND) { | ||||
CreateVerackMessage(); | CreateVerackMessage(); | ||||
return CSeederNode::ProcessMessage(VERACK_COMMAND, message); | return CSeederNode::ProcessMessage(VERACK_COMMAND, message); | ||||
} else { | } else if (strCommand == ADDR_COMMAND) { | ||||
// strCommand == ADDR_COMMAND | |||||
CreateAddrMessage(); | CreateAddrMessage(); | ||||
return CSeederNode::ProcessMessage(ADDR_COMMAND, message); | 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); | |||||
} | } | ||||
} | } | ||||
void setVersion(int32_t version) { nVersion = version; } | void setVersion(int32_t version) { nVersion = version; } | ||||
size_t getAddrListSize() { return vAddr.size(); } | size_t getAddrListSize() { return vAddr.size(); } | ||||
private: | private: | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | void CreateAddrMessage() { | ||||
message.erase(message.begin(), message.end()); | message.erase(message.begin(), message.end()); | ||||
message += payload; | message += payload; | ||||
header.nMessageSize = payload.size(); | header.nMessageSize = payload.size(); | ||||
uint256 hash = Hash(payload.begin(), payload.end()); | uint256 hash = Hash(payload.begin(), payload.end()); | ||||
memcpy(header.pchChecksum, &hash, header.CHECKSUM_SIZE); | 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; | |||||
deadalnixUnsubmitted Not Done Inline ActionsThe lack of if statement bellow makes it very clear that this is NOT the size of the message. the size of the message is also very clearly not 0 or 1. deadalnix: The lack of if statement bellow makes it very clear that this is NOT the size of the message. | |||||
// 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<CAddress> vAddr; | std::vector<CAddress> vAddr; | ||||
int32_t nVersion; | int32_t nVersion; | ||||
CDataStream message; | CDataStream message; | ||||
CMessageHeader header; | CMessageHeader header; | ||||
}; | }; | ||||
BOOST_AUTO_TEST_CASE(parse_name_happy_path) { | BOOST_AUTO_TEST_CASE(parse_name_happy_path) { | ||||
const std::string messageQualifierName = "www.mydomain.com"; | const std::string messageQualifierName = "www.mydomain.com"; | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(seeder_node_addr_test_full_vaddr) { | ||||
TestCSeederNode testNode(service, vAddr); | TestCSeederNode testNode(service, vAddr); | ||||
// After the 1000th, only one is added and the rest are ignored | // After the 1000th, only one is added and the rest are ignored | ||||
bool ret = testNode.TestProcessMessage(ADDR_COMMAND); | bool ret = testNode.TestProcessMessage(ADDR_COMMAND); | ||||
BOOST_CHECK_EQUAL(ret, true); | BOOST_CHECK_EQUAL(ret, true); | ||||
BOOST_CHECK_EQUAL(1001, testNode.getAddrListSize()); | 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<CAddress> vAddr(1, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
bool ret = testNode.TestProcessMessage(HEADERS_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
deadalnixUnsubmitted Not Done Inline ActionsPresumably you'd want to test that the node is not banned. deadalnix: Presumably you'd want to test that the node is not banned. | |||||
} | |||||
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<CAddress> vAddr(1, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
bool ret = testNode.TestProcessMessage(EMPTY_HEADERS_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
BOOST_CHECK_EQUAL(testNode.GetBan(), 100000); | |||||
} | |||||
deadalnixUnsubmitted Not Done Inline ActionsThis is not really testing what we need/want to be testing. We want to make sure we keep nodes that follow a certain chain and reject these that do not. There are intermediary steps here, but it is clear that this test is not helping because the does the completely wrong thing, and the test effectively test the corresponding wrong behavior. deadalnix: This is not really testing what we need/want to be testing. We want to make sure we keep nodes… | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |
This is not a message that exists.