diff --git a/src/Makefile.seedertest.include b/src/Makefile.seedertest.include --- a/src/Makefile.seedertest.include +++ b/src/Makefile.seedertest.include @@ -12,7 +12,10 @@ seeder/test/seeder_tests.cpp seeder_test_test_bitcoin_seeder_LDADD = $(LIBBITCOIN_SEEDER) -seeder_test_test_bitcoin_seeder_LDADD += $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) + +seeder_test_test_bitcoin_seeder_LDADD += $(LIBBITCOIN_COMMON) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UTIL) \ + $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(CRYPTO_LIBS) + seeder_test_test_bitcoin_seeder_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) seeder_test_test_bitcoin_seeder_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -48,10 +48,11 @@ void GotVersion(); - bool ProcessMessage(std::string strCommand, CDataStream &recv); - bool ProcessMessages(); +protected: + bool ProcessMessage(std::string strCommand, CDataStream &recv); + public: CSeederNode(const CService &ip, std::vector *vAddrIn); diff --git a/src/seeder/test/CMakeLists.txt b/src/seeder/test/CMakeLists.txt --- a/src/seeder/test/CMakeLists.txt +++ b/src/seeder/test/CMakeLists.txt @@ -14,5 +14,7 @@ ) target_link_libraries(test_bitcoin-seeder + common + bitcoinconsensus seeder-netprocessing ) 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,12 +4,143 @@ #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +const std::function G_TRANSLATION_FUN = nullptr; + #include -BOOST_AUTO_TEST_SUITE(seeder_tests) +static const unsigned short SERVICE_PORT = 18444; +static const uint32_t VERACK_PAYLOAD = 0; +// After the 1000th addr, the seeder will only add one more address from an addr +// message. +static const int ADDR_SOFT_CAP = 1000; + +static CDataStream +CreateVersionMessage(int64_t now, CAddress addrTo, CAddress addrFrom, + int32_t start_height, uint64_t nonce = 0, + std::string user_agent = "/bitcoin-cash-seeder:0.15/", + uint32_t nVersion = INIT_PROTO_VERSION) { + CDataStream payload(SER_NETWORK, 0); + payload.SetVersion(nVersion); + ServiceFlags service = ServiceFlags(NODE_NETWORK); + payload << nVersion << uint64_t(service) << now << addrTo << addrFrom + << nonce << user_agent << start_height; + return payload; +} + +// Verack message consists of only the header with NetMsgType::VERACK as the +// command string. +static CDataStream CreateVerackMessage(uint32_t nVersion = INIT_PROTO_VERSION) { + CDataStream payload(SER_NETWORK, 0); + payload.SetVersion(nVersion); + payload << VERACK_PAYLOAD; + return payload; +} + +static CDataStream CreateAddrMessage(std::vector sendAddrs, + uint32_t nVersion = INIT_PROTO_VERSION) { + CDataStream payload(SER_NETWORK, 0); + payload.SetVersion(nVersion); + payload << sendAddrs; + return payload; +} + +class TestCSeederNode : public CSeederNode { +public: + TestCSeederNode(const CService &service, std::vector *vAddrIn) + : CSeederNode(service, vAddrIn) { + SelectParams(CBaseChainParams::REGTEST); + } + + void TestProcessMessage(const std::string &strCommand, + std::vector &addrs) { + if (strCommand == NetMsgType::VERSION) { + CService serviceFrom; + CAddress addrFrom(serviceFrom, + ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); + CDataStream versionMessage = CreateVersionMessage( + time(nullptr), addrs[0], addrFrom, GetRequireHeight()); + + bool ret = CSeederNode::ProcessMessage(strCommand, versionMessage); + BOOST_CHECK_EQUAL(ret, false); + int version = versionMessage.GetVersion() < PROTOCOL_VERSION + ? versionMessage.GetVersion() + : PROTOCOL_VERSION; + BOOST_CHECK_EQUAL(CSeederNode::GetClientVersion(), version); + return; + } + if (strCommand == NetMsgType::VERACK) { + CDataStream verackMessage = CreateVerackMessage(); + + bool ret = + CSeederNode::ProcessMessage(NetMsgType::VERACK, verackMessage); + BOOST_CHECK_EQUAL(ret, false); + return; + } + if (strCommand == NetMsgType::ADDR) { + // addrs starts with 1 entry. Only need to add ADDR_SOFT_CAP - 1 + std::vector sendAddrs(ADDR_SOFT_CAP - 1, addrs[0]); + CDataStream addrMessage = CreateAddrMessage(sendAddrs); + + // Happy path + // Maximum number of addrs is ADDR_SOFT_CAP. All addrs are added + // until the ADDR_SOFT_CAPth. + BOOST_CHECK_EQUAL(1, addrs.size()); + bool ret = + CSeederNode::ProcessMessage(NetMsgType::ADDR, addrMessage); + BOOST_CHECK_EQUAL(ret, false); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, addrs.size()); + + // Test the seeder's addr softcap + // After the VADDR_SOFT_CAPth, only one is added and the rest are + // ignored + addrMessage = CreateAddrMessage(sendAddrs); + ret = CSeederNode::ProcessMessage(NetMsgType::ADDR, addrMessage); + BOOST_CHECK_EQUAL(ret, true); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, addrs.size()); + return; + } + } +}; + +struct SeederTestingSetup { + SeederTestingSetup() { + CNetAddr ip; + ip.SetInternal("bitcoin.test"); + service = {ip, SERVICE_PORT}; + vAddr.emplace_back(service, ServiceFlags()); + testNode = std::make_unique(service, &vAddr); + } + + std::vector vAddr; + CService service; + std::unique_ptr testNode; +}; + +BOOST_FIXTURE_TEST_SUITE(seeder_tests, SeederTestingSetup) + +BOOST_AUTO_TEST_CASE(seeder_node_version_test) { + testNode->TestProcessMessage(NetMsgType::VERSION, vAddr); +} + +BOOST_AUTO_TEST_CASE(seeder_node_verack_test) { + testNode->TestProcessMessage(NetMsgType::VERACK, vAddr); +} -BOOST_AUTO_TEST_CASE(test_stub) { - BOOST_CHECK_EQUAL(true, true); +BOOST_AUTO_TEST_CASE(seeder_node_addr_test) { + testNode->TestProcessMessage(NetMsgType::ADDR, vAddr); } BOOST_AUTO_TEST_SUITE_END()