From b621cfb5fb44bf1ed736aa19e0d4c7b4c405d4f4 Mon Sep 17 00:00:00 2001 From: Oleg Girko Date: Thu, 27 Jul 2017 15:28:05 +0100 Subject: [PATCH] Backport Bitcoin PR#8708: net: have CConnman handle message sending (#1553) * serialization: teach serializers variadics Also add a variadic CDataStream ctor for ease-of-use. * connman is in charge of pushing messages The changes here are dense and subtle, but hopefully all is more explicit than before. - CConnman is now in charge of sending data rather than the nodes themselves. This is necessary because many decisions need to be made with all nodes in mind, and a model that requires the nodes calling up to their manager quickly turns to spaghetti. - The per-node-serializer (ssSend) has been replaced with a (quasi-)const send-version. Since the send version for serialization can only change once per connection, we now explicitly tag messages with INIT_PROTO_VERSION if they are sent before the handshake. With this done, there's no need to lock for access to nSendVersion. Also, a new stream is used for each message, so there's no need to lock during the serialization process. - This takes care of accounting for optimistic sends, so the nOptimisticBytesWritten hack can be removed. - -dropmessagestest and -fuzzmessagestest have not been preserved, as I suspect they haven't been used in years. * net: switch all callers to connman for pushing messages Drop all of the old stuff. * drop the optimistic write counter hack This is now handled properly in realtime. * net: remove now-unused ssSend and Fuzz * net: construct CNodeStates in place * net: handle version push in InitializeNode --- src/alert.cpp | 4 +- src/alert.h | 3 +- src/governance.cpp | 8 +- src/main.cpp | 144 ++++++++++-------- src/masternode-payments.cpp | 8 +- src/masternode-sync.cpp | 12 +- src/masternodeman.cpp | 10 +- src/net.cpp | 186 +++++++---------------- src/net.h | 281 +++++++---------------------------- src/privatesend-client.cpp | 8 +- src/privatesend-server.cpp | 6 +- src/privatesend.cpp | 2 +- src/sendalert.cpp | 2 +- src/serialize.h | 49 ++++++ src/spork.cpp | 2 +- src/streams.h | 7 + src/test/DoS_tests.cpp | 12 +- src/test/serialize_tests.cpp | 71 ++++++++- 18 files changed, 363 insertions(+), 452 deletions(-) diff --git a/src/alert.cpp b/src/alert.cpp index 75cfb091af1fd..1dc272cda886d 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -125,7 +125,7 @@ bool CAlert::AppliesToMe() const return AppliesTo(PROTOCOL_VERSION, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector())); } -bool CAlert::RelayTo(CNode* pnode) const +bool CAlert::RelayTo(CNode* pnode, CConnman& connman) const { if (!IsInEffect()) return false; @@ -139,7 +139,7 @@ bool CAlert::RelayTo(CNode* pnode) const AppliesToMe() || GetAdjustedTime() < nRelayUntil) { - pnode->PushMessage(NetMsgType::ALERT, *this); + connman.PushMessage(pnode, NetMsgType::ALERT, *this); return true; } } diff --git a/src/alert.h b/src/alert.h index a0b16d5731836..f2201172430dd 100644 --- a/src/alert.h +++ b/src/alert.h @@ -16,6 +16,7 @@ class CAlert; class CNode; +class CConnman; class uint256; extern std::map mapAlerts; @@ -99,7 +100,7 @@ class CAlert : public CUnsignedAlert bool Cancels(const CAlert& alert) const; bool AppliesTo(int nVersion, const std::string& strSubVerIn) const; bool AppliesToMe() const; - bool RelayTo(CNode* pnode) const; + bool RelayTo(CNode* pnode, CConnman& connman) const; bool Sign(); bool CheckSignature(const std::vector& alertKey) const; bool ProcessAlert(const std::vector& alertKey, bool fThread = true); // fThread means run -alertnotify in a free-running thread diff --git a/src/governance.cpp b/src/governance.cpp index f3caefb26abb1..22c781500a652 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -834,8 +834,8 @@ void CGovernanceManager::Sync(CNode* pfrom, const uint256& nProp, const CBloomFi } } - pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ, nObjCount); - pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ_VOTE, nVoteCount); + g_connman->PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ, nObjCount); + g_connman->PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ_VOTE, nVoteCount); LogPrintf("CGovernanceManager::Sync -- sent %d objects and %d votes to peer=%d\n", nObjCount, nVoteCount, pfrom->id); } @@ -1147,7 +1147,7 @@ void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nH LogPrint("gobject", "CGovernanceObject::RequestGovernanceObject -- hash = %s (peer=%d)\n", nHash.ToString(), pfrom->GetId()); if(pfrom->nVersion < GOVERNANCE_FILTER_PROTO_VERSION) { - pfrom->PushMessage(NetMsgType::MNGOVERNANCESYNC, nHash); + g_connman->PushMessage(pfrom, NetMsgType::MNGOVERNANCESYNC, nHash); return; } @@ -1170,7 +1170,7 @@ void CGovernanceManager::RequestGovernanceObject(CNode* pfrom, const uint256& nH } LogPrint("gobject", "CGovernanceManager::RequestGovernanceObject -- nHash %s nVoteCount %d peer=%d\n", nHash.ToString(), nVoteCount, pfrom->id); - pfrom->PushMessage(NetMsgType::MNGOVERNANCESYNC, nHash, filter); + g_connman->PushMessage(pfrom, NetMsgType::MNGOVERNANCESYNC, nHash, filter); } int CGovernanceManager::RequestGovernanceObjectVotes(CNode* pnode) diff --git a/src/main.cpp b/src/main.cpp index 85b9a75f61e77..433b598b15f25 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,6 +19,7 @@ #include "init.h" #include "merkleblock.h" #include "net.h" +#include "netbase.h" #include "policy/policy.h" #include "pow.h" #include "primitives/block.h" @@ -246,7 +247,7 @@ struct CBlockReject { */ struct CNodeState { //! The peer's address - CService address; + const CService address; //! Whether we have a fully established connection. bool fCurrentlyConnected; //! Accumulated misbehaviour score for this peer. @@ -254,7 +255,7 @@ struct CNodeState { //! Whether this peer should be disconnected and banned (unless whitelisted). bool fShouldBan; //! String name of this peer (debugging/logging purposes). - std::string name; + const std::string name; //! List of asynchronously-determined block rejections to notify this peer about. std::vector rejects; //! The best known block we know this peer has announced. @@ -279,7 +280,7 @@ struct CNodeState { //! Whether this peer wants invs or headers (when possible) for block announcements. bool fPreferHeaders; - CNodeState() { + CNodeState(CAddress addrIn, std::string addrNameIn) : address(addrIn), name(addrNameIn) { fCurrentlyConnected = false; nMisbehavior = 0; fShouldBan = false; @@ -318,11 +319,36 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state) nPreferredDownload += state->fPreferredDownload; } -void InitializeNode(NodeId nodeid, const CNode *pnode) { - LOCK(cs_main); - CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; - state.name = pnode->addrName; - state.address = pnode->addr; +void PushNodeVersion(CNode *pnode, CConnman& connman, int64_t nTime) +{ + ServiceFlags nLocalNodeServices = pnode->GetLocalServices(); + uint64_t nonce = pnode->GetLocalNonce(); + int nNodeStartingHeight = pnode->GetMyStartingHeight(); + NodeId nodeid = pnode->GetId(); + CAddress addr = pnode->addr; + + CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices)); + CAddress addrMe = GetLocalAddress(&addr, nLocalNodeServices); + + connman.PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, + nonce, strSubVersion, nNodeStartingHeight, ::fRelayTxes); + + if (fLogIPs) + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); + else + LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nNodeStartingHeight, addrMe.ToString(), nodeid); +} + +void InitializeNode(CNode *pnode, CConnman& connman) { + CAddress addr = pnode->addr; + std::string addrName = pnode->addrName; + NodeId nodeid = pnode->GetId(); + { + LOCK(cs_main); + mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName))); + } + if(!pnode->fInbound) + PushNodeVersion(pnode, connman, GetTime()); } void FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) { @@ -5057,14 +5083,14 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam if (!ReadBlockFromDisk(block, (*mi).second, consensusParams)) assert(!"cannot load block from disk"); if (inv.type == MSG_BLOCK) - pfrom->PushMessage(NetMsgType::BLOCK, block); + connman.PushMessage(pfrom, NetMsgType::BLOCK, block); else // MSG_FILTERED_BLOCK) { LOCK(pfrom->cs_filter); if (pfrom->pfilter) { CMerkleBlock merkleBlock(block, *pfrom->pfilter); - pfrom->PushMessage(NetMsgType::MERKLEBLOCK, merkleBlock); + connman.PushMessage(pfrom, NetMsgType::MERKLEBLOCK, merkleBlock); // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see // This avoids hurting performance by pointlessly requiring a round-trip // Note that there is currently no way for a node to request any single transactions we didn't send here - @@ -5073,7 +5099,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // however we MUST always provide at least what the remote peer needs typedef std::pair PairType; BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) - pfrom->PushMessage(NetMsgType::TX, block.vtx[pair.first]); + connman.PushMessage(pfrom, NetMsgType::TX, block.vtx[pair.first]); } // else // no response @@ -5087,7 +5113,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // wait for other stuff first. vector vInv; vInv.push_back(CInv(MSG_BLOCK, chainActive.Tip()->GetBlockHash())); - pfrom->PushMessage(NetMsgType::INV, vInv); + connman.PushMessage(pfrom, NetMsgType::INV, vInv); pfrom->hashContinue.SetNull(); } } @@ -5107,7 +5133,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } } if(pushed) - pfrom->PushMessage(inv.GetCommand(), ss); + connman.PushMessage(pfrom, inv.GetCommand(), ss); } if (!pushed && inv.type == MSG_TX) { @@ -5116,7 +5142,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << tx; - pfrom->PushMessage(NetMsgType::TX, ss); + connman.PushMessage(pfrom, NetMsgType::TX, ss); pushed = true; } } @@ -5127,7 +5153,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << txLockRequest; - pfrom->PushMessage(NetMsgType::TXLOCKREQUEST, ss); + connman.PushMessage(pfrom, NetMsgType::TXLOCKREQUEST, ss); pushed = true; } } @@ -5138,7 +5164,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << vote; - pfrom->PushMessage(NetMsgType::TXLOCKVOTE, ss); + connman.PushMessage(pfrom, NetMsgType::TXLOCKVOTE, ss); pushed = true; } } @@ -5148,7 +5174,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mapSporks[inv.hash]; - pfrom->PushMessage(NetMsgType::SPORK, ss); + connman.PushMessage(pfrom, NetMsgType::SPORK, ss); pushed = true; } } @@ -5158,7 +5184,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mnpayments.mapMasternodePaymentVotes[inv.hash]; - pfrom->PushMessage(NetMsgType::MASTERNODEPAYMENTVOTE, ss); + connman.PushMessage(pfrom, NetMsgType::MASTERNODEPAYMENTVOTE, ss); pushed = true; } } @@ -5174,7 +5200,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mnpayments.mapMasternodePaymentVotes[hash]; - pfrom->PushMessage(NetMsgType::MASTERNODEPAYMENTVOTE, ss); + connman.PushMessage(pfrom, NetMsgType::MASTERNODEPAYMENTVOTE, ss); } } } @@ -5187,7 +5213,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mnodeman.mapSeenMasternodeBroadcast[inv.hash].second; - pfrom->PushMessage(NetMsgType::MNANNOUNCE, ss); + connman.PushMessage(pfrom, NetMsgType::MNANNOUNCE, ss); pushed = true; } } @@ -5197,7 +5223,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mnodeman.mapSeenMasternodePing[inv.hash]; - pfrom->PushMessage(NetMsgType::MNPING, ss); + connman.PushMessage(pfrom, NetMsgType::MNPING, ss); pushed = true; } } @@ -5208,7 +5234,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << dstx; - pfrom->PushMessage(NetMsgType::DSTX, ss); + connman.PushMessage(pfrom, NetMsgType::DSTX, ss); pushed = true; } } @@ -5227,7 +5253,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } LogPrint("net", "ProcessGetData -- MSG_GOVERNANCE_OBJECT: topush = %d, inv = %s\n", topush, inv.ToString()); if(topush) { - pfrom->PushMessage(NetMsgType::MNGOVERNANCEOBJECT, ss); + connman.PushMessage(pfrom, NetMsgType::MNGOVERNANCEOBJECT, ss); pushed = true; } } @@ -5245,7 +5271,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam } if(topush) { LogPrint("net", "ProcessGetData -- pushing: inv = %s\n", inv.ToString()); - pfrom->PushMessage(NetMsgType::MNGOVERNANCEOBJECTVOTE, ss); + connman.PushMessage(pfrom, NetMsgType::MNGOVERNANCEOBJECTVOTE, ss); pushed = true; } } @@ -5255,7 +5281,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss.reserve(1000); ss << mnodeman.mapSeenMasternodeVerification[inv.hash]; - pfrom->PushMessage(NetMsgType::MNVERIFY, ss); + connman.PushMessage(pfrom, NetMsgType::MNVERIFY, ss); pushed = true; } } @@ -5282,7 +5308,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // do that because they want to know about (and store and rebroadcast and // risk analyze) the dependencies of transactions relevant to them, without // having to download the entire memory pool. - pfrom->PushMessage(NetMsgType::NOTFOUND, vNotFound); + connman.PushMessage(pfrom, NetMsgType::NOTFOUND, vNotFound); } } @@ -5327,7 +5353,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Each connection can only send one version message if (pfrom->nVersion != 0) { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); + connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, string("Duplicate version message")); LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; @@ -5347,7 +5373,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pfrom->nServicesExpected & ~pfrom->nServices) { LogPrint("net", "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->id, pfrom->nServices, pfrom->nServicesExpected); - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, + connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, strprintf("Expected to offer services %08x", pfrom->nServicesExpected)); pfrom->fDisconnect = true; return false; @@ -5357,7 +5383,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { // disconnect from peers older than this proto version LogPrintf("peer=%d using obsolete version %i; disconnecting\n", pfrom->id, pfrom->nVersion); - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, + connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION)); pfrom->fDisconnect = true; return false; @@ -5394,7 +5420,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Be shy and don't send version until we hear if (pfrom->fInbound) - pfrom->PushVersion(); + PushNodeVersion(pfrom, connman, GetAdjustedTime()); pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); @@ -5405,8 +5431,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Change version - pfrom->PushMessage(NetMsgType::VERACK); - pfrom->ssSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); + connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::VERACK); + pfrom->SetSendVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); if (!pfrom->fInbound) { @@ -5428,7 +5454,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Get recent addresses if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || connman.GetAddressCount() < 1000) { - pfrom->PushMessage(NetMsgType::GETADDR); + connman.PushMessage(pfrom, NetMsgType::GETADDR); pfrom->fGetAddr = true; } connman.MarkAddressGood(pfrom->addr); @@ -5444,7 +5470,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) - item.second.RelayTo(pfrom); + item.second.RelayTo(pfrom, connman); } pfrom->fSuccessfullyConnected = true; @@ -5488,7 +5514,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning // nodes) - pfrom->PushMessage(NetMsgType::SENDHEADERS); + connman.PushMessage(pfrom, NetMsgType::SENDHEADERS); } } @@ -5593,7 +5619,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // time the block arrives, the header chain leading up to it is already validated. Not // doing this will result in the received block being rejected as an orphan in case it is // not a direct successor. - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); + connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); if (CanDirectFetch(chainparams.GetConsensus()) && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { @@ -5623,7 +5649,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (!vToFetch.empty()) - pfrom->PushMessage(NetMsgType::GETDATA, vToFetch); + connman.PushMessage(pfrom, NetMsgType::GETDATA, vToFetch); } @@ -5738,7 +5764,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // headers message). In both cases it's safe to update // pindexBestHeaderSent to be our tip. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); - pfrom->PushMessage(NetMsgType::HEADERS, vHeaders); + connman.PushMessage(pfrom, NetMsgType::HEADERS, vHeaders); } @@ -5949,7 +5975,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->id, FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P - pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); @@ -6009,7 +6035,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue // from there instead. LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight); - pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); + connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()); } bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus()); @@ -6054,7 +6080,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pindexLast->GetBlockHash().ToString(), pindexLast->nHeight); } if (vGetData.size() > 0) { - pfrom->PushMessage(NetMsgType::GETDATA, vGetData); + connman.PushMessage(pfrom, NetMsgType::GETDATA, vGetData); } } } @@ -6085,7 +6111,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS; if (state.IsInvalid(nDoS)) { assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), + connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) { LOCK(cs_main); @@ -6138,12 +6164,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } vInv.push_back(inv); if (vInv.size() == MAX_INV_SZ) { - pfrom->PushMessage(NetMsgType::INV, vInv); + connman.PushMessage(pfrom, NetMsgType::INV, vInv); vInv.clear(); } } if (vInv.size() > 0) - pfrom->PushMessage(NetMsgType::INV, vInv); + connman.PushMessage(pfrom, NetMsgType::INV, vInv); } @@ -6164,7 +6190,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // it, if the remote node sends a ping once per second and this node takes 5 // seconds to respond to each, the 5th ping the remote sends would appear to // return very quickly. - pfrom->PushMessage(NetMsgType::PONG, nonce); + connman.PushMessage(pfrom, NetMsgType::PONG, nonce); } } @@ -6239,8 +6265,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Relay pfrom->setKnown.insert(alertHash); { - connman.ForEachNode([&alert](CNode* pnode) { - alert.RelayTo(pnode); + connman.ForEachNode([&alert, &connman](CNode* pnode) { + alert.RelayTo(pnode, connman); }); } } @@ -6452,7 +6478,7 @@ bool ProcessMessages(CNode* pfrom, CConnman& connman) } catch (const std::ios_base::failure& e) { - pfrom->PushMessage(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); + connman.PushMessageWithVersion(pfrom, INIT_PROTO_VERSION, NetMsgType::REJECT, strCommand, REJECT_MALFORMED, string("error parsing message")); if (strstr(e.what(), "end of data")) { // Allow exceptions from under-length message on vRecv @@ -6520,11 +6546,11 @@ bool SendMessages(CNode* pto, CConnman& connman) pto->nPingUsecStart = GetTimeMicros(); if (pto->nVersion > BIP0031_VERSION) { pto->nPingNonceSent = nonce; - pto->PushMessage(NetMsgType::PING, nonce); + connman.PushMessage(pto, NetMsgType::PING, nonce); } else { // Peer is too old to support ping command with nonce, pong will never arrive. pto->nPingNonceSent = 0; - pto->PushMessage(NetMsgType::PING); + connman.PushMessage(pto, NetMsgType::PING); } } @@ -6555,14 +6581,14 @@ bool SendMessages(CNode* pto, CConnman& connman) // receiver rejects addr messages larger than 1000 if (vAddr.size() >= 1000) { - pto->PushMessage(NetMsgType::ADDR, vAddr); + connman.PushMessage(pto, NetMsgType::ADDR, vAddr); vAddr.clear(); } } } pto->vAddrToSend.clear(); if (!vAddr.empty()) - pto->PushMessage(NetMsgType::ADDR, vAddr); + connman.PushMessage(pto, NetMsgType::ADDR, vAddr); } CNodeState &state = *State(pto->GetId()); @@ -6582,7 +6608,7 @@ bool SendMessages(CNode* pto, CConnman& connman) } BOOST_FOREACH(const CBlockReject& reject, state.rejects) - pto->PushMessage(NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); + connman.PushMessage(pto, NetMsgType::REJECT, (string)NetMsgType::BLOCK, reject.chRejectCode, reject.strRejectReason, reject.hashBlock); state.rejects.clear(); // Start block sync @@ -6605,7 +6631,7 @@ bool SendMessages(CNode* pto, CConnman& connman) if (pindexStart->pprev) pindexStart = pindexStart->pprev; LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight); - pto->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); + connman.PushMessage(pto, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()); } } @@ -6719,7 +6745,7 @@ bool SendMessages(CNode* pto, CConnman& connman) LogPrint("net", "%s: sending header %s to peer=%d\n", __func__, vHeaders.front().GetHash().ToString(), pto->id); } - pto->PushMessage(NetMsgType::HEADERS, vHeaders); + connman.PushMessage(pto, NetMsgType::HEADERS, vHeaders); state.pindexBestHeaderSent = pBestIndex; } pto->vBlockHashesToAnnounce.clear(); @@ -6770,7 +6796,7 @@ bool SendMessages(CNode* pto, CConnman& connman) if (vInv.size() >= 1000) { LogPrint("net", "SendMessages -- pushing inv's: count=%d peer=%d\n", vInv.size(), pto->id); - pto->PushMessage(NetMsgType::INV, vInv); + connman.PushMessage(pto, NetMsgType::INV, vInv); vInv.clear(); } } @@ -6778,7 +6804,7 @@ bool SendMessages(CNode* pto, CConnman& connman) } if (!vInv.empty()) { LogPrint("net", "SendMessages -- pushing tailing inv's: count=%d peer=%d\n", vInv.size(), pto->id); - pto->PushMessage(NetMsgType::INV, vInv); + connman.PushMessage(pto, NetMsgType::INV, vInv); } // Detect whether we're stalling @@ -6838,7 +6864,7 @@ bool SendMessages(CNode* pto, CConnman& connman) vGetData.push_back(inv); if (vGetData.size() >= 1000) { - pto->PushMessage(NetMsgType::GETDATA, vGetData); + connman.PushMessage(pto, NetMsgType::GETDATA, vGetData); LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id); vGetData.clear(); } @@ -6850,7 +6876,7 @@ bool SendMessages(CNode* pto, CConnman& connman) pto->mapAskFor.erase(pto->mapAskFor.begin()); } if (!vGetData.empty()) { - pto->PushMessage(NetMsgType::GETDATA, vGetData); + connman.PushMessage(pto, NetMsgType::GETDATA, vGetData); LogPrint("net", "SendMessages -- GETDATA -- pushed size = %lu peer=%d\n", vGetData.size(), pto->id); } diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 9ad0bdc9c11d4..a61bb8ed50268 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -842,7 +842,7 @@ void CMasternodePayments::Sync(CNode* pnode) } LogPrintf("CMasternodePayments::Sync -- Sent %d votes to peer %d\n", nInvCount, pnode->id); - pnode->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount); + g_connman->PushMessage(pnode, NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_MNW, nInvCount); } // Request low data/unknown payment blocks in batches directly from some node instead of/after preliminary Sync. @@ -864,7 +864,7 @@ void CMasternodePayments::RequestLowDataPaymentBlocks(CNode* pnode) // We should not violate GETDATA rules if(vToFetch.size() == MAX_INV_SZ) { LogPrintf("CMasternodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d blocks\n", pnode->id, MAX_INV_SZ); - pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + g_connman->PushMessage(pnode, NetMsgType::GETDATA, vToFetch); // Start filling new batch vToFetch.clear(); } @@ -912,7 +912,7 @@ void CMasternodePayments::RequestLowDataPaymentBlocks(CNode* pnode) // We should not violate GETDATA rules if(vToFetch.size() == MAX_INV_SZ) { LogPrintf("CMasternodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d payment blocks\n", pnode->id, MAX_INV_SZ); - pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + g_connman->PushMessage(pnode, NetMsgType::GETDATA, vToFetch); // Start filling new batch vToFetch.clear(); } @@ -921,7 +921,7 @@ void CMasternodePayments::RequestLowDataPaymentBlocks(CNode* pnode) // Ask for the rest of it if(!vToFetch.empty()) { LogPrintf("CMasternodePayments::SyncLowDataPaymentBlocks -- asking peer %d for %d payment blocks\n", pnode->id, vToFetch.size()); - pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + g_connman->PushMessage(pnode, NetMsgType::GETDATA, vToFetch); } } diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index 5331c35ac92c4..619b7b3fca0b1 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -324,12 +324,12 @@ void CMasternodeSync::ProcessTick() if(Params().NetworkIDString() == CBaseChainParams::REGTEST) { if(nRequestedMasternodeAttempt <= 2) { - pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks + g_connman->PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::GETSPORKS); //get current network sporks } else if(nRequestedMasternodeAttempt < 4) { mnodeman.DsegUpdate(pnode); } else if(nRequestedMasternodeAttempt < 6) { int nMnCount = mnodeman.CountMasternodes(); - pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes + g_connman->PushMessage(pnode, NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes SendGovernanceSyncRequest(pnode); } else { nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED; @@ -355,7 +355,7 @@ void CMasternodeSync::ProcessTick() // only request once from each peer netfulfilledman.AddFulfilledRequest(pnode->addr, "spork-sync"); // get current network sporks - pnode->PushMessage(NetMsgType::GETSPORKS); + g_connman->PushMessageWithVersion(pnode, INIT_PROTO_VERSION, NetMsgType::GETSPORKS); LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- requesting sporks from peer %d\n", nTick, nRequestedMasternodeAssets, pnode->id); continue; // always get sporks first, switch to the next node without waiting for the next tick } @@ -431,7 +431,7 @@ void CMasternodeSync::ProcessTick() nRequestedMasternodeAttempt++; // ask node for all payment votes it has (new nodes will only return votes for future payments) - pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit()); + g_connman->PushMessage(pnode, NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit()); // ask node for missing pieces only (old nodes will not be asked) mnpayments.RequestLowDataPaymentBlocks(pnode); @@ -511,10 +511,10 @@ void CMasternodeSync::SendGovernanceSyncRequest(CNode* pnode) CBloomFilter filter; filter.clear(); - pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256(), filter); + g_connman->PushMessage(pnode, NetMsgType::MNGOVERNANCESYNC, uint256(), filter); } else { - pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256()); + g_connman->PushMessage(pnode, NetMsgType::MNGOVERNANCESYNC, uint256()); } } diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 263f96ae5facc..37c4d7fb28bb5 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -162,7 +162,7 @@ void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn &vin) } mWeAskedForMasternodeListEntry[vin.prevout][pnode->addr] = GetTime() + DSEG_UPDATE_SECONDS; - pnode->PushMessage(NetMsgType::DSEG, vin); + g_connman->PushMessage(pnode, NetMsgType::DSEG, vin); } void CMasternodeMan::Check() @@ -438,7 +438,7 @@ void CMasternodeMan::DsegUpdate(CNode* pnode) } } - pnode->PushMessage(NetMsgType::DSEG, CTxIn()); + g_connman->PushMessage(pnode, NetMsgType::DSEG, CTxIn()); int64_t askAgain = GetTime() + DSEG_UPDATE_SECONDS; mWeAskedForMasternodeList[pnode->addr] = askAgain; @@ -926,7 +926,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } if(vin == CTxIn()) { - pfrom->PushMessage(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount); + g_connman->PushMessage(pfrom, NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_LIST, nInvCount); LogPrintf("DSEG -- Sent %d Masternode invs to peer %d\n", nInvCount, pfrom->id); return; } @@ -1109,7 +1109,7 @@ bool CMasternodeMan::SendVerifyRequest(const CAddress& addr, const std::vectornHeight - 1); mWeAskedForVerification[addr] = mnv; LogPrintf("CMasternodeMan::SendVerifyRequest -- verifying node using nonce %d addr=%s\n", mnv.nonce, addr.ToString()); - pnode->PushMessage(NetMsgType::MNVERIFY, mnv); + g_connman->PushMessage(pnode, NetMsgType::MNVERIFY, mnv); return true; } @@ -1150,7 +1150,7 @@ void CMasternodeMan::SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv) return; } - pnode->PushMessage(NetMsgType::MNVERIFY, mnv); + g_connman->PushMessage(pnode, NetMsgType::MNVERIFY, mnv); netfulfilledman.AddFulfilledRequest(pnode->addr, strprintf("%s", NetMsgType::MNVERIFY)+"-reply"); } diff --git a/src/net.cpp b/src/net.cpp index 8cc53081dfa96..1c652767da207 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -411,17 +411,17 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo // Add node CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addrConnect, pszDest ? pszDest : "", false, true); - GetNodeSignals().InitializeNode(pnode->GetId(), pnode); + pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); pnode->nTimeConnected = GetTime(); if(fConnectToMasternode) { pnode->AddRef(); pnode->fMasternode = true; } + GetNodeSignals().InitializeNode(pnode, *this); LOCK(cs_vNodes); vNodes.push_back(pnode); - pnode->nServicesExpected = ServiceFlags(addrConnect.nServices & nRelevantServices); return pnode; } else if (!proxyConnectionFailed) { @@ -468,23 +468,6 @@ void CNode::CloseSocketDisconnect() vRecvMsg.clear(); } -void CNode::PushVersion() -{ - int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); - CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0", 0), addr.nServices)); - CAddress addrMe = GetLocalAddress(&addr, nLocalServices); - if (fLogIPs) - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), addrYou.ToString(), id); - else - LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nMyStartingHeight, addrMe.ToString(), id); - PushMessage(NetMsgType::VERSION, PROTOCOL_VERSION, (uint64_t)nLocalServices, nTime, addrYou, addrMe, - nLocalHostNonce, strSubVersion, nMyStartingHeight, !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)); -} - - - - - void CConnman::ClearBanned() { { @@ -1074,8 +1057,8 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) { } CNode* pnode = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), hSocket, addr, "", true); - GetNodeSignals().InitializeNode(pnode->GetId(), pnode); pnode->fWhitelisted = whitelisted; + GetNodeSignals().InitializeNode(pnode, *this); LogPrint("net", "connection from %s accepted\n", addr.ToString()); @@ -1100,7 +1083,7 @@ void CConnman::ThreadSocketHandler() BOOST_FOREACH(CNode* pnode, vNodesCopy) { if (pnode->fDisconnect || - (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0 && pnode->ssSend.empty())) + (pnode->GetRefCount() <= 0 && pnode->vRecvMsg.empty() && pnode->nSendSize == 0)) { LogPrintf("ThreadSocketHandler -- removing node: peer=%d addr=%s nRefCount=%d fNetworkNode=%d fInbound=%d fMasternode=%d\n", pnode->id, pnode->addr.ToString(), pnode->GetRefCount(), pnode->fNetworkNode, pnode->fInbound, pnode->fMasternode); @@ -1210,10 +1193,6 @@ void CConnman::ThreadSocketHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) { - if (pnode->nOptimisticBytesWritten) { - RecordBytesSent(pnode->nOptimisticBytesWritten); - pnode->nOptimisticBytesWritten = 0; - } if (!pnode->vSendMsg.empty()) { FD_SET(pnode->hSocket, &fdsetSend); continue; @@ -1829,7 +1808,7 @@ void CConnman::ThreadMnbRequestConnections() } // ask for data - pnode->PushMessage(NetMsgType::GETDATA, vToFetch); + PushMessage(pnode, NetMsgType::GETDATA, vToFetch); pnode->Release(); } @@ -2160,7 +2139,7 @@ bool CConnman::Start(boost::thread_group& threadGroup, CScheduler& scheduler, st if (pnodeLocalHost == NULL) { pnodeLocalHost = new CNode(GetNewNodeId(), nLocalServices, GetBestHeight(), INVALID_SOCKET, CAddress(CService("127.0.0.1", 0), nLocalServices)); - GetNodeSignals().InitializeNode(pnodeLocalHost->GetId(), pnodeLocalHost); + GetNodeSignals().InitializeNode(pnodeLocalHost, *this); } // @@ -2579,48 +2558,13 @@ int CConnman::GetBestHeight() const return nBestHeight.load(std::memory_order_acquire); } -void CNode::Fuzz(int nChance) -{ - if (!fSuccessfullyConnected) return; // Don't fuzz initial handshake - if (GetRand(nChance) != 0) return; // Fuzz 1 of every nChance messages - - switch (GetRand(3)) - { - case 0: - // xor a random byte with a random value: - if (!ssSend.empty()) { - CDataStream::size_type pos = GetRand(ssSend.size()); - ssSend[pos] ^= (unsigned char)(GetRand(256)); - } - break; - case 1: - // delete a random byte: - if (!ssSend.empty()) { - CDataStream::size_type pos = GetRand(ssSend.size()); - ssSend.erase(ssSend.begin()+pos); - } - break; - case 2: - // insert a random byte at a random position - { - CDataStream::size_type pos = GetRand(ssSend.size()); - char ch = (char)GetRand(256); - ssSend.insert(ssSend.begin()+pos, ch); - } - break; - } - // Chance of more than one change half the time: - // (more changes exponentially less likely): - Fuzz(2); -} - unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetSendBufferSize() const{ return nSendBufferMaxSize; } CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn, bool fNetworkNodeIn) : - ssSend(SER_NETWORK, INIT_PROTO_VERSION), addrKnown(5000, 0.001), - filterInventoryKnown(50000, 0.000001) + filterInventoryKnown(50000, 0.000001), + nSendVersion(0) { nServices = NODE_NONE; nServicesExpected = NODE_NONE; @@ -2668,7 +2612,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn nMinPingUsecTime = std::numeric_limits::max(); vchKeyedNetGroup = CalculateKeyedNetGroup(addr); id = idIn; - nOptimisticBytesWritten = 0; nLocalServices = nLocalServicesIn; GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); @@ -2685,10 +2628,6 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn LogPrint("net", "Added connection to %s peer=%d\n", addrName, id); else LogPrint("net", "Added connection peer=%d\n", id); - - // Be shy and don't send version until we hear - if (hSocket != INVALID_SOCKET && !fInbound) - PushVersion(); } CNode::~CNode() @@ -2745,69 +2684,6 @@ void CNode::AskFor(const CInv& inv) mapAskFor.insert(std::make_pair(nRequestTime, inv)); } -void CNode::BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend) -{ - ENTER_CRITICAL_SECTION(cs_vSend); - assert(ssSend.size() == 0); - ssSend << CMessageHeader(Params().MessageStart(), pszCommand, 0); - LogPrint("net", "sending: %s ", SanitizeString(pszCommand)); -} - -void CNode::AbortMessage() UNLOCK_FUNCTION(cs_vSend) -{ - ssSend.clear(); - - LEAVE_CRITICAL_SECTION(cs_vSend); - - LogPrint("net", "(aborted)\n"); -} - -void CNode::EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend) -{ - // The -*messagestest options are intentionally not documented in the help message, - // since they are only used during development to debug the networking code and are - // not intended for end-users. - if (mapArgs.count("-dropmessagestest") && GetRand(GetArg("-dropmessagestest", 2)) == 0) - { - LogPrint("net", "dropmessages DROPPING SEND MESSAGE\n"); - AbortMessage(); - return; - } - if (mapArgs.count("-fuzzmessagestest")) - Fuzz(GetArg("-fuzzmessagestest", 10)); - - if (ssSend.size() == 0) - { - LEAVE_CRITICAL_SECTION(cs_vSend); - return; - } - // Set the size - unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE; - WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); - - //log total amount of bytes per command - mapSendBytesPerMsgCmd[std::string(pszCommand)] += nSize + CMessageHeader::HEADER_SIZE; - - // Set the checksum - uint256 hash = Hash(ssSend.begin() + CMessageHeader::HEADER_SIZE, ssSend.end()); - unsigned int nChecksum = 0; - memcpy(&nChecksum, &hash, sizeof(nChecksum)); - assert(ssSend.size () >= CMessageHeader::CHECKSUM_OFFSET + sizeof(nChecksum)); - memcpy((char*)&ssSend[CMessageHeader::CHECKSUM_OFFSET], &nChecksum, sizeof(nChecksum)); - - LogPrint("net", "(%d bytes) peer=%d\n", nSize, id); - - std::deque::iterator it = vSendMsg.insert(vSendMsg.end(), CSerializeData()); - ssSend.GetAndClear(*it); - nSendSize += (*it).size(); - - // If write queue empty, attempt "optimistic write" - if (it == vSendMsg.begin()) - nOptimisticBytesWritten += SocketSendData(this); - - LEAVE_CRITICAL_SECTION(cs_vSend); -} - std::vector CNode::CalculateKeyedNetGroup(CAddress& address) { if(vchSecretKey.size() == 0) { @@ -2829,6 +2705,52 @@ std::vector CNode::CalculateKeyedNetGroup(CAddress& address) return vch; } +CDataStream CConnman::BeginMessage(CNode* pnode, int nVersion, int flags, const std::string& sCommand) +{ + return {SER_NETWORK, (nVersion ? nVersion : pnode->GetSendVersion()) | flags, CMessageHeader(Params().MessageStart(), sCommand.c_str(), 0) }; +} + +void CConnman::EndMessage(CDataStream& strm) +{ + // Set the size + assert(strm.size () >= CMessageHeader::HEADER_SIZE); + unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; + WriteLE32((uint8_t*)&strm[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize); + // Set the checksum + uint256 hash = Hash(strm.begin() + CMessageHeader::HEADER_SIZE, strm.end()); + memcpy((char*)&strm[CMessageHeader::CHECKSUM_OFFSET], hash.begin(), CMessageHeader::CHECKSUM_SIZE); + +} + +void CConnman::PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand) +{ + if(strm.empty()) + return; + + unsigned int nSize = strm.size() - CMessageHeader::HEADER_SIZE; + LogPrint("net", "sending %s (%d bytes) peer=%d\n", SanitizeString(sCommand.c_str()), nSize, pnode->id); + + size_t nBytesSent = 0; + { + LOCK(pnode->cs_vSend); + if(pnode->hSocket == INVALID_SOCKET) { + return; + } + bool optimisticSend(pnode->vSendMsg.empty()); + pnode->vSendMsg.emplace_back(strm.begin(), strm.end()); + + //log total amount of bytes per command + pnode->mapSendBytesPerMsgCmd[sCommand] += strm.size(); + pnode->nSendSize += strm.size(); + + // If write queue empty, attempt "optimistic write" + if (optimisticSend == true) + nBytesSent = SocketSendData(pnode); + } + if (nBytesSent) + RecordBytesSent(nBytesSent); +} + bool CConnman::ForNode(const CService& addr, std::function func) { CNode* found = nullptr; diff --git a/src/net.h b/src/net.h index f0ae9d9776ccf..49b8ca97dd3d3 100644 --- a/src/net.h +++ b/src/net.h @@ -142,6 +142,33 @@ class CConnman bool ForNode(NodeId id, std::function func); bool ForNode(const CService& addr, std::function func); + template + void PushMessageWithVersionAndFlag(CNode* pnode, int nVersion, int flag, const std::string& sCommand, Args&&... args) + { + auto msg(BeginMessage(pnode, nVersion, flag, sCommand)); + ::SerializeMany(msg, msg.nType, msg.nVersion, std::forward(args)...); + EndMessage(msg); + PushMessage(pnode, msg, sCommand); + } + + template + void PushMessageWithFlag(CNode* pnode, int flag, const std::string& sCommand, Args&&... args) + { + PushMessageWithVersionAndFlag(pnode, 0, flag, sCommand, std::forward(args)...); + } + + template + void PushMessageWithVersion(CNode* pnode, int nVersion, const std::string& sCommand, Args&&... args) + { + PushMessageWithVersionAndFlag(pnode, nVersion, 0, sCommand, std::forward(args)...); + } + + template + void PushMessage(CNode* pnode, const std::string& sCommand, Args&&... args) + { + PushMessageWithVersionAndFlag(pnode, 0, 0, sCommand, std::forward(args)...); + } + template bool ForEachNodeContinueIf(Callable&& func) { @@ -352,6 +379,10 @@ class CConnman unsigned int GetReceiveFloodSize() const; + CDataStream BeginMessage(CNode* node, int nVersion, int flags, const std::string& sCommand); + void PushMessage(CNode* pnode, CDataStream& strm, const std::string& sCommand); + void EndMessage(CDataStream& strm); + // Network stats void RecordBytesRecv(uint64_t bytes); void RecordBytesSent(uint64_t bytes); @@ -433,7 +464,7 @@ struct CNodeSignals { boost::signals2::signal ProcessMessages; boost::signals2::signal SendMessages; - boost::signals2::signal InitializeNode; + boost::signals2::signal InitializeNode; boost::signals2::signal FinalizeNode; }; @@ -560,15 +591,14 @@ class CNetMessage { /** Information about a peer */ class CNode { + friend class CConnman; public: // socket ServiceFlags nServices; ServiceFlags nServicesExpected; SOCKET hSocket; - CDataStream ssSend; size_t nSendSize; // total size of all vSendMsg entries size_t nSendOffset; // offset inside the first vSendMsg already sent - uint64_t nOptimisticBytesWritten; uint64_t nSendBytes; std::deque vSendMsg; CCriticalSection cs_vSend; @@ -620,9 +650,6 @@ class CNode mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapRecvBytesPerMsgCmd; - // Basic fuzz-testing - void Fuzz(int nChance); // modifies ssSend - public: uint256 hashContinue; int nStartingHeight; @@ -679,6 +706,7 @@ class CNode uint64_t nLocalHostNonce; ServiceFlags nLocalServices; int nMyStartingHeight; + int nSendVersion; public: NodeId GetId() const { @@ -689,6 +717,10 @@ class CNode return nLocalHostNonce; } + int GetMyStartingHeight() const { + return nMyStartingHeight; + } + int GetRefCount() { LOCK(cs_nRefCount); @@ -715,6 +747,25 @@ class CNode BOOST_FOREACH(CNetMessage &msg, vRecvMsg) msg.SetVersion(nVersionIn); } + void SetSendVersion(int nVersionIn) + { + // Send version may only be changed in the version message, and + // only one version message is allowed per session. We can therefore + // treat this value as const and even atomic as long as it's only used + // once the handshake is complete. Any attempt to set this twice is an + // error. + assert(nSendVersion == 0); + nSendVersion = nVersionIn; + } + + int GetSendVersion() const + { + // The send version should always be explicitly set to + // INIT_PROTO_VERSION rather than using this value until the handshake + // is complete. See PushMessageWithVersion(). + assert(nSendVersion != 0); + return nSendVersion; + } CNode* AddRef() { @@ -781,224 +832,6 @@ class CNode void AskFor(const CInv& inv); - // TODO: Document the postcondition of this function. Is cs_vSend locked? - void BeginMessage(const char* pszCommand) EXCLUSIVE_LOCK_FUNCTION(cs_vSend); - - // TODO: Document the precondition of this function. Is cs_vSend locked? - void AbortMessage() UNLOCK_FUNCTION(cs_vSend); - - // TODO: Document the precondition of this function. Is cs_vSend locked? - void EndMessage(const char* pszCommand) UNLOCK_FUNCTION(cs_vSend); - - void PushVersion(); - - - void PushMessage(const char* pszCommand) - { - try - { - BeginMessage(pszCommand); - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1) - { - try - { - BeginMessage(pszCommand); - ssSend << a1; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10, const T11& a11) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10 << a11; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - - template - void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5, const T6& a6, const T7& a7, const T8& a8, const T9& a9, const T10& a10, const T11& a11, const T12& a12) - { - try - { - BeginMessage(pszCommand); - ssSend << a1 << a2 << a3 << a4 << a5 << a6 << a7 << a8 << a9 << a10 << a11 << a12; - EndMessage(pszCommand); - } - catch (...) - { - AbortMessage(); - throw; - } - } - void CloseSocketDisconnect(); void copyStats(CNodeStats &stats); diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 8ee4fd028935f..cde47427bf022 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -552,7 +552,7 @@ bool CPrivateSendClient::SignFinalTransaction(const CTransaction& finalTransacti // push all of our signatures to the Masternode LogPrintf("CPrivateSendClient::SignFinalTransaction -- pushing sigs to the masternode, finalMutableTransaction=%s", finalMutableTransaction.ToString()); - pnode->PushMessage(NetMsgType::DSSIGNFINALTX, sigs); + g_connman->PushMessage(pnode, NetMsgType::DSSIGNFINALTX, sigs); SetState(POOL_STATE_SIGNING); nTimeLastSuccessfulStep = GetTimeMillis(); @@ -870,7 +870,7 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized) infoMixingMasternode = infoMn; nSessionDenom = dsq.nDenom; - pnode->PushMessage(NetMsgType::DSACCEPT, nSessionDenom, txMyCollateral); + g_connman->PushMessage(pnode, NetMsgType::DSACCEPT, nSessionDenom, txMyCollateral); LogPrintf("CPrivateSendClient::JoinExistingQueue -- connected (from queue), sending DSACCEPT: nSessionDenom: %d (%s), addr=%s\n", nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), pnode->addr.ToString()); strAutoDenomResult = _("Mixing in progress..."); @@ -953,7 +953,7 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA nSessionDenom = CPrivateSend::GetDenominationsByAmounts(vecAmounts); } - pnode->PushMessage(NetMsgType::DSACCEPT, nSessionDenom, txMyCollateral); + g_connman->PushMessage(pnode, NetMsgType::DSACCEPT, nSessionDenom, txMyCollateral); LogPrintf("CPrivateSendClient::StartNewQueue -- connected, sending DSACCEPT, nSessionDenom: %d (%s)\n", nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); strAutoDenomResult = _("Mixing in progress..."); @@ -1374,7 +1374,7 @@ void CPrivateSendClient::RelayIn(const CDarkSendEntry& entry) g_connman->ForNode(infoMixingMasternode.addr, [&entry](CNode* pnode) { LogPrintf("CPrivateSendClient::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString()); - pnode->PushMessage(NetMsgType::DSVIN, entry); + g_connman->PushMessage(pnode, NetMsgType::DSVIN, entry); return true; }); } diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 0eb592f70989f..8a3b58e119bbd 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -802,7 +802,7 @@ void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal) // final mixing tx with empty signatures should be relayed to mixing participants only for (const auto entry : vecEntries) { bool fOk = g_connman->ForNode(entry.addr, [&txFinal, this](CNode* pnode) { - pnode->PushMessage(NetMsgType::DSFINALTX, nSessionID, txFinal); + g_connman->PushMessage(pnode, NetMsgType::DSFINALTX, nSessionID, txFinal); return true; }); if(!fOk) { @@ -816,7 +816,7 @@ void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal) void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID) { if(!pnode) return; - pnode->PushMessage(NetMsgType::DSSTATUSUPDATE, nSessionID, (int)nState, (int)vecEntries.size(), (int)nStatusUpdate, (int)nMessageID); + g_connman->PushMessage(pnode, NetMsgType::DSSTATUSUPDATE, nSessionID, (int)nState, (int)vecEntries.size(), (int)nStatusUpdate, (int)nMessageID); } void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID) @@ -863,7 +863,7 @@ void CPrivateSendServer::RelayCompletedTransaction(PoolMessage nMessageID) // final mixing tx with empty signatures should be relayed to mixing participants only for (const auto entry : vecEntries) { bool fOk = g_connman->ForNode(entry.addr, [&nMessageID, this](CNode* pnode) { - pnode->PushMessage(NetMsgType::DSCOMPLETE, nSessionID, (int)nMessageID); + g_connman->PushMessage(pnode, NetMsgType::DSCOMPLETE, nSessionID, (int)nMessageID); return true; }); if(!fOk) { diff --git a/src/privatesend.cpp b/src/privatesend.cpp index 31efaa80a8631..bc2503417da40 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -77,7 +77,7 @@ bool CDarksendQueue::Relay() std::vector vNodesCopy = g_connman->CopyNodeVector(); BOOST_FOREACH(CNode* pnode, vNodesCopy) if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) - pnode->PushMessage(NetMsgType::DSQUEUE, (*this)); + g_connman->PushMessage(pnode, NetMsgType::DSQUEUE, (*this)); g_connman->ReleaseNodeVector(vNodesCopy); return true; diff --git a/src/sendalert.cpp b/src/sendalert.cpp index 53cd3fc847bf2..cbc1bc6369ef9 100644 --- a/src/sendalert.cpp +++ b/src/sendalert.cpp @@ -101,7 +101,7 @@ void ThreadSendAlert(CConnman& connman) int nSent = 0; { g_connman->ForEachNode([&alert2, &nSent](CNode* pnode) { - if (alert2.RelayTo(pnode)) + if (alert2.RelayTo(pnode, *g_connman)) { printf("ThreadSendAlert() : Sent alert to %s\n", pnode->addr.ToString().c_str()); nSent++; diff --git a/src/serialize.h b/src/serialize.h index 649fe69728aee..cf4267f6b47cf 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -173,6 +173,7 @@ enum }; #define READWRITE(obj) (::SerReadWrite(s, (obj), nType, nVersion, ser_action)) +#define READWRITEMANY(...) (::SerReadWriteMany(s, nType, nVersion, ser_action, __VA_ARGS__)) /** * Implement three methods for serializable objects. These are actually wrappers over @@ -983,4 +984,52 @@ class CSizeComputer } }; +template +void SerializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); +} + +template +void SerializeMany(Stream& s, int nType, int nVersion, Arg&& arg, Args&&... args) +{ + ::Serialize(s, std::forward(arg), nType, nVersion); + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion) +{ +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg) +{ + ::Unserialize(s, arg, nType, nVersion); +} + +template +inline void UnserializeMany(Stream& s, int nType, int nVersion, Arg& arg, Args&... args) +{ + ::Unserialize(s, arg, nType, nVersion); + ::UnserializeMany(s, nType, nVersion, args...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionSerialize ser_action, Args&&... args) +{ + ::SerializeMany(s, nType, nVersion, std::forward(args)...); +} + +template +inline void SerReadWriteMany(Stream& s, int nType, int nVersion, CSerActionUnserialize ser_action, Args&... args) +{ + ::UnserializeMany(s, nType, nVersion, args...); +} + #endif // BITCOIN_SERIALIZE_H diff --git a/src/spork.cpp b/src/spork.cpp index 788f7ac08737b..af4ad9480695a 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -64,7 +64,7 @@ void CSporkManager::ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStr std::map::iterator it = mapSporksActive.begin(); while(it != mapSporksActive.end()) { - pfrom->PushMessage(NetMsgType::SPORK, it->second); + g_connman->PushMessage(pfrom, NetMsgType::SPORK, it->second); it++; } } diff --git a/src/streams.h b/src/streams.h index 0fc6135a6a793..3d887feb3b765 100644 --- a/src/streams.h +++ b/src/streams.h @@ -79,6 +79,13 @@ class CDataStream Init(nTypeIn, nVersionIn); } + template + CDataStream(int nTypeIn, int nVersionIn, Args&&... args) + { + Init(nTypeIn, nVersionIn); + ::SerializeMany(*this, nType, nVersion, std::forward(args)...); + } + void Init(int nTypeIn, int nVersionIn) { nReadPos = 0; diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index cc65784d2cf75..16f596414ca51 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -49,7 +49,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning) connman->ClearBanned(); CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); - GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); + dummyNode1.SetSendVersion(PROTOCOL_VERSION); + GetNodeSignals().InitializeNode(&dummyNode1, *connman); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); // Should get banned SendMessages(&dummyNode1, *connman); @@ -58,7 +59,8 @@ BOOST_AUTO_TEST_CASE(DoS_banning) CAddress addr2(ip(0xa0b0c002), NODE_NONE); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, "", true); - GetNodeSignals().InitializeNode(dummyNode2.GetId(), &dummyNode2); + dummyNode2.SetSendVersion(PROTOCOL_VERSION); + GetNodeSignals().InitializeNode(&dummyNode2, *connman); dummyNode2.nVersion = 1; Misbehaving(dummyNode2.GetId(), 50); SendMessages(&dummyNode2, *connman); @@ -75,7 +77,8 @@ BOOST_AUTO_TEST_CASE(DoS_banscore) mapArgs["-banscore"] = "111"; // because 11 is my favorite number CAddress addr1(ip(0xa0b0c001), NODE_NONE); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, "", true); - GetNodeSignals().InitializeNode(dummyNode1.GetId(), &dummyNode1); + dummyNode1.SetSendVersion(PROTOCOL_VERSION); + GetNodeSignals().InitializeNode(&dummyNode1, *connman); dummyNode1.nVersion = 1; Misbehaving(dummyNode1.GetId(), 100); SendMessages(&dummyNode1, *connman); @@ -97,7 +100,8 @@ BOOST_AUTO_TEST_CASE(DoS_bantime) CAddress addr(ip(0xa0b0c001), NODE_NONE); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, "", true); - GetNodeSignals().InitializeNode(dummyNode.GetId(), &dummyNode); + dummyNode.SetSendVersion(PROTOCOL_VERSION); + GetNodeSignals().InitializeNode(&dummyNode, *connman); dummyNode.nVersion = 1; Misbehaving(dummyNode.GetId(), 100); diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index 3b76f2129d374..0a253e1fe5c4d 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -10,11 +10,54 @@ #include #include - using namespace std; BOOST_FIXTURE_TEST_SUITE(serialize_tests, BasicTestingSetup) +class CSerializeMethodsTestSingle +{ +protected: + int intval; + bool boolval; + std::string stringval; + const char* charstrval; + CTransaction txval; +public: + CSerializeMethodsTestSingle() = default; + CSerializeMethodsTestSingle(int intvalin, bool boolvalin, std::string stringvalin, const char* charstrvalin, CTransaction txvalin) : intval(intvalin), boolval(boolvalin), stringval(std::move(stringvalin)), charstrval(charstrvalin), txval(txvalin){} + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(intval); + READWRITE(boolval); + READWRITE(stringval); + READWRITE(FLATDATA(charstrval)); + READWRITE(txval); + } + + bool operator==(const CSerializeMethodsTestSingle& rhs) + { + return intval == rhs.intval && \ + boolval == rhs.boolval && \ + stringval == rhs.stringval && \ + strcmp(charstrval, rhs.charstrval) == 0 && \ + txval == rhs.txval; + } +}; + +class CSerializeMethodsTestMany : public CSerializeMethodsTestSingle +{ +public: + using CSerializeMethodsTestSingle::CSerializeMethodsTestSingle; + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITEMANY(intval, boolval, stringval, FLATDATA(charstrval), txval); + } +}; + BOOST_AUTO_TEST_CASE(sizes) { BOOST_CHECK_EQUAL(sizeof(char), GetSerializeSize(char(0), 0)); @@ -325,4 +368,30 @@ BOOST_AUTO_TEST_CASE(check_backward_compatibility) BOOST_REQUIRE(new_src.field1 == old_dest.field1); } +BOOST_AUTO_TEST_CASE(class_methods) +{ + int intval(100); + bool boolval(true); + std::string stringval("testing"); + const char* charstrval("testing charstr"); + CMutableTransaction txval; + CSerializeMethodsTestSingle methodtest1(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestMany methodtest2(intval, boolval, stringval, charstrval, txval); + CSerializeMethodsTestSingle methodtest3; + CSerializeMethodsTestMany methodtest4; + CDataStream ss(SER_DISK, PROTOCOL_VERSION); + BOOST_CHECK(methodtest1 == methodtest2); + ss << methodtest1; + ss >> methodtest4; + ss << methodtest2; + ss >> methodtest3; + BOOST_CHECK(methodtest1 == methodtest2); + BOOST_CHECK(methodtest2 == methodtest3); + BOOST_CHECK(methodtest3 == methodtest4); + + CDataStream ss2(SER_DISK, PROTOCOL_VERSION, intval, boolval, stringval, FLATDATA(charstrval), txval); + ss2 >> methodtest3; + BOOST_CHECK(methodtest3 == methodtest4); +} + BOOST_AUTO_TEST_SUITE_END()