PIVX Core  5.6.99
P2P Digital Currency
quorums_signing.h
Go to the documentation of this file.
1 // Copyright (c) 2018-2022 The Dash Core developers
2 // Copyright (c) 2023 The PIVX Core developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #ifndef PIVX_LLMQ_QUORUMS_SIGNING_H
7 #define PIVX_LLMQ_QUORUMS_SIGNING_H
8 
9 #include "llmq/quorums.h"
10 
11 #include "chainparams.h"
12 #include "net.h"
13 #include "saltedhasher.h"
14 #include "sync.h"
15 #include "unordered_lru_cache.h"
16 
17 #include <unordered_map>
18 
19 namespace llmq
20 {
21 
23 {
24 public:
25  uint8_t llmqType;
30 
31  // only in-memory
33 
34 public:
36  {
37  READWRITE(obj.llmqType);
38  READWRITE(obj.quorumHash);
39  READWRITE(obj.id);
40  READWRITE(obj.msgHash);
41  READWRITE(obj.sig);
42  SER_READ(obj, obj.UpdateHash());
43  }
44 
45  void UpdateHash()
46  {
47  hash = ::SerializeHash(*this);
48  }
49 
50  const uint256& GetHash() const
51  {
52  assert(!hash.IsNull());
53  return hash;
54  }
55 };
56 
58 {
59 private:
61 
66 
67 public:
68  explicit CRecoveredSigsDb(CDBWrapper& _db);
69 
71  void AddVoteTimeKeys();
72 
73  bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash);
74  bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id);
75  bool HasRecoveredSigForSession(const uint256& signHash);
76  bool HasRecoveredSigForHash(const uint256& hash);
77  bool GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret);
78  bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret);
79  void WriteRecoveredSig(const CRecoveredSig& recSig);
80  void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id);
81  void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id);
82 
83  void CleanupOldRecoveredSigs(int64_t maxAge);
84 
85  // votes are removed when the recovered sig is written to the db
86  bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id);
87  bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet);
88  void WriteVoteForId(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash);
89 
90  void CleanupOldVotes(int64_t maxAge);
91 
92 private:
93  bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret);
94  void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey);
95 };
96 
98 {
99 public:
101 
102  virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) = 0;
103 };
104 
106 {
107  friend class CSigSharesManager;
108  static const int64_t DEFAULT_MAX_RECOVERED_SIGS_AGE = 60 * 60 * 24 * 7; // keep them for a week
109 
110  // when selecting a quorum for signing and verification, we use CQuorumManager::SelectQuorum with this offset as
111  // starting height for scanning. This is because otherwise the resulting signatures would not be verifiable by nodes
112  // which are not 100% at the chain tip.
113  static const int SIGN_HEIGHT_OFFSET = 8;
114 
115 private:
117 
119 
120  // Incoming and not verified yet
121  std::unordered_map<NodeId, std::list<CRecoveredSig>> pendingRecoveredSigs;
122 
123  // must be protected by cs
125 
126  int64_t lastCleanupTime{0};
127 
128  std::vector<CRecoveredSigsListener*> recoveredSigsListeners;
129 
130 public:
131  CSigningManager(CDBWrapper& llmqDb, bool fMemory);
132 
133  bool AlreadyHave(const CInv& inv);
134  bool GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret);
135 
136  void ProcessMessage(CNode* pnode, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
137 
138  // This is called when a recovered signature can be safely removed from the DB. This is only safe when some other
139  // mechanism prevents possible conflicts. As an example, ChainLocks prevent conflicts in confirmed TXs InstantSend votes
140  // This won't completely remove all traces of the recovered sig but instead leave the hash entry in the DB. This
141  // allows AlreadyHave to keep returning true. Cleanup will later remove the remains
142  void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id);
143 
144 private:
145  void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman);
146  bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, bool& retBan);
147 
148  void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions,
149  std::unordered_map<NodeId, std::list<CRecoveredSig>>& retSigShares,
150  std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
151  bool ProcessPendingRecoveredSigs(CConnman& connman); // called from the worker thread of CSigSharesManager
152  void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig, const CQuorumCPtr& quorum, CConnman& connman);
153  void Cleanup(); // called from the worker thread of CSigSharesManager
154 
155 public:
156  // public interface
159  bool AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, bool allowReSign = false);
160  bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash);
161  bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id);
162  bool HasRecoveredSigForSession(const uint256& signHash);
163  bool IsConflicting(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash);
164  bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id);
165  bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet);
166 
167  std::vector<CQuorumCPtr> GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight);
168  CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, const uint256& selectionHash, int signHeight = -1 /*chain tip*/, int signOffset = SIGN_HEIGHT_OFFSET);
169  // Verifies a recovered sig that was signed while the chain tip was at signedAtTip
170  bool VerifyRecoveredSig(Consensus::LLMQType llmqType, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig);
171 };
172 
173 extern std::unique_ptr<CSigningManager> quorumSigningManager;
174 
175 } // namespace llmq
176 
177 #endif // PIVX_LLMQ_QUORUMS_SIGNING_H
Definition: net.h:145
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:46
inv message data
Definition: protocol.h:466
Information about a peer.
Definition: net.h:669
Fast randomness source.
Definition: random.h:107
bool IsNull() const
Definition: uint256.h:36
const uint256 & GetHash() const
SERIALIZE_METHODS(CRecoveredSig, obj)
CBLSLazySignature sig
void CleanupOldVotes(int64_t maxAge)
bool HasRecoveredSigForHash(const uint256 &hash)
bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
CRecoveredSigsDb(CDBWrapper &_db)
unordered_lru_cache< uint256, bool, StaticSaltedHasher, 30000 > hasSigForHashCache
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256 &id, uint256 &msgHashRet)
unordered_lru_cache< std::pair< Consensus::LLMQType, uint256 >, bool, StaticSaltedHasher, 30000 > hasSigForIdCache
void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id)
bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id, CRecoveredSig &ret)
void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id)
void WriteVoteForId(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
unordered_lru_cache< uint256, bool, StaticSaltedHasher, 30000 > hasSigForSessionCache
bool HasRecoveredSigForSession(const uint256 &signHash)
void CleanupOldRecoveredSigs(int64_t maxAge)
bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256 &id, CRecoveredSig &ret)
void WriteRecoveredSig(const CRecoveredSig &recSig)
bool GetRecoveredSigByHash(const uint256 &hash, CRecoveredSig &ret)
bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256 &id)
bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256 &id)
virtual void HandleNewRecoveredSig(const CRecoveredSig &recoveredSig)=0
void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id)
void ProcessMessage(CNode *pnode, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
FastRandomContext rnd
bool HasRecoveredSigForSession(const uint256 &signHash)
CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, const uint256 &selectionHash, int signHeight=-1, int signOffset=SIGN_HEIGHT_OFFSET)
bool AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash, bool allowReSign=false)
void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig &recoveredSig, const CQuorumCPtr &quorum, CConnman &connman)
bool VerifyRecoveredSig(Consensus::LLMQType llmqType, int signedAtHeight, const uint256 &id, const uint256 &msgHash, const CBLSSignature &sig)
bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256 &id)
void UnregisterRecoveredSigsListener(CRecoveredSigsListener *l)
bool AlreadyHave(const CInv &inv)
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig &recoveredSig, bool &retBan)
bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
bool GetRecoveredSigForGetData(const uint256 &hash, CRecoveredSig &ret)
bool ProcessPendingRecoveredSigs(CConnman &connman)
static const int64_t DEFAULT_MAX_RECOVERED_SIGS_AGE
void ProcessMessageRecoveredSig(CNode *pfrom, const CRecoveredSig &recoveredSig, CConnman &connman)
std::unordered_map< NodeId, std::list< CRecoveredSig > > pendingRecoveredSigs
CSigningManager(CDBWrapper &llmqDb, bool fMemory)
bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256 &id)
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256 &id, uint256 &msgHashRet)
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions, std::unordered_map< NodeId, std::list< CRecoveredSig >> &retSigShares, std::unordered_map< std::pair< Consensus::LLMQType, uint256 >, CQuorumCPtr, StaticSaltedHasher > &retQuorums)
bool IsConflicting(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
void RegisterRecoveredSigsListener(CRecoveredSigsListener *l)
std::vector< CQuorumCPtr > GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight)
CRecoveredSigsDb db
std::vector< CRecoveredSigsListener * > recoveredSigsListeners
static const int SIGN_HEIGHT_OFFSET
256-bit opaque blob.
Definition: uint256.h:138
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
LLMQType
Definition: params.h:90
Definition: quorums.cpp:26
std::shared_ptr< const CQuorum > CQuorumCPtr
Definition: quorums.h:72
std::unique_ptr< CSigningManager > quorumSigningManager
CDBWrapper * llmqDb
int NodeId
Definition: net.h:109
#define SER_READ(obj, code)
Definition: serialize.h:185
#define READWRITE(...)
Definition: serialize.h:183