PIVX Core  5.6.99
P2P Digital Currency
tiertwo_networksync.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-2022 The PIVX Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or https://www.opensource.org/licenses/mit-license.php.
4 
5 #include "masternode-sync.h"
6 
10 #include "llmq/quorums_signing.h"
12 #include "masternodeman.h" // for mnodeman
13 #include "net_processing.h" // for Misbehaving
14 #include "netmessagemaker.h"
15 #include "spork.h" // for sporkManager
16 #include "streams.h" // for CDataStream
18 
19 
20 // Update in-flight message status if needed
21 bool CMasternodeSync::UpdatePeerSyncState(const NodeId& id, const char* msg, const int nextSyncStatus)
22 {
23  auto it = peersSyncState.find(id);
24  if (it != peersSyncState.end()) {
25  auto peerData = it->second;
26  auto msgMapIt = peerData.mapMsgData.find(msg);
27  if (msgMapIt != peerData.mapMsgData.end()) {
28  // exists, let's update the received status and the sync state.
29 
30  // future: these boolean will not be needed once the peer syncState status gets implemented.
31  msgMapIt->second.second = true;
32  LogPrintf("%s: %s message updated peer sync state\n", __func__, msgMapIt->first);
33 
34  // Only update sync status if we really need it. Otherwise, it's just good redundancy to verify data several times.
35  if (g_tiertwo_sync_state.GetSyncPhase() < nextSyncStatus) {
36  // todo: this should only happen if more than N peers have sent the data.
37  // move overall tier two sync state to the next one if needed.
38  LogPrintf("%s: moving to next assset %s\n", __func__, nextSyncStatus);
40  }
41  return true;
42  }
43  }
44  return false;
45 }
46 
47 bool CMasternodeSync::MessageDispatcher(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
48 {
49  if (strCommand == NetMsgType::GETSPORKS) {
50  // send sporks
51  sporkManager.ProcessGetSporks(pfrom, strCommand, vRecv);
52  return true;
53  }
54 
55  if (strCommand == NetMsgType::QFCOMMITMENT) {
56  // Only process qfc if v6.0.0 is enforced.
57  if (!deterministicMNManager->IsDIP3Enforced()) return true; // nothing to do.
58  int retMisbehavingScore{0};
59  llmq::quorumBlockProcessor->ProcessMessage(pfrom, vRecv, retMisbehavingScore);
60  if (retMisbehavingScore > 0) {
61  WITH_LOCK(cs_main, Misbehaving(pfrom->GetId(), retMisbehavingScore));
62  }
63  return true;
64  }
65 
66  if (strCommand == NetMsgType::QCONTRIB
67  || strCommand == NetMsgType::QCOMPLAINT
68  || strCommand == NetMsgType::QJUSTIFICATION
69  || strCommand == NetMsgType::QPCOMMITMENT) {
70  if (!llmq::quorumDKGSessionManager->ProcessMessage(pfrom, strCommand, vRecv)) {
71  WITH_LOCK(cs_main, Misbehaving(pfrom->GetId(), 100));
72  }
73  return true;
74  }
75  if (strCommand == NetMsgType::QSIGSHARESINV || strCommand == NetMsgType::QGETSIGSHARES || strCommand == NetMsgType::QBSIGSHARES || strCommand == NetMsgType::QSIGSESANN || strCommand == NetMsgType::QSIGSHARE) {
76  llmq::quorumSigSharesManager->ProcessMessage(pfrom, strCommand, vRecv, *g_connman);
77  return true;
78  }
79  if (strCommand == NetMsgType::QSIGREC) {
80  llmq::quorumSigningManager->ProcessMessage(pfrom, strCommand, vRecv, *g_connman);
81  return true;
82  }
83 
84  if (strCommand == NetMsgType::CLSIG) {
85  llmq::chainLocksHandler->ProcessMessage(pfrom, strCommand, vRecv, *g_connman);
86  }
87 
88  if (strCommand == NetMsgType::GETMNLIST) {
89  // Get Masternode list or specific entry
90  CTxIn vin;
91  vRecv >> vin;
92  int banScore = mnodeman.ProcessGetMNList(pfrom, vin);
93  if (banScore > 0) {
94  LOCK(cs_main);
95  Misbehaving(pfrom->GetId(), banScore);
96  }
97  return true;
98  }
99 
100  if (strCommand == NetMsgType::SPORK) {
101  // as there is no completion message, this is using a SPORK_INVALID as final message for now.
102  // which is just a hack, should be replaced with another message, guard it until the protocol gets deployed on mainnet and
103  // add compatibility with the previous protocol as well.
105  vRecv >> spork;
106  int banScore = sporkManager.ProcessSporkMsg(spork);
107  if (banScore > 0) {
108  LOCK(cs_main);
109  Misbehaving(pfrom->GetId(), banScore);
110  return true;
111  }
112  // All good, Update in-flight message status if needed
114  // This could happen because of the message thread is requesting the sporks alone..
115  // So.. for now, can just update the peer status and move it to the next state if the end message arrives
116  if (spork.nSporkID == SPORK_INVALID) {
118  // future note: use internal cs for RequestedMasternodeAssets.
120  }
121  }
122  }
123  return true;
124  }
125 
126  if (strCommand == NetMsgType::SYNCSTATUSCOUNT) {
127  // Nothing to do.
129 
130  // Sync status count
131  int nItemID;
132  int nCount;
133  vRecv >> nItemID >> nCount;
134 
135  // Update stats
136  ProcessSyncStatusMsg(nItemID, nCount);
137 
138  // this means we will receive no further communication on the first sync
139  switch (nItemID) {
140  case MASTERNODE_SYNC_LIST: {
142  return true;
143  }
144  case MASTERNODE_SYNC_MNW: {
146  return true;
147  }
149  // TODO: This could be a MASTERNODE_SYNC_BUDGET_FIN as well, possibly should decouple the finalization budget sync
150  // from the MASTERNODE_SYNC_BUDGET_PROP (both are under the BUDGETVOTESYNC message)
152  return true;
153  }
155  // No need to handle this one, is handled by the proposals sync message for now..
156  return true;
157  }
158  }
159  }
160 
161  return false;
162 }
163 
164 template <typename... Args>
165 void CMasternodeSync::PushMessage(CNode* pnode, const char* msg, Args&&... args)
166 {
167  g_connman->PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(msg, std::forward<Args>(args)...));
168 }
169 
170 template <typename... Args>
171 void CMasternodeSync::RequestDataTo(CNode* pnode, const char* msg, bool forceRequest, Args&&... args)
172 {
173  const auto& it = peersSyncState.find(pnode->GetId());
174  bool exist = it != peersSyncState.end();
175  if (!exist || forceRequest) {
176  // Erase it if this is a forced request
177  if (exist) {
178  peersSyncState.at(pnode->GetId()).mapMsgData.erase(msg);
179  }
180  // send the message
181  PushMessage(pnode, msg, std::forward<Args>(args)...);
182 
183  // Add data to the tier two peers sync state
184  TierTwoPeerData peerData;
185  peerData.mapMsgData.emplace(msg, std::make_pair(GetTime(), false));
186  peersSyncState.emplace(pnode->GetId(), peerData);
187  } else {
188  // Check if we have sent the message or not
189  TierTwoPeerData& peerData = it->second;
190  const auto& msgMapIt = peerData.mapMsgData.find(msg);
191 
192  if (msgMapIt == peerData.mapMsgData.end()) {
193  // message doesn't exist, push it and add it to the map.
194  PushMessage(pnode, msg, std::forward<Args>(args)...);
195  peerData.mapMsgData.emplace(msg, std::make_pair(GetTime(), false));
196  } else {
197  // message sent, next step: need to check if it was already answered or not.
198  // And, if needed, request it again every certain amount of time.
199 
200  // Check if the node answered the message or not
201  if (!msgMapIt->second.second) {
202  int64_t lastRequestTime = msgMapIt->second.first;
203  if (lastRequestTime + 600 < GetTime()) {
204  // ten minutes passed. Let's ask it again.
205  RequestDataTo(pnode, msg, true, std::forward<Args>(args)...);
206  }
207  }
208 
209  }
210  }
211 }
212 
214 {
215  // skip mn list and winners sync if legacy mn are obsolete
216  int syncPhase = g_tiertwo_sync_state.GetSyncPhase();
217  if (deterministicMNManager->LegacyMNObsolete() &&
218  (syncPhase == MASTERNODE_SYNC_LIST || syncPhase == MASTERNODE_SYNC_MNW)) {
220  syncPhase = g_tiertwo_sync_state.GetSyncPhase();
221  }
222 
223  // Initial sync, verify that the other peer answered to all of the messages successfully
224  if (syncPhase == MASTERNODE_SYNC_SPORKS) {
225  RequestDataTo(pnode, NetMsgType::GETSPORKS, false);
226  } else if (syncPhase == MASTERNODE_SYNC_LIST) {
227  RequestDataTo(pnode, NetMsgType::GETMNLIST, false, CTxIn());
228  } else if (syncPhase == MASTERNODE_SYNC_MNW) {
230  } else if (syncPhase == MASTERNODE_SYNC_BUDGET) {
231  // sync masternode votes
233  } else if (syncPhase == MASTERNODE_SYNC_FINISHED) {
234  LogPrintf("REGTEST SYNC FINISHED!\n");
235  }
236 }
237 
int CountEnabled(bool only_legacy=false) const
int ProcessGetMNList(CNode *pfrom, CTxIn &vin)
std::map< NodeId, TierTwoPeerData > peersSyncState
void ProcessSyncStatusMsg(int nItemID, int itemCount)
void RequestDataTo(CNode *pnode, const char *msg, bool forceRequest, Args &&... args)
void PushMessage(CNode *pnode, const char *msg, Args &&... args)
static int GetNextAsset(int currentAsset)
void SyncRegtest(CNode *pnode)
bool UpdatePeerSyncState(const NodeId &id, const char *msg, const int nextSyncStatus)
bool MessageDispatcher(CNode *pfrom, std::string &strCommand, CDataStream &vRecv)
CSerializedNetMsg Make(int nFlags, std::string sCommand, Args &&... args)
Information about a peer.
Definition: net.h:669
NodeId GetId() const
Definition: net.h:825
int GetSendVersion() const
Definition: net.cpp:789
void ProcessGetSporks(CNode *pfrom, std::string &strCommand, CDataStream &vRecv)
Definition: spork.cpp:174
int ProcessSporkMsg(CDataStream &vRecv)
Definition: spork.cpp:101
An input of a transaction.
Definition: transaction.h:94
int GetSyncPhase() const
void SetCurrentSyncPhase(int sync_phase)
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
CMasternodeMan mnodeman
Masternode manager.
UniValue spork(const JSONRPCRequest &request)
Definition: misc.cpp:286
const char * QFCOMMITMENT
The qfcommit message is used to propagate LLMQ final commitments.
Definition: protocol.cpp:56
const char * BUDGETVOTESYNC
The budgetvotesync message is used to request budget vote data from connected peers.
Definition: protocol.cpp:51
const char * GETMNLIST
The dseg message is used to request the Masternode list or an specific entry.
Definition: protocol.cpp:55
const char * QSIGSESANN
Definition: protocol.cpp:63
const char * GETMNWINNERS
The getmnwinners message is used to request winning masternode data from connected peers.
Definition: protocol.cpp:48
const char * QGETSIGSHARES
Definition: protocol.cpp:65
const char * QBSIGSHARES
Definition: protocol.cpp:66
const char * QSIGREC
Definition: protocol.cpp:67
const char * QCONTRIB
Definition: protocol.cpp:59
const char * QPCOMMITMENT
Definition: protocol.cpp:62
const char * QCOMPLAINT
Definition: protocol.cpp:60
const char * QSIGSHARE
Definition: protocol.cpp:68
const char * QJUSTIFICATION
Definition: protocol.cpp:61
const char * SYNCSTATUSCOUNT
The syncstatuscount message is used to track the layer 2 syncing process.
Definition: protocol.cpp:54
const char * CLSIG
Definition: protocol.cpp:69
const char * SPORK
The spork message is used to send spork values to connected peers.
Definition: protocol.cpp:42
const char * GETSPORKS
The getsporks message is used to request spork data from connected peers.
Definition: protocol.cpp:43
const char * QSIGSHARESINV
Definition: protocol.cpp:64
std::unique_ptr< CQuorumBlockProcessor > quorumBlockProcessor
std::unique_ptr< CDKGSessionManager > quorumDKGSessionManager
std::unique_ptr< CSigningManager > quorumSigningManager
std::unique_ptr< CSigSharesManager > quorumSigSharesManager
std::unique_ptr< CChainLocksHandler > chainLocksHandler
int NodeId
Definition: net.h:109
void Misbehaving(NodeId pnode, int howmuch, const std::string &message) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Increase a node's misbehavior score.
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
CSporkManager sporkManager
Definition: spork.cpp:29
@ SPORK_INVALID
Definition: sporkid.h:32
std::map< const char *, std::pair< int64_t, bool > > mapMsgData
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
TierTwoSyncState g_tiertwo_sync_state
#define MASTERNODE_SYNC_MNW
#define MASTERNODE_SYNC_SPORKS
#define MASTERNODE_SYNC_BUDGET_PROP
#define MASTERNODE_SYNC_BUDGET
#define MASTERNODE_SYNC_BUDGET_FIN
#define MASTERNODE_SYNC_FINISHED
#define MASTERNODE_SYNC_LIST
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27