diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h index 5613653f2..0a14c3e36 100644 --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -1,75 +1,81 @@ // Copyright (c) 2017-2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SEEDER_BITCOIN_H #define BITCOIN_SEEDER_BITCOIN_H #include #include #include #include #include static inline unsigned short GetDefaultPort() { return Params().GetDefaultPort(); } // After the 1000th addr, the seeder will only add one more address per addr // message. static const unsigned int ADDR_SOFT_CAP = 1000; enum class PeerMessagingState { AwaitingMessages, Finished, }; +namespace { +class CSeederNodeTest; +} + class CSeederNode { + friend class ::CSeederNodeTest; + private: SOCKET sock; CDataStream vSend; CDataStream vRecv; uint32_t nHeaderStart; uint32_t nMessageStart; int nVersion; std::string strSubVer; int nStartingHeight; std::vector *vAddr; int ban; int64_t doneAfter; CAddress you; int GetTimeout() { return you.IsTor() ? 120 : 30; } void BeginMessage(const char *pszCommand); void AbortMessage(); void EndMessage(); void Send(); void PushVersion(); bool ProcessMessages(); protected: PeerMessagingState ProcessMessage(std::string strCommand, CDataStream &recv); public: CSeederNode(const CService &ip, std::vector *vAddrIn); bool Run(); int GetBan() { return ban; } int GetClientVersion() { return nVersion; } std::string GetClientSubVersion() { return strSubVer; } int GetStartingHeight() { return nStartingHeight; } }; #endif // BITCOIN_SEEDER_BITCOIN_H diff --git a/src/seeder/test/p2p_messaging_tests.cpp b/src/seeder/test/p2p_messaging_tests.cpp index c4436bd76..cecc9f754 100644 --- a/src/seeder/test/p2p_messaging_tests.cpp +++ b/src/seeder/test/p2p_messaging_tests.cpp @@ -1,132 +1,148 @@ // Copyright (c) 2019 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::ostream &operator<<(std::ostream &os, const PeerMessagingState &state) { os << to_integral(state); return os; } -class TestCSeederNode : public CSeederNode { +namespace { +class CSeederNodeTest : public CSeederNode { public: - TestCSeederNode(const CService &service, std::vector *vAddrIn) - : CSeederNode(service, vAddrIn) { - SelectParams(CBaseChainParams::REGTEST); - } + CSeederNodeTest(const CService &service, std::vector *vAddrIn) + : CSeederNode(service, vAddrIn) {} void TestProcessMessage(const std::string &strCommand, CDataStream &message, PeerMessagingState expectedState) { - PeerMessagingState ret = - CSeederNode::ProcessMessage(strCommand, message); + PeerMessagingState ret = ProcessMessage(strCommand, message); BOOST_CHECK_EQUAL(ret, expectedState); } + + CDataStream getSendBuffer() { return vSend; } }; +} // namespace static const unsigned short SERVICE_PORT = 18444; struct SeederTestingSetup { SeederTestingSetup() { + SelectParams(CBaseChainParams::REGTEST); CNetAddr ip; ip.SetInternal("bitcoin.test"); CService service = {ip, SERVICE_PORT}; vAddr.emplace_back(service, ServiceFlags()); - testNode = std::make_unique(service, &vAddr); + testNode = std::make_unique(service, &vAddr); } std::vector vAddr; - std::unique_ptr testNode; + std::unique_ptr testNode; }; BOOST_FIXTURE_TEST_SUITE(p2p_messaging_tests, SeederTestingSetup) 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 const int SEEDER_INIT_VERSION = 0; -BOOST_AUTO_TEST_CASE(seeder_node_version_test) { +BOOST_AUTO_TEST_CASE(process_version_msg) { CService serviceFrom; CAddress addrFrom(serviceFrom, ServiceFlags(NODE_NETWORK)); CDataStream versionMessage = CreateVersionMessage( GetTime(), 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(process_verack_msg) { + CDataStream verackMessage(SER_NETWORK, 0); + verackMessage.SetVersion(INIT_PROTO_VERSION); + testNode->TestProcessMessage(NetMsgType::VERACK, verackMessage, + PeerMessagingState::AwaitingMessages); + + // Seeder should respond with an ADDR message + const CMessageHeader::MessageMagic netMagic = Params().NetMagic(); + CMessageHeader header(netMagic); + testNode->getSendBuffer() >> header; + BOOST_CHECK(header.IsValidWithoutConfig(netMagic)); + BOOST_CHECK_EQUAL(header.GetCommand(), NetMsgType::GETADDR); +} + static CDataStream CreateAddrMessage(std::vector sendAddrs, uint32_t nVersion = INIT_PROTO_VERSION) { CDataStream payload(SER_NETWORK, 0); payload.SetVersion(nVersion); payload << sendAddrs; return payload; } -BOOST_AUTO_TEST_CASE(seeder_node_addr_test) { +BOOST_AUTO_TEST_CASE(process_addr_msg) { // 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()); // 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()