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 int SEEDER_INIT_VERSION = 0; +// After the 1000th addr, the seeder will only add one more address per addr +// message. +static const int ADDR_SOFT_CAP = 1000; + +enum PeerMessagingState : bool { + Finished = true, + AwaitingMessages = false, +}; + +static CDataStream +CreateVersionMessage(int64_t now, CAddress addrTo, CAddress addrFrom, + int32_t start_height, uint32_t nVersion, + uint64_t nonce = 0, + std::string user_agent = "/bitcoin-cash-seeder:0.15/") { + 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; +} + +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, + PeerMessagingState state) { + bool ret = CSeederNode::ProcessMessage(strCommand, message); + BOOST_CHECK_EQUAL(ret, bool(state)); + } +}; + +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(), INIT_PROTO_VERSION); + + // Verify the version is set as the initial value + BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(), + SEEDER_INIT_VERSION); + testNode->TestProcessMessage(NetMsgType::VERSION, versionMessage, + PeerMessagingState::AwaitingMessages); + // Verify the version has been updated + BOOST_CHECK_EQUAL(testNode->CSeederNode::GetClientVersion(), + versionMessage.GetVersion()); +} + +BOOST_AUTO_TEST_CASE(seeder_node_addr_test) { + // vAddrs starts with 1 entry. + std::vector sendAddrs(ADDR_SOFT_CAP - 1, vAddr[0]); + + // Happy path + // addrs are added normally to vAddr until ADDR_SOFT_CAP is reached. + // Add addrs up to the soft cap. + CDataStream addrMessage = CreateAddrMessage(sendAddrs); + BOOST_CHECK_EQUAL(1, vAddr.size()); + testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage, + PeerMessagingState::AwaitingMessages); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP, vAddr.size()); + + // ADDR_SOFT_CAP is exceeded + sendAddrs.resize(1); + addrMessage = CreateAddrMessage(sendAddrs); + testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage, + PeerMessagingState::Finished); + BOOST_CHECK_EQUAL(ADDR_SOFT_CAP + 1, vAddr.size()); -BOOST_AUTO_TEST_CASE(test_stub) { - BOOST_CHECK_EQUAL(true, true); + // Test the seeder's behavior after ADDR_SOFT_CAP addrs + // Only one addr per ADDR message will be added, the rest are ignored + size_t expectedSize = vAddr.size() + 1; + for (size_t i = 1; i < 10; i++) { + sendAddrs.resize(i, sendAddrs[0]); + addrMessage = CreateAddrMessage(sendAddrs); + testNode->TestProcessMessage(NetMsgType::ADDR, addrMessage, + PeerMessagingState::Finished); + BOOST_CHECK_EQUAL(expectedSize, vAddr.size()); + ++expectedSize; + } } BOOST_AUTO_TEST_SUITE_END()