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 <chainparams.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 25 Lines | |||||
static const uint16_t QUERY_TYPE = 1; | static const uint16_t QUERY_TYPE = 1; | ||||
// End of name field | // End of name field | ||||
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 int SEND_NO_HEADERS = -1; | |||||
static const int SEND_WRONG_CHAIN_HEADER = 0; | |||||
static const int SEND_GOOD_HEADER = 1; | |||||
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; | ||||
// After the 1000th addr, the seeder will only add one more address from an addr | // After the 1000th addr, the seeder will only add one more address from an addr | ||||
// message. | // message. | ||||
static const int VADDR_SOFT_CAP = 1000; | static const int VADDR_SOFT_CAP = 1000; | ||||
// Builds dummy DNS query message | // Builds dummy DNS query message | ||||
std::array<uint8_t, BUFFER_LENGTH> | std::array<uint8_t, BUFFER_LENGTH> | ||||
Show All 31 Lines | CreateDNSQuestion(const std::string &queryName) { | ||||
messageBuffer.fill(0); | messageBuffer.fill(0); | ||||
queryhex >> std::hex >> messageBuffer.data(); | queryhex >> std::hex >> messageBuffer.data(); | ||||
return messageBuffer; | return messageBuffer; | ||||
} | } | ||||
class TestCSeederNode : public CSeederNode { | class TestCSeederNode : public CSeederNode { | ||||
public: | public: | ||||
TestCSeederNode(const CService &service, std::vector<CAddress> &vAddrIn, | TestCSeederNode(const CService &service, std::vector<CAddress> &vAddrIn, | ||||
int nAddrsToSendIn = 0) | int nAddrsToSendIn = 0, int headersTest = 1) | ||||
: CSeederNode(service, &vAddr), vAddr(vAddrIn), | : CSeederNode(service, &vAddr), vAddr(vAddrIn), | ||||
nAddrsToSend(nAddrsToSendIn), nVersion(INIT_PROTO_VERSION) {} | nAddrsToSend(nAddrsToSendIn), nVersion(INIT_PROTO_VERSION), | ||||
headersMessageContent(headersTest) {} | |||||
bool TestProcessMessage(const std::string &strCommand) { | bool TestProcessMessage(const std::string &strCommand) { | ||||
if (strCommand == VERSION_COMMAND) { | if (strCommand == VERSION_COMMAND) { | ||||
CDataStream message = CreateVersionMessage(); | CDataStream message = CreateVersionMessage(); | ||||
return CSeederNode::ProcessMessage(VERSION_COMMAND, message); | return CSeederNode::ProcessMessage(VERSION_COMMAND, message); | ||||
} else if (strCommand == VERACK_COMMAND) { | } else if (strCommand == VERACK_COMMAND) { | ||||
CDataStream message = CreateVerackMessage(); | CDataStream message = CreateVerackMessage(); | ||||
return CSeederNode::ProcessMessage(VERACK_COMMAND, message); | return CSeederNode::ProcessMessage(VERACK_COMMAND, message); | ||||
} else { | } else if (strCommand == ADDR_COMMAND) { | ||||
CDataStream message = CreateAddrMessage(); | CDataStream message = CreateAddrMessage(); | ||||
return CSeederNode::ProcessMessage(ADDR_COMMAND, message); | return CSeederNode::ProcessMessage(ADDR_COMMAND, message); | ||||
} else { | |||||
// strCommand == HEADERS_COMMAND | |||||
CDataStream message = CreateHeadersMessage(); | |||||
return CSeederNode::ProcessMessage(HEADERS_COMMAND, message); | |||||
} | } | ||||
} | } | ||||
size_t getAddrListSize() { return vAddr.size(); } | size_t getAddrListSize() { return vAddr.size(); } | ||||
private: | private: | ||||
CDataStream CreateVersionMessage() { | CDataStream CreateVersionMessage() { | ||||
CDataStream payload(SER_NETWORK, 0); | CDataStream payload(SER_NETWORK, 0); | ||||
Show All 27 Lines | CDataStream CreateAddrMessage() { | ||||
std::vector<CAddress> sendAddrs; | std::vector<CAddress> sendAddrs; | ||||
for (int i = 0; i < nAddrsToSend; i++) { | for (int i = 0; i < nAddrsToSend; i++) { | ||||
sendAddrs.push_back(vAddr[0]); | sendAddrs.push_back(vAddr[0]); | ||||
} | } | ||||
payload << sendAddrs; | payload << sendAddrs; | ||||
return payload; | return payload; | ||||
} | } | ||||
CDataStream CreateHeadersMessage() { | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
uint8_t numberOfHeaders = | |||||
headersMessageContent == SEND_NO_HEADERS ? 0 : 1; | |||||
payload << numberOfHeaders; | |||||
// 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()); | |||||
uint256 previousBlockHash; | |||||
if (headersMessageContent == SEND_WRONG_CHAIN_HEADER) { | |||||
previousBlockHash = garbageHash; | |||||
} else { | |||||
previousBlockHash = CSeederNode::networkParams->Checkpoints() | |||||
.mapCheckpoints.rbegin() | |||||
->second; | |||||
} | |||||
uint32_t garbageTimeStamp = 0; | |||||
uint32_t garbageBits = 0; | |||||
uint32_t garbageNonce = 0; | |||||
payload << nVersion; | |||||
// prev_block | |||||
payload << previousBlockHash; | |||||
// merkle_root | |||||
payload << garbageHash; | |||||
// timestamp | |||||
payload << garbageTimeStamp; | |||||
// bits | |||||
payload << garbageBits; | |||||
// nonce | |||||
payload << garbageNonce; | |||||
// txn_count | |||||
payload << HEADERS_TXN_COUNT; | |||||
return payload; | |||||
} | |||||
std::vector<CAddress> vAddr; | std::vector<CAddress> vAddr; | ||||
int nAddrsToSend; | int nAddrsToSend; | ||||
int32_t nVersion; | int32_t nVersion; | ||||
int headersMessageContent; | |||||
}; | }; | ||||
BOOST_AUTO_TEST_CASE(parse_name_happy_path) { | BOOST_AUTO_TEST_CASE(parse_name_happy_path) { | ||||
const std::string messageQueryName = "www.mydomain.com"; | const std::string messageQueryName = "www.mydomain.com"; | ||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | ||||
CreateDNSQuestion(messageQueryName); | CreateDNSQuestion(messageQueryName); | ||||
std::array<char, QUERY_NAME_BUFFER_LENGTH> queryName; | std::array<char, QUERY_NAME_BUFFER_LENGTH> queryName; | ||||
queryName.fill(0); | queryName.fill(0); | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(seeder_node_addr_test_past_soft_cap) { | ||||
// vAddr starts with 1 entry and trys to add 1001 more. Only 1000 are | // vAddr starts with 1 entry and trys to add 1001 more. Only 1000 are | ||||
// actually added. | // actually added. | ||||
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(VADDR_SOFT_CAP + 1, testNode.getAddrListSize()); | BOOST_CHECK_EQUAL(VADDR_SOFT_CAP + 1, testNode.getAddrListSize()); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(seeder_node_headers_test_correct_chain) { | |||||
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, 0, SEND_GOOD_HEADER); | |||||
bool ret = testNode.TestProcessMessage(HEADERS_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
BOOST_CHECK_EQUAL(testNode.GetBan(), 0); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_headers_test_wrong_chain) { | |||||
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, 0, SEND_WRONG_CHAIN_HEADER); | |||||
bool ret = testNode.TestProcessMessage(HEADERS_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, true); | |||||
BOOST_CHECK_EQUAL(testNode.GetBan(), 100000); | |||||
} | |||||
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, 0, SEND_NO_HEADERS); | |||||
bool ret = testNode.TestProcessMessage(HEADERS_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, true); | |||||
BOOST_CHECK_EQUAL(testNode.GetBan(), 100000); | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |