neobytes/src/llmq/quorums_instantsend.h
2019-03-07 21:14:31 +01:00

150 lines
5.8 KiB
C++

// 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_INSTANTX_H
#define DASH_QUORUMS_INSTANTX_H
#include "quorums_signing.h"
#include "coins.h"
#include "primitives/transaction.h"
#include <unordered_map>
#include <unordered_set>
class CScheduler;
namespace llmq
{
class CInstantXLock
{
public:
std::vector<COutPoint> inputs;
uint256 txid;
CBLSSignature sig;
public:
ADD_SERIALIZE_METHODS
template<typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(inputs);
READWRITE(txid);
READWRITE(sig);
}
uint256 GetRequestId() const;
};
class CInstantXLockInfo
{
public:
// might be nullptr when ixlock is received before the TX itself
CTransactionRef tx;
CInstantXLock ixlock;
// only valid when recovered sig was received
uint256 ixlockHash;
// time when it was created/received
int64_t time;
// might be null initially (when TX was not mined yet) and will later be filled by SyncTransaction
const CBlockIndex* pindexMined{nullptr};
};
class CInstantSendManager : public CRecoveredSigsListener
{
private:
CCriticalSection cs;
CScheduler* scheduler;
/**
* These are the votes/signatures we performed locally. It's indexed by the LLMQ requestId, which is
* hash(TXLOCK_REQUESTID_PREFIX, prevout). The map values are the txids we voted for. This map is used to
* avoid voting for the same input twice.
*/
std::unordered_map<uint256, uint256, StaticSaltedHasher> inputVotes;
/**
* These are the ixlocks 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 ixlock.
* When the recovered sig for the ixlock later arrives, we can finish the ixlock and propagate it.
*/
std::unordered_map<uint256, CInstantXLockInfo, StaticSaltedHasher> creatingInstantXLocks;
// maps from txid to the in-progress ixlock
std::unordered_map<uint256, CInstantXLockInfo*, StaticSaltedHasher> txToCreatingInstantXLocks;
/**
* These are the final ixlocks, indexed by their own hash. The other maps are used to get from TXs, inputs and blocks
* to ixlocks.
*/
std::unordered_map<uint256, CInstantXLockInfo, StaticSaltedHasher> finalInstantXLocks;
std::unordered_map<uint256, CInstantXLockInfo*, StaticSaltedHasher> txToInstantXLock;
std::unordered_map<COutPoint, CInstantXLockInfo*, SaltedOutpointHasher> inputToInstantXLock;
std::unordered_multimap<uint256, CInstantXLockInfo*, StaticSaltedHasher> blockToInstantXLocks;
const CBlockIndex* pindexLastChainLock{nullptr};
// Incoming and not verified yet
std::unordered_map<uint256, std::pair<NodeId, CInstantXLock>> pendingInstantXLocks;
bool hasScheduledProcessPending{false};
public:
CInstantSendManager(CScheduler* _scheduler);
~CInstantSendManager();
void RegisterAsRecoveredSigsListener();
void UnregisterAsRecoveredSigsListener();
public:
bool ProcessTx(CNode* pfrom, const CTransaction& tx, CConnman& connman, 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 HandleNewInstantXLockRecoveredSig(const CRecoveredSig& recoveredSig);
void TrySignInstantXLock(const CTransaction& tx);
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
void ProcessMessageInstantXLock(CNode* pfrom, const CInstantXLock& ixlock, CConnman& connman);
bool PreVerifyInstantXLock(NodeId nodeId, const CInstantXLock& ixlock, bool& retBan);
void ProcessPendingInstantXLocks();
void ProcessInstantXLock(NodeId from, const uint256& hash, const CInstantXLock& ixlock);
void UpdateWalletTransaction(const uint256& txid);
void SyncTransaction(const CTransaction &tx, const CBlockIndex *pindex, int posInBlock);
void NotifyChainLock(const CBlockIndex* pindex);
void UpdateIxLockMinedBlock(CInstantXLockInfo* ixlockInfo, const CBlockIndex* pindex);
void RemoveFinalIxLock(const uint256& hash);
void RemoveMempoolConflictsForLock(const uint256& hash, const CInstantXLock& ixlock);
void RetryLockMempoolTxs(const uint256& lockedParentTx);
bool AlreadyHave(const CInv& inv);
bool GetInstantXLockByHash(const uint256& hash, CInstantXLock& ret);
};
extern CInstantSendManager* quorumInstantSendManager;
// The meaning of spork 2 has changed in v0.14. Before that, spork 2 was simply time based and either enabled or not
// After 0.14, spork 2 can have 3 states.
// 0 = old system is active (0 is compatible with the value set on mainnet at time of deployment)
// 1 = new system is active (old nodes will interpret this as the old system being enabled, but then won't get enough IX lock votes)
// everything else = disabled
// TODO When the new system is fully deployed and enabled, we can remove this special handling of the spork in a future version
// and revert to the old behaviour.
bool IsOldInstantSendEnabled();
bool IsNewInstantSendEnabled();
bool IsInstantSendEnabled();
}
#endif//DASH_QUORUMS_INSTANTX_H