diff --git a/src/seeder/CMakeLists.txt b/src/seeder/CMakeLists.txt --- a/src/seeder/CMakeLists.txt +++ b/src/seeder/CMakeLists.txt @@ -9,7 +9,7 @@ db.cpp dns.cpp ) -target_link_libraries(seeder-base common) +target_link_libraries(seeder-base server) add_executable(bitcoin-seeder main.cpp diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp --- a/src/seeder/bitcoin.cpp +++ b/src/seeder/bitcoin.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2019 The Bitcoin developers +// Copyright (c) 2017-2020 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -17,50 +18,6 @@ #define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL -static const uint32_t allones(-1); - -void CSeederNode::BeginMessage(const char *pszCommand) { - if (nHeaderStart != allones) { - AbortMessage(); - } - nHeaderStart = vSend.size(); - vSend << CMessageHeader(netMagic, pszCommand, 0); - nMessageStart = vSend.size(); - // tfm::format(std::cout, "%s: SEND %s\n", ToString(you), - // pszCommand); -} - -void CSeederNode::AbortMessage() { - if (nHeaderStart == allones) { - return; - } - vSend.resize(nHeaderStart); - nHeaderStart = allones; - nMessageStart = allones; -} - -void CSeederNode::EndMessage() { - if (nHeaderStart == allones) { - return; - } - uint32_t nSize = vSend.size() - nMessageStart; - memcpy((char *)&vSend[nHeaderStart] + - offsetof(CMessageHeader, nMessageSize), - &nSize, sizeof(nSize)); - if (vSend.GetVersion() >= 209) { - uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); - unsigned int nChecksum = 0; - memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(nMessageStart - nHeaderStart >= - offsetof(CMessageHeader, pchChecksum) + sizeof(nChecksum)); - memcpy((char *)&vSend[nHeaderStart] + - offsetof(CMessageHeader, pchChecksum), - &nChecksum, sizeof(nChecksum)); - } - nHeaderStart = allones; - nMessageStart = allones; -} - void CSeederNode::Send() { if (sock == INVALID_SOCKET) { return; @@ -77,20 +34,6 @@ } } -void CSeederNode::PushVersion() { - int64_t nTime = time(nullptr); - uint64_t nLocalNonce = BITCOIN_SEED_NONCE; - int64_t nLocalServices = 0; - CService myService; - CAddress me(myService, ServiceFlags(NODE_NETWORK)); - BeginMessage(NetMsgType::VERSION); - int nBestHeight = GetRequireHeight(); - std::string ver = "/bitcoin-cash-seeder:0.15/"; - vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me - << nLocalNonce << ver << nBestHeight; - EndMessage(); -} - PeerMessagingState CSeederNode::ProcessMessage(std::string strCommand, CDataStream &recv) { // tfm::format(std::cout, "%s: RECV %s\n", ToString(you), @@ -107,9 +50,9 @@ recv >> strSubVer; recv >> nStartingHeight; - BeginMessage(NetMsgType::VERACK); - EndMessage(); vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); + vSend += + MessageWriter::WriteMessage(vSend.GetVersion(), NetMsgType::VERACK); return PeerMessagingState::AwaitingMessages; } @@ -118,8 +61,8 @@ // tfm::format(std::cout, "\n%s: version %i\n", ToString(you), // nVersion); if (vAddr) { - BeginMessage(NetMsgType::GETADDR); - EndMessage(); + vSend += MessageWriter::WriteMessage(vSend.GetVersion(), + NetMsgType::GETADDR); doneAfter = time(nullptr) + GetTimeout(); } else { doneAfter = time(nullptr) + 1; @@ -271,7 +214,16 @@ return false; } - PushVersion(); + // Push version; + uint64_t nLocalServices = 0; + uint64_t nLocalNonce = BITCOIN_SEED_NONCE; + CService myService; + CAddress me(myService, ServiceFlags(NODE_NETWORK)); + std::string ver = "/bitcoin-cash-seeder:0.15/"; + vSend += MessageWriter::WriteMessage(vSend.GetVersion(), + NetMsgType::VERSION, PROTOCOL_VERSION, + nLocalServices, time(nullptr), you, me, + nLocalNonce, ver, GetRequireHeight()); Send(); bool res = true; diff --git a/src/seeder/messagewriter.h b/src/seeder/messagewriter.h new file mode 100644 --- /dev/null +++ b/src/seeder/messagewriter.h @@ -0,0 +1,39 @@ +// Copyright (c) 2020 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_MESSAGEWRITER_H +#define BITCOIN_SEEDER_MESSAGEWRITER_H + +#include +#include +#include + +namespace MessageWriter { + +template +static CDataStream WriteMessage(int version, std::string command, + Args &&... args) { + CSerializedNetMsg payload = + CNetMsgMaker(version).Make(command, std::forward(args)...); + size_t nMessageSize = payload.data.size(); + + // Serialize header + std::vector serializedHeader; + V1TransportSerializer serializer = V1TransportSerializer(); + serializer.prepareForTransport(GetConfig(), payload, serializedHeader); + + // Send message + std::vector sendMsg; + sendMsg.insert(sendMsg.end(), serializedHeader.begin(), + serializedHeader.end()); + if (nMessageSize) { + sendMsg.insert(sendMsg.end(), payload.data.begin(), payload.data.end()); + } + + return CDataStream(sendMsg, SER_NETWORK, version); +} + +} // namespace MessageWriter + +#endif // BITCOIN_SEEDER_MESSAGEWRITER_H 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 @@ -1,4 +1,4 @@ -# Copyright (c) 2019 The Bitcoin developers +# Copyright (c) 2019-2020 The Bitcoin developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -12,6 +12,7 @@ fixture.cpp TESTS + message_writer_tests.cpp p2p_messaging_tests.cpp parse_name_tests.cpp write_name_tests.cpp diff --git a/src/seeder/test/message_writer_tests.cpp b/src/seeder/test/message_writer_tests.cpp new file mode 100644 --- /dev/null +++ b/src/seeder/test/message_writer_tests.cpp @@ -0,0 +1,99 @@ +// Copyright (c) 2020 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 + +BOOST_AUTO_TEST_SUITE(message_writer_tests) + +template +static void CheckMessage(CDataStream expectedMessage, int version, + std::string command, Args &&... args) { + CDataStream message = MessageWriter::WriteMessage( + version, command, std::forward(args)...); + BOOST_CHECK_EQUAL(message.size(), expectedMessage.size()); + for (size_t i = 0; i < message.size(); i++) { + BOOST_CHECK_EQUAL(message[i], expectedMessage[i]); + } +} + +BOOST_AUTO_TEST_CASE(simple_header_and_payload_message_writer_test) { + SelectParams(CBaseChainParams::MAIN); + int nVersion = PROTOCOL_VERSION; + uint64_t now = time(nullptr); + uint64_t nonce = 0; + uint64_t serviceFlags = uint64_t(ServiceFlags(NODE_NETWORK)); + CService service; + CAddress addrTo(service, ServiceFlags(NODE_NETWORK)); + CAddress addrFrom(service, ServiceFlags(NODE_NETWORK)); + std::string user_agent = "/bitcoin-cash-seeder:0.15/"; + int start_height = 1; + + CDataStream versionPayload(SER_NETWORK, nVersion); + versionPayload << nVersion << serviceFlags << now << addrTo << addrFrom + << nonce << user_agent << start_height; + + CMessageHeader versionhdr(Params().NetMagic(), NetMsgType::VERSION, + versionPayload.size()); + uint256 hash = Hash(versionPayload.data(), + versionPayload.data() + versionPayload.size()); + memcpy(versionhdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); + + CDataStream expectedVersion(SER_NETWORK, nVersion); + expectedVersion << versionhdr; + expectedVersion += versionPayload; + + CheckMessage(expectedVersion, nVersion, NetMsgType::VERSION, nVersion, + serviceFlags, now, addrTo, addrFrom, nonce, user_agent, + start_height); +} + +BOOST_AUTO_TEST_CASE(header_empty_payload_message_writer_test) { + SelectParams(CBaseChainParams::MAIN); + int nVersion = PROTOCOL_VERSION; + CMessageHeader verackHeader(Params().NetMagic(), NetMsgType::VERACK, 0); + CDataStream expectedVerack(SER_NETWORK, nVersion); + // This is an empty payload, but is still necessary for the checksum + std::vector payload; + uint256 hash = Hash(payload.data(), payload.data() + payload.size()); + memcpy(verackHeader.pchChecksum, hash.begin(), + CMessageHeader::CHECKSUM_SIZE); + expectedVerack << verackHeader; + + CheckMessage(expectedVerack, nVersion, NetMsgType::VERACK); +} + +BOOST_AUTO_TEST_CASE(write_getheaders_message_test) { + SelectParams(CBaseChainParams::MAIN); + int nVersion = PROTOCOL_VERSION; + CDataStream payload(SER_NETWORK, nVersion); + BlockHash bhash(uint256S( + "0000000099f5509b5f36b1926bcf82b21d936ebeadee811030dfbbb7fae915d7")); + std::vector vlocator(1, bhash); + CBlockLocator locatorhash(vlocator); + payload << locatorhash << uint256(); + uint256 hash = Hash(payload.data(), payload.data() + payload.size()); + + CMessageHeader msgHeader(Params().NetMagic(), NetMsgType::GETHEADERS, + payload.size()); + memcpy(msgHeader.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); + + CDataStream expectedMsg(SER_NETWORK, nVersion); + expectedMsg << msgHeader; + expectedMsg += payload; + + CheckMessage(expectedMsg, nVersion, NetMsgType::GETHEADERS, locatorhash, + uint256()); +} + +BOOST_AUTO_TEST_SUITE_END()