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) | ||||
const int BUFFER_LENGTH = 512; | const int BUFFER_LENGTH = 512; | ||||
const int QNAME_BUFFER_LENGTH = 256; | const int QNAME_BUFFER_LENGTH = 256; | ||||
const int SIZE_OF_DNS_MESSAGE_HEADER = 12; | const int SIZE_OF_DNS_MESSAGE_HEADER = 12; | ||||
const int SIZE_OF_QTYPE = 2; | const int SIZE_OF_QTYPE = 2; | ||||
const int SIZE_OF_QCLASS = 2; | const int SIZE_OF_QCLASS = 2; | ||||
const unsigned short MAINNET_PORT = 8333; | |||||
const unsigned short TESTNET_PORT = 18333; | |||||
const std::string VERACK_COMMAND = "verack"; | |||||
const std::string VERSION_COMMAND = "version"; | |||||
const std::string ADDR_COMMAND = "addr"; | |||||
std::string SEED = "seed.bitcoinabc.org"; | |||||
// Builds dummy DNS query message | // Builds dummy DNS query message | ||||
std::array<uint8_t, BUFFER_LENGTH> CreateDNSMessage(const std::string &qname) { | std::array<uint8_t, BUFFER_LENGTH> CreateDNSMessage(const std::string &qname) { | ||||
std::stringstream querryhex; | std::stringstream querryhex; | ||||
querryhex.clear(); | querryhex.clear(); | ||||
querryhex << std::hex << std::setfill('0'); | querryhex << std::hex << std::setfill('0'); | ||||
// ID | // ID | ||||
querryhex << std::setw(2) << static_cast<uint8_t>(0); | querryhex << std::setw(2) << static_cast<uint8_t>(0); | ||||
Show All 37 Lines | std::array<uint8_t, BUFFER_LENGTH> CreateDNSMessage(const std::string &qname) { | ||||
querryhex << std::setw(2) << static_cast<uint8_t>(1); | querryhex << std::setw(2) << static_cast<uint8_t>(1); | ||||
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), versionMessage(SER_NETWORK, 0), | |||||
versionHeader(netMagic, VERSION_COMMAND.c_str(), 0), | |||||
verackMessage(SER_NETWORK, 0), | |||||
verackHeader(netMagic, VERACK_COMMAND.c_str(), 0), | |||||
addrMessage(SER_NETWORK, 0), | |||||
addrHeader(netMagic, ADDR_COMMAND.c_str(), 0) {} | |||||
bool TestProcessMessage(const std::string &strCommand) { | |||||
if (strCommand == VERSION_COMMAND) { | |||||
CreateVersionMessage(); | |||||
return CSeederNode::ProcessMessage(VERSION_COMMAND, versionMessage); | |||||
} else if (strCommand == VERACK_COMMAND) { | |||||
CreateVerackMessage(); | |||||
return CSeederNode::ProcessMessage(VERACK_COMMAND, verackMessage); | |||||
} else { | |||||
// strCommand == ADDR_COMMAND | |||||
CreateAddrMessage(); | |||||
return CSeederNode::ProcessMessage(ADDR_COMMAND, addrMessage); | |||||
} | |||||
} | |||||
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; | |||||
versionMessage.erase(versionMessage.begin(), versionMessage.end()); | |||||
versionMessage.SetVersion(nVersion); | |||||
versionMessage += payload; | |||||
versionHeader.nMessageSize = payload.size(); | |||||
uint256 hash = Hash(payload.begin(), payload.end()); | |||||
memcpy(versionHeader.pchChecksum, &hash, versionHeader.CHECKSUM_SIZE); | |||||
} | |||||
// Verack message consists of only the header with VERACK_COMMAND as the | |||||
// command string. | |||||
void CreateVerackMessage() { | |||||
verackHeader.nMessageSize = 0; | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
payload << static_cast<uint32_t>(0); | |||||
uint256 hash = Hash(payload.begin(), payload.end()); | |||||
memcpy(verackHeader.pchChecksum, &hash, verackHeader.CHECKSUM_SIZE); | |||||
verackMessage.erase(verackMessage.begin(), verackMessage.end()); | |||||
verackMessage.SetVersion(nVersion); | |||||
verackMessage << verackHeader.pchMessageStart | |||||
<< verackHeader.GetCommand() << verackHeader.nMessageSize | |||||
<< verackHeader.pchChecksum; | |||||
} | |||||
void CreateAddrMessage() { | |||||
CDataStream payload(SER_NETWORK, 0); | |||||
payload.SetVersion(nVersion); | |||||
payload << static_cast<uint8_t>(1); | |||||
// Insert timestamp and then net_addr(s) | |||||
payload << vAddr[0]; | |||||
addrMessage.erase(addrMessage.begin(), addrMessage.end()); | |||||
addrMessage += payload; | |||||
addrHeader.nMessageSize = payload.size(); | |||||
uint256 hash = Hash(payload.begin(), payload.end()); | |||||
memcpy(addrHeader.pchChecksum, &hash, addrHeader.CHECKSUM_SIZE); | |||||
} | |||||
std::vector<CAddress> vAddr; | |||||
int32_t nVersion; | |||||
CDataStream versionMessage; | |||||
CMessageHeader versionHeader; | |||||
CDataStream verackMessage; | |||||
CMessageHeader verackHeader; | |||||
CDataStream addrMessage; | |||||
CMessageHeader addrHeader; | |||||
}; | |||||
BOOST_AUTO_TEST_CASE(parse_name_simple) { | BOOST_AUTO_TEST_CASE(parse_name_simple) { | ||||
const std::string messageQName = "www.mydomain.com"; | const std::string messageQName = "www.mydomain.com"; | ||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage; | std::array<uint8_t, BUFFER_LENGTH> dnsMessage; | ||||
dnsMessage.fill(0); | dnsMessage.fill(0); | ||||
dnsMessage = CreateDNSMessage(messageQName); | dnsMessage = CreateDNSMessage(messageQName); | ||||
std::array<char, QNAME_BUFFER_LENGTH> qname; | std::array<char, QNAME_BUFFER_LENGTH> qname; | ||||
qname.fill(0); | qname.fill(0); | ||||
size_t insize = QNAME_BUFFER_LENGTH; | size_t insize = QNAME_BUFFER_LENGTH; | ||||
Show All 38 Lines | BOOST_AUTO_TEST_CASE(parse_name_simple) { | ||||
messageIndex = dnsMessage.data() + SIZE_OF_DNS_MESSAGE_HEADER; | messageIndex = dnsMessage.data() + SIZE_OF_DNS_MESSAGE_HEADER; | ||||
messageEnd = dnsMessage.data() + SIZE_OF_DNS_MESSAGE_HEADER + | messageEnd = dnsMessage.data() + SIZE_OF_DNS_MESSAGE_HEADER + | ||||
tooLongQName.size() + 1 + SIZE_OF_QTYPE + SIZE_OF_QCLASS; | tooLongQName.size() + 1 + SIZE_OF_QTYPE + SIZE_OF_QCLASS; | ||||
ret = parse_name(&messageIndex, messageEnd, dnsMessage.data(), qname.data(), | ret = parse_name(&messageIndex, messageEnd, dnsMessage.data(), qname.data(), | ||||
insize); | insize); | ||||
BOOST_CHECK_EQUAL(ret, -1); | BOOST_CHECK_EQUAL(ret, -1); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(seeder_node_tests) { | |||||
CNetAddr ip; | |||||
LookupHost(SEED.c_str(), ip, true); | |||||
const CService service(ip, MAINNET_PORT); | |||||
CAddress addr(service, ServiceFlags()); | |||||
fprintf(stderr, "addr time: %d", addr.nTime); | |||||
std::vector<CAddress> vAddr(999, addr); | |||||
TestCSeederNode testNode(service, vAddr); | |||||
bool ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
ret = testNode.TestProcessMessage(VERACK_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
// vAddr adds new addresses up to the 1000th | |||||
ret = testNode.TestProcessMessage(ADDR_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
BOOST_CHECK_EQUAL(1000, testNode.getAddrListSize()); | |||||
// After the 1000th, only one is added and the rest are ignored | |||||
ret = testNode.TestProcessMessage(ADDR_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, true); | |||||
BOOST_CHECK_EQUAL(1001, testNode.getAddrListSize()); | |||||
testNode.setVersion(10300); | |||||
ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
testNode.setVersion(106); | |||||
ret = testNode.TestProcessMessage(VERSION_COMMAND); | |||||
BOOST_CHECK_EQUAL(ret, false); | |||||
} | |||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |