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 <hash.h> | |||||
#include <netbase.h> | |||||
#include <protocol.h> | |||||
#include <seeder/bitcoin.h> | |||||
#include <seeder/db.h> | |||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
#include <serialize.h> | |||||
#include <streams.h> | |||||
#include <uint256.h> | |||||
#include <util/system.h> | |||||
#include <version.h> | |||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <array> | #include <array> | ||||
#include <functional> | |||||
#include <iomanip> | #include <iomanip> | ||||
#include <iostream> | #include <iostream> | ||||
#include <sstream> | #include <sstream> | ||||
#include <string> | #include <string> | ||||
#include <vector> | |||||
const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | |||||
BOOST_AUTO_TEST_SUITE(seeder) | BOOST_AUTO_TEST_SUITE(seeder) | ||||
static const int BUFFER_LENGTH = 512; | static const int BUFFER_LENGTH = 512; | ||||
static const int QUALIFIER_NAME_BUFFER_LENGTH = 256; | static const int QUALIFIER_NAME_BUFFER_LENGTH = 256; | ||||
static const int SIZE_OF_QUESTION_TYPE = 2; | static const int SIZE_OF_QUESTION_TYPE = 2; | ||||
static const int SIZE_OF_QUESTION_CLASS = 2; | static const int SIZE_OF_QUESTION_CLASS = 2; | ||||
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 std::string VERACK_COMMAND = "verack"; | |||||
static const std::string VERSION_COMMAND = "version"; | |||||
static const std::string ADDR_COMMAND = "addr"; | |||||
static const std::string SEED = "seed.bitcoinabc.org"; | |||||
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(); | ||||
querryhex << std::hex << std::setfill('0'); | querryhex << std::hex << std::setfill('0'); | ||||
Show All 26 Lines | CreateDNSQuestion(const std::string &qualifierName) { | ||||
querryhex << QUESTION_CLASS; | querryhex << QUESTION_CLASS; | ||||
std::array<uint8_t, BUFFER_LENGTH> messageBuffer; | std::array<uint8_t, BUFFER_LENGTH> messageBuffer; | ||||
messageBuffer.fill(0); | messageBuffer.fill(0); | ||||
querryhex >> std::hex >> messageBuffer.data(); | querryhex >> std::hex >> messageBuffer.data(); | ||||
return messageBuffer; | return messageBuffer; | ||||
} | } | ||||
class TestCSeederNode : public CSeederNode { | |||||
public: | |||||
TestCSeederNode(const CService &service, std::vector<CAddress> &vAddrIn) | |||||
: CSeederNode(service, &vAddr), vAddr(vAddrIn), | |||||
nVersion(INIT_PROTO_VERSION), message(SER_NETWORK, 0), | |||||
header(netMagic, ADDR_COMMAND.c_str(), 0) {} | |||||
bool TestProcessMessage(const std::string &strCommand) { | |||||
if (strCommand == VERSION_COMMAND) { | |||||
CreateVersionMessage(); | |||||
return CSeederNode::ProcessMessage(VERSION_COMMAND, message); | |||||
} else if (strCommand == VERACK_COMMAND) { | |||||
CreateVerackMessage(); | |||||
return CSeederNode::ProcessMessage(VERACK_COMMAND, message); | |||||
} else { | |||||
// strCommand == ADDR_COMMAND | |||||
CreateAddrMessage(); | |||||
return CSeederNode::ProcessMessage(ADDR_COMMAND, message); | |||||
} | |||||
} | |||||
void setVersion(int32_t version) { nVersion = version; } | |||||
size_t getAddrListSize() { return vAddr.size(); } | |||||
private: | |||||
void CreateVersionMessage() { | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
ServiceFlags service = ServiceFlags(NODE_NETWORK); | |||||
int64_t now = time(nullptr); | |||||
uint64_t nonce = 0; | |||||
uint16_t user_agent = 0; | |||||
CAddress addrTo = vAddr[0]; | |||||
CService serviceFrom; | |||||
CAddress addrFrom(serviceFrom, | |||||
ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); | |||||
int32_t start_height = GetRequireHeight(false); | |||||
payload << nVersion << static_cast<uint64_t>(service) << now << addrTo | |||||
<< addrFrom << nonce << user_agent << start_height; | |||||
message.erase(message.begin(), message.end()); | |||||
message.SetVersion(nVersion); | |||||
message += payload; | |||||
header.nMessageSize = payload.size(); | |||||
uint256 hash = Hash(payload.begin(), payload.end()); | |||||
memcpy(header.pchChecksum, &hash, header.CHECKSUM_SIZE); | |||||
} | |||||
// Verack message consists of only the header with VERACK_COMMAND as the | |||||
// command string. | |||||
void CreateVerackMessage() { | |||||
header.nMessageSize = 0; | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
payload << VERACK_PAYLOAD; | |||||
uint256 hash = Hash(payload.begin(), payload.end()); | |||||
memcpy(header.pchChecksum, &hash, header.CHECKSUM_SIZE); | |||||
message.erase(message.begin(), message.end()); | |||||
message.SetVersion(nVersion); | |||||
message << header.pchMessageStart << header.GetCommand() | |||||
<< header.nMessageSize << header.pchChecksum; | |||||
} | |||||
void CreateAddrMessage() { | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
payload << vAddr; | |||||
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; | |||||
int32_t nVersion; | |||||
CDataStream message; | |||||
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"; | ||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | ||||
CreateDNSQuestion(messageQualifierName); | CreateDNSQuestion(messageQualifierName); | ||||
std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | ||||
qualifierName.fill(0); | qualifierName.fill(0); | ||||
size_t writeBufferSize = QUALIFIER_NAME_BUFFER_LENGTH; | size_t writeBufferSize = QUALIFIER_NAME_BUFFER_LENGTH; | ||||
const uint8_t *messageBegin = dnsMessage.data(); | const uint8_t *messageBegin = dnsMessage.data(); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(parse_name_field_name_too_long) { | ||||
const uint8_t *messageBegin = dnsMessage.data(); | const uint8_t *messageBegin = dnsMessage.data(); | ||||
const uint8_t *messageEnd = dnsMessage.data() + tooLongQName.size() + 1 + | const uint8_t *messageEnd = dnsMessage.data() + tooLongQName.size() + 1 + | ||||
SIZE_OF_QUESTION_TYPE + SIZE_OF_QUESTION_CLASS; | SIZE_OF_QUESTION_TYPE + SIZE_OF_QUESTION_CLASS; | ||||
int ret = parse_name(&messageBegin, messageEnd, dnsMessage.data(), | int ret = parse_name(&messageBegin, messageEnd, dnsMessage.data(), | ||||
qualifierName.data(), writeBufferSize); | qualifierName.data(), writeBufferSize); | ||||
BOOST_CHECK_EQUAL(ret, -1); | BOOST_CHECK_EQUAL(ret, -1); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(seeder_node_default_version_tests) { | |||||
CNetAddr ip; | |||||
LookupHost(SEED.c_str(), ip, true); | |||||
const CService service(ip, MAINNET_PORT); | |||||
CAddress addr(service, ServiceFlags()); | |||||
std::vector<CAddress> vAddr(999, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
bool ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_version_10300_tests) { | |||||
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); | |||||
testNode.setVersion(10300); | |||||
bool ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_version_106_tests) { | |||||
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); | |||||
testNode.setVersion(106); | |||||
bool ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_verack_tests) { | |||||
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(VERACK_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_addr_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(ADDR_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
BOOST_CHECK_EQUAL(2, testNode.getAddrListSize()); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_addr_test_until_full) { | |||||
CNetAddr ip; | |||||
LookupHost(SEED.c_str(), ip, true); | |||||
const CService service(ip, MAINNET_PORT); | |||||
CAddress addr(service, ServiceFlags()); | |||||
std::vector<CAddress> vAddr(500, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
// Maximum number of addrs is 1000. All addrs are added until the 1000th. | |||||
bool ret = testNode.TestProcessMessage(ADDR_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
BOOST_CHECK_EQUAL(1000, testNode.getAddrListSize()); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(seeder_node_addr_test_full_vaddr) { | |||||
CNetAddr ip; | |||||
LookupHost(SEED.c_str(), ip, true); | |||||
const CService service(ip, MAINNET_PORT); | |||||
CAddress addr(service, ServiceFlags()); | |||||
std::vector<CAddress> vAddr(1000, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
// After the 1000th, only one is added and the rest are ignored | |||||
bool ret = testNode.TestProcessMessage(ADDR_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, true); | |||||
BOOST_CHECK_EQUAL(1001, testNode.getAddrListSize()); | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |