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 += $(LIBUNIVALUE) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) + +seeder_test_test_bitcoin_seeder_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ + $(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) diff --git a/src/seeder/CMakeLists.txt b/src/seeder/CMakeLists.txt --- a/src/seeder/CMakeLists.txt +++ b/src/seeder/CMakeLists.txt @@ -11,11 +11,9 @@ ) target_link_libraries(seeder-net - common + bitcoinconsensus ) -target_include_directories(seeder-net PUBLIC .) - add_executable(bitcoin-seeder main.cpp) target_link_libraries(bitcoin-seeder seeder-net) diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -53,10 +53,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/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,15 +4,29 @@ #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include +#include #include #include #include #include +#include + +const std::function G_TRANSLATION_FUN = nullptr; BOOST_AUTO_TEST_SUITE(seeder) @@ -21,6 +35,12 @@ const int SIZE_OF_DNS_MESSAGE_HEADER = 12; const int SIZE_OF_QTYPE = 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 std::array CreateDNSMessage(const std::string &qname) { @@ -74,6 +94,100 @@ return messageBuffer; } +class TestCSeederNode : public CSeederNode { +public: + TestCSeederNode(const CService &service, std::vector &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(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(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(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 vAddr; + int32_t nVersion; + CDataStream versionMessage; + CMessageHeader versionHeader; + CDataStream verackMessage; + CMessageHeader verackHeader; + CDataStream addrMessage; + CMessageHeader addrHeader; +}; + BOOST_AUTO_TEST_CASE(parse_name_simple) { const std::string messageQName = "www.mydomain.com"; std::array dnsMessage; @@ -128,4 +242,37 @@ 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 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()