From 9694658cd3f44d20cb71370c1f03ce6eb27f6a6a Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Tue, 25 Jul 2017 13:57:26 +0300 Subject: [PATCH] Make sure mixing messages are relayed/accepted properly (#1547) * make sure addr of mixing mn matches peer's addr exactly (including port) * Store addr of every mixing client and relay mixing mesasges to them only --- src/privatesend-client.cpp | 8 ++--- src/privatesend-server.cpp | 69 +++++++++++++++++++++++++++++++++----- src/privatesend.cpp | 2 +- src/privatesend.h | 5 ++- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 76a1cabb67..8ee4fd0289 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -60,7 +60,7 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C // if the queue is ready, submit if we can if(dsq.fReady) { if(!infoMixingMasternode.fInfoValid) return; - if((CNetAddr)infoMixingMasternode.addr != (CNetAddr)infoMn.addr) { + if(infoMixingMasternode.addr != infoMn.addr) { LogPrintf("DSQUEUE -- message doesn't match current Masternode: infoMixingMasternode=%s, addr=%s\n", infoMixingMasternode.addr.ToString(), infoMn.addr.ToString()); return; } @@ -105,7 +105,7 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } if(!infoMixingMasternode.fInfoValid) return; - if((CNetAddr)infoMixingMasternode.addr != (CNetAddr)pfrom->addr) { + if(infoMixingMasternode.addr != pfrom->addr) { //LogPrintf("DSSTATUSUPDATE -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); return; } @@ -149,7 +149,7 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } if(!infoMixingMasternode.fInfoValid) return; - if((CNetAddr)infoMixingMasternode.addr != (CNetAddr)pfrom->addr) { + if(infoMixingMasternode.addr != pfrom->addr) { //LogPrintf("DSFINALTX -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); return; } @@ -176,7 +176,7 @@ void CPrivateSendClient::ProcessMessage(CNode* pfrom, std::string& strCommand, C } if(!infoMixingMasternode.fInfoValid) return; - if((CNetAddr)infoMixingMasternode.addr != (CNetAddr)pfrom->addr) { + if(infoMixingMasternode.addr != pfrom->addr) { LogPrint("privatesend", "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); return; } diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 18fd52fa73..0eb592f709 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -229,6 +229,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C PoolMessage nMessageID = MSG_NOERR; + entry.addr = pfrom->addr; if(AddEntry(entry, nMessageID)) { PushStatus(pfrom, STATUS_ACCEPTED, nMessageID); CheckPool(); @@ -795,10 +796,21 @@ bool CPrivateSendServer::AddUserToExistingSession(int nDenom, CTransaction txCol void CPrivateSendServer::RelayFinalTransaction(const CTransaction& txFinal) { - g_connman->ForEachNode([&txFinal, this](CNode* pnode) { - if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) + LogPrint("privatesend", "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n", + __func__, nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); + + // 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); - }); + return true; + }); + if(!fOk) { + // no such node? maybe this client disconnected or our own connection went down + RelayStatus(STATUS_REJECTED); + break; + } + } } void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID) @@ -809,18 +821,57 @@ void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID) { - g_connman->ForEachNode([nStatusUpdate, nMessageID, this](CNode* pnode) { - if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) + unsigned int nDisconnected{}; + // status updates should be relayed to mixing participants only + for (const auto entry : vecEntries) { + // make sure everyone is still connected + bool fOk = g_connman->ForNode(entry.addr, [&nStatusUpdate, &nMessageID, this](CNode* pnode) { PushStatus(pnode, nStatusUpdate, nMessageID); - }); + return true; + }); + if(!fOk) { + // no such node? maybe this client disconnected or our own connection went down + ++nDisconnected; + } + } + if (nDisconnected == 0) return; // all is clear + + // smth went wrong + LogPrintf("CPrivateSendServer::%s -- can't continue, %llu client(s) disconnected, nSessionID: %d nSessionDenom: %d (%s)\n", + __func__, nDisconnected, nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); + + // notify everyone else that this session should be terminated + for (const auto entry : vecEntries) { + g_connman->ForNode(entry.addr, [this](CNode* pnode) { + PushStatus(pnode, STATUS_REJECTED, MSG_NOERR); + return true; + }); + } + + if(nDisconnected == vecEntries.size()) { + // all clients disconnected, there is probably some issues with our own connection + // do not charge any fees, just reset the pool + SetNull(); + } } void CPrivateSendServer::RelayCompletedTransaction(PoolMessage nMessageID) { - g_connman->ForEachNode([nMessageID, this](CNode* pnode) { - if(pnode->nVersion >= MIN_PRIVATESEND_PEER_PROTO_VERSION) + LogPrint("privatesend", "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n", + __func__, nSessionID, nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom)); + + // 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); - }); + return true; + }); + if(!fOk) { + // no such node? maybe client disconnected or our own connection went down + RelayStatus(STATUS_REJECTED); + break; + } + } } void CPrivateSendServer::SetState(PoolState nStateNew) diff --git a/src/privatesend.cpp b/src/privatesend.cpp index a4f1957860..31efaa80a8 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -20,7 +20,7 @@ #include CDarkSendEntry::CDarkSendEntry(const std::vector& vecTxIn, const std::vector& vecTxOut, const CTransaction& txCollateral) : - txCollateral(txCollateral) + txCollateral(txCollateral), addr(CService()) { BOOST_FOREACH(CTxIn txin, vecTxIn) vecTxDSIn.push_back(txin); diff --git a/src/privatesend.h b/src/privatesend.h index 504c89c0be..bbdfa1c6b1 100644 --- a/src/privatesend.h +++ b/src/privatesend.h @@ -117,11 +117,14 @@ public: std::vector vecTxDSIn; std::vector vecTxDSOut; CTransaction txCollateral; + // memory only + CService addr; CDarkSendEntry() : vecTxDSIn(std::vector()), vecTxDSOut(std::vector()), - txCollateral(CTransaction()) + txCollateral(CTransaction()), + addr(CService()) {} CDarkSendEntry(const std::vector& vecTxIn, const std::vector& vecTxOut, const CTransaction& txCollateral);