// Copyright (c) 2019 The Dash Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef DASH_QUORUMS_INSTANTSEND_H #define DASH_QUORUMS_INSTANTSEND_H #include "quorums_signing.h" #include "coins.h" #include "unordered_lru_cache.h" #include "primitives/transaction.h" #include #include class CScheduler; namespace llmq { class CInstantSendLock { public: std::vector inputs; uint256 txid; CBLSSignature sig; public: ADD_SERIALIZE_METHODS template inline void SerializationOp(Stream& s, Operation ser_action) { READWRITE(inputs); READWRITE(txid); READWRITE(sig); } uint256 GetRequestId() const; }; typedef std::shared_ptr CInstantSendLockPtr; class CInstantSendDb { private: CDBWrapper& db; unordered_lru_cache islockCache; unordered_lru_cache txidCache; unordered_lru_cache outpointCache; public: CInstantSendDb(CDBWrapper& _db) : db(_db) {} void WriteNewInstantSendLock(const uint256& hash, const CInstantSendLock& islock); void RemoveInstantSendLock(const uint256& hash, CInstantSendLockPtr islock); CInstantSendLockPtr GetInstantSendLockByHash(const uint256& hash); uint256 GetInstantSendLockHashByTxid(const uint256& txid); CInstantSendLockPtr GetInstantSendLockByTxid(const uint256& txid); CInstantSendLockPtr GetInstantSendLockByInput(const COutPoint& outpoint); void WriteLastChainLockBlock(const uint256& hashBlock); uint256 GetLastChainLockBlock(); }; class CInstantSendManager : public CRecoveredSigsListener { private: CCriticalSection cs; CScheduler* scheduler; CInstantSendDb db; /** * Request ids of inputs that we signed. Used to determine if a recovered signature belongs to an * in-progress input lock. */ std::unordered_set inputRequestIds; /** * These are the islocks that are currently in the middle of being created. Entries are created when we observed * recovered signatures for all inputs of a TX. At the same time, we initiate signing of our sigshare for the islock. * When the recovered sig for the islock later arrives, we can finish the islock and propagate it. */ std::unordered_map creatingInstantSendLocks; // maps from txid to the in-progress islock std::unordered_map txToCreatingInstantSendLocks; // Incoming and not verified yet std::unordered_map> pendingInstantSendLocks; bool hasScheduledProcessPending{false}; public: CInstantSendManager(CScheduler* _scheduler, CDBWrapper& _llmqDb); ~CInstantSendManager(); void RegisterAsRecoveredSigsListener(); void UnregisterAsRecoveredSigsListener(); public: bool ProcessTx(const CTransaction& tx, const Consensus::Params& params); bool CheckCanLock(const CTransaction& tx, bool printDebug, const Consensus::Params& params); bool CheckCanLock(const COutPoint& outpoint, bool printDebug, const uint256& txHash, CAmount* retValue, const Consensus::Params& params); bool IsLocked(const uint256& txHash); bool IsConflicted(const CTransaction& tx); bool GetConflictingTx(const CTransaction& tx, uint256& retConflictTxHash); virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig); void HandleNewInputLockRecoveredSig(const CRecoveredSig& recoveredSig, const uint256& txid); void HandleNewInstantSendLockRecoveredSig(const CRecoveredSig& recoveredSig); void TrySignInstantSendLock(const CTransaction& tx); void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessMessageInstantSendLock(CNode* pfrom, const CInstantSendLock& islock, CConnman& connman); bool PreVerifyInstantSendLock(NodeId nodeId, const CInstantSendLock& islock, bool& retBan); void ProcessPendingInstantSendLocks(); void ProcessInstantSendLock(NodeId from, const uint256& hash, const CInstantSendLock& islock); void UpdateWalletTransaction(const uint256& txid, const CTransactionRef& tx); void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock); void NotifyChainLock(const CBlockIndex* pindexChainLock); void RemoveFinalISLock(const uint256& hash, const CInstantSendLockPtr& islock); void RemoveMempoolConflictsForLock(const uint256& hash, const CInstantSendLock& islock); void RetryLockTxs(const uint256& lockedParentTx); bool AlreadyHave(const CInv& inv); bool GetInstantSendLockByHash(const uint256& hash, CInstantSendLock& ret); }; extern CInstantSendManager* quorumInstantSendManager; // This involves 2 sporks: SPORK_2_INSTANTSEND_ENABLED and SPORK_20_INSTANTSEND_LLMQ_BASED // SPORK_2_INSTANTSEND_ENABLED generally enables/disables InstantSend and SPORK_20_INSTANTSEND_LLMQ_BASED switches // between the old and the new (LLMQ based) system // TODO When the new system is fully deployed and enabled, we can remove this special handling in a future version // and revert to only using SPORK_2_INSTANTSEND_ENABLED. bool IsOldInstantSendEnabled(); bool IsNewInstantSendEnabled(); bool IsInstantSendEnabled(); } #endif//DASH_QUORUMS_INSTANTSEND_H