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,134 @@ #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; + +enum AddrCapacity : bool { + AddrFull = true, + AddrNotFull = false, +}; + +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 serviceflags = ServiceFlags(NODE_NETWORK); + payload << nVersion << uint64_t(serviceflags) << 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, CDataStream &message, + AddrCapacity addrCap) { + bool ret = CSeederNode::ProcessMessage(strCommand, message); + BOOST_CHECK_EQUAL(ret, addrCap); + } +}; + +struct SeederTestingSetup { + SeederTestingSetup() { + CNetAddr ip; + ip.SetInternal("bitcoin.test"); + CService service = {ip, SERVICE_PORT}; + vAddr.emplace_back(service, ServiceFlags()); + testNode = std::make_unique(service, &vAddr); + } + + std::vector vAddr; + std::unique_ptr testNode; +}; + +BOOST_FIXTURE_TEST_SUITE(seeder_tests, SeederTestingSetup) + +BOOST_AUTO_TEST_CASE(seeder_node_version_test) { + CService serviceFrom; + CAddress addrFrom(serviceFrom, + ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); + CDataStream versionMessage = CreateVersionMessage( + time(nullptr), vAddr[0], addrFrom, GetRequireHeight()); + + testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage, + AddrCapacity::AddrNotFull); + int version = versionMessage.GetVersion() < PROTOCOL_VERSION + ? versionMessage.GetVersion() + : PROTOCOL_VERSION; + BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(), version); +} + +BOOST_AUTO_TEST_CASE(seeder_node_verack_test) { + CDataStream verackMessage = CreateVerackMessage(); + testNode->TestProcessMessage(NetMsgType::VERACK, verackMessage, + AddrCapacity::AddrNotFull); +} + +BOOST_AUTO_TEST_CASE(seeder_node_addr_test) { + // addrs starts with 1 entry. Only need to add ADDR_SOFT_CAP - 1 + std::vector sendAddrs(ADDR_SOFT_CAP - 1, vAddr[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, vAddr.size()); + testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage, + AddrCapacity::AddrNotFull); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, vAddr.size()); -BOOST_AUTO_TEST_CASE(test_stub) { - BOOST_CHECK_EQUAL(true, true); + // Test the seeder's addr softcap + // After the VADDR_SOFT_CAPth, only one is added and the rest are + // ignored + addrMessage = CreateAddrMessage(sendAddrs); + testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage, + AddrCapacity::AddrFull); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, vAddr.size()); } BOOST_AUTO_TEST_SUITE_END()