diff --git a/src/seeder/CMakeLists.txt b/src/seeder/CMakeLists.txt --- a/src/seeder/CMakeLists.txt +++ b/src/seeder/CMakeLists.txt @@ -5,10 +5,10 @@ project(bitcoin-seeder) add_library(seeder bitcoin.cpp db.cpp dns.cpp) -target_link_libraries(seeder common bitcoinconsensus) +target_link_libraries(seeder common server) add_executable(bitcoin-seeder main.cpp) -target_link_libraries(bitcoin-seeder common bitcoinconsensus seeder) +target_link_libraries(bitcoin-seeder common seeder) include(BinaryTest) add_to_symbols_check(bitcoin-seeder) diff --git a/src/seeder/bitcoin.h b/src/seeder/bitcoin.h --- a/src/seeder/bitcoin.h +++ b/src/seeder/bitcoin.h @@ -31,7 +31,7 @@ class CSeederNode { private: SOCKET sock; - CDataStream vSend; + std::vector vSend; CDataStream vRecv; uint32_t nHeaderStart; uint32_t nMessageStart; diff --git a/src/seeder/bitcoin.cpp b/src/seeder/bitcoin.cpp --- a/src/seeder/bitcoin.cpp +++ b/src/seeder/bitcoin.cpp @@ -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; @@ -68,7 +25,7 @@ if (vSend.empty()) { return; } - int nBytes = send(sock, &vSend[0], vSend.size(), 0); + int nBytes = send(sock, vSend.data(), vSend.size(), 0); if (nBytes > 0) { vSend.erase(vSend.begin(), vSend.begin() + nBytes); } else { @@ -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 | NODE_BITCOIN_CASH)); - 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), @@ -106,10 +49,11 @@ recv >> addrFrom >> nNonce; recv >> strSubVer; recv >> nStartingHeight; + nVersion = std::min(nVersion, PROTOCOL_VERSION); - BeginMessage(NetMsgType::VERACK); - EndMessage(); - vSend.SetVersion(std::min(nVersion, PROTOCOL_VERSION)); + std::vector verackMsg = + WriteMessage(nVersion, NetMsgType::VERACK, netMagic); + vSend.insert(vSend.end(), verackMsg.begin(), verackMsg.end()); return PeerMessagingState::AwaitingMessages; } @@ -118,8 +62,9 @@ // tfm::format(std::cout, "\n%s: version %i\n", ToString(you), // nVersion); if (vAddr) { - BeginMessage(NetMsgType::GETADDR); - EndMessage(); + std::vector getAddrMsg = + WriteMessage(nVersion, NetMsgType::GETADDR, netMagic); + vSend.insert(vSend.end(), getAddrMsg.begin(), getAddrMsg.end()); doneAfter = time(nullptr) + GetTimeout(); } else { doneAfter = time(nullptr) + 1; @@ -226,11 +171,10 @@ } CSeederNode::CSeederNode(const CService &ip, std::vector *vAddrIn) - : sock(INVALID_SOCKET), vSend(SER_NETWORK, 0), vRecv(SER_NETWORK, 0), - nHeaderStart(-1), nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), - doneAfter(0), you(ip, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)) { + : sock(INVALID_SOCKET), vRecv(SER_NETWORK, 0), nHeaderStart(-1), + nMessageStart(-1), nVersion(0), vAddr(vAddrIn), ban(0), doneAfter(0), + you(ip, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)) { if (time(nullptr) > 1329696000) { - vSend.SetVersion(209); vRecv.SetVersion(209); } } @@ -271,7 +215,15 @@ return false; } - PushVersion(); + // PushVersion(); + uint64_t nLocalServices = 0; + uint64_t nLocalNonce = BITCOIN_SEED_NONCE; + CService myService; + CAddress me(myService, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); + std::string ver = "/bitcoin-cash-seeder:0.15/"; + vSend = WriteMessage(nVersion, NetMsgType::VERSION, netMagic, + 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) 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_MESSAGEWRITER_H +#define BITCOIN_SEEDER_MESSAGEWRITER_H + +#include +#include + +template +static std::vector WriteMessage(int version, std::string command, + CMessageHeader::MessageMagic netmagic, + Args &&... args) { + CSerializedNetMsg payload = + CNetMsgMaker(version).Make(command, std::forward(args)...); + size_t nMessageSize = payload.data.size(); + + // Create header + std::vector serializedHeader; + serializedHeader.reserve(CMessageHeader::HEADER_SIZE); + uint256 hash = + Hash(payload.data.data(), payload.data.data() + nMessageSize); + CMessageHeader hdr(netmagic, payload.command.c_str(), nMessageSize); + memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE); + CVectorWriter{SER_NETWORK, INIT_PROTO_VERSION, serializedHeader, 0, hdr}; + + // Combine header and payload + std::vector sendMsg; + sendMsg.insert(sendMsg.end(), serializedHeader.begin(), + serializedHeader.end()); + if (nMessageSize) { + sendMsg.insert(sendMsg.end(), payload.data.begin(), payload.data.end()); + } + + return sendMsg; +} + +#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 @@ -15,6 +15,7 @@ p2p_messaging_tests.cpp parse_name_tests.cpp write_name_tests.cpp + message_writer_tests.cpp ) target_link_libraries(test_bitcoin-seeder 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,76 @@ +// 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 + +BOOST_AUTO_TEST_SUITE(message_writer_tests) + +template +static void +CheckMessage(CDataStream expectedMessage, int version, std::string command, + CMessageHeader::MessageMagic netMagic, Args &&... args) { + std::vector message = + WriteMessage(version, command, netMagic, std::forward(args)...); + BOOST_CHECK_EQUAL(message.size(), expectedMessage.size()); + for (size_t i = 0; i < message.size(); i++) { + if (message[i] != uint8_t(expectedMessage[i])) { + BOOST_CHECK_EQUAL(i, -1); + } + BOOST_CHECK_EQUAL(message[i], uint8_t(expectedMessage[i])); + } +} + +BOOST_AUTO_TEST_CASE(header_and_payload_message_writer_test) { + 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 | NODE_BITCOIN_CASH)); + CAddress addrFrom(service, ServiceFlags(NODE_NETWORK | NODE_BITCOIN_CASH)); + 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::MessageMagic netMagic = {{0xe3, 0xe1, 0xf3, 0xe8}}; + CMessageHeader versionhdr(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 << versionPayload; + + CheckMessage(expectedVersion, nVersion, NetMsgType::VERSION, netMagic, + nVersion, serviceFlags, now, addrTo, addrFrom, nonce, + user_agent, start_height); +} + +BOOST_AUTO_TEST_CASE(header_empty_payload_message_writer_test) { + int nVersion = PROTOCOL_VERSION; + CMessageHeader::MessageMagic netMagic = {{0xe3, 0xe1, 0xf3, 0xe8}}; + CMessageHeader verackHeader(netMagic, NetMsgType::VERACK, 0); + CDataStream expectedVerack(SER_NETWORK, nVersion); + 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, netMagic); +} + +BOOST_AUTO_TEST_SUITE_END()