252 lines
7.9 KiB
C++
252 lines
7.9 KiB
C++
// Copyright (c) 2014-2017 The Dash Core developers
|
|
// Copyright (c) 2021-2024 The NeoBytes Core developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef INSTANTX_H
|
|
#define INSTANTX_H
|
|
|
|
#include "net.h"
|
|
#include "primitives/transaction.h"
|
|
|
|
class CTxLockVote;
|
|
class COutPointLock;
|
|
class CTxLockRequest;
|
|
class CTxLockCandidate;
|
|
class CInstantSend;
|
|
|
|
extern CInstantSend instantsend;
|
|
|
|
/*
|
|
At 15 signatures, 1/2 of the masternode network can be owned by
|
|
one party without comprimising the security of InstantSend
|
|
(1000/2150.0)**10 = 0.00047382219560689856
|
|
(1000/2900.0)**10 = 2.3769498616783657e-05
|
|
|
|
### getting 5 of 10 signatures w/ 1000 nodes of 2900
|
|
(1000/2900.0)**5 = 0.004875397277841433
|
|
*/
|
|
static const int INSTANTSEND_CONFIRMATIONS_REQUIRED = 6;
|
|
static const int DEFAULT_INSTANTSEND_DEPTH = 5;
|
|
|
|
static const int MIN_INSTANTSEND_PROTO_VERSION = 70206;
|
|
|
|
extern bool fEnableInstantSend;
|
|
extern int nInstantSendDepth;
|
|
extern int nCompleteTXLocks;
|
|
|
|
class CInstantSend
|
|
{
|
|
private:
|
|
static const int ORPHAN_VOTE_SECONDS = 60;
|
|
|
|
// Keep track of current block index
|
|
const CBlockIndex *pCurrentBlockIndex;
|
|
|
|
// maps for AlreadyHave
|
|
std::map<uint256, CTxLockRequest> mapLockRequestAccepted; // tx hash - tx
|
|
std::map<uint256, CTxLockRequest> mapLockRequestRejected; // tx hash - tx
|
|
std::map<uint256, CTxLockVote> mapTxLockVotes; // vote hash - vote
|
|
std::map<uint256, CTxLockVote> mapTxLockVotesOrphan; // vote hash - vote
|
|
|
|
std::map<uint256, CTxLockCandidate> mapTxLockCandidates; // tx hash - lock candidate
|
|
|
|
std::map<COutPoint, std::set<uint256> > mapVotedOutpoints; // utxo - tx hash set
|
|
std::map<COutPoint, uint256> mapLockedOutpoints; // utxo - tx hash
|
|
|
|
//track masternodes who voted with no txreq (for DOS protection)
|
|
std::map<COutPoint, int64_t> mapMasternodeOrphanVotes; // mn outpoint - time
|
|
|
|
bool CreateTxLockCandidate(const CTxLockRequest& txLockRequest);
|
|
void Vote(CTxLockCandidate& txLockCandidate);
|
|
|
|
//process consensus vote message
|
|
bool ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote);
|
|
void ProcessOrphanTxLockVotes();
|
|
bool IsEnoughOrphanVotesForTx(const CTxLockRequest& txLockRequest);
|
|
bool IsEnoughOrphanVotesForTxAndOutPoint(const uint256& txHash, const COutPoint& outpoint);
|
|
int64_t GetAverageMasternodeOrphanVoteTime();
|
|
|
|
void TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate);
|
|
void LockTransactionInputs(const CTxLockCandidate& txLockCandidate);
|
|
//update UI and notify external script if any
|
|
void UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate);
|
|
bool ResolveConflicts(const CTxLockCandidate& txLockCandidate, int nMaxBlocks);
|
|
|
|
bool IsInstantSendReadyToLock(const uint256 &txHash);
|
|
|
|
public:
|
|
CCriticalSection cs_instantsend;
|
|
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
|
|
|
bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest);
|
|
|
|
bool AlreadyHave(const uint256& hash);
|
|
|
|
void AcceptLockRequest(const CTxLockRequest& txLockRequest);
|
|
void RejectLockRequest(const CTxLockRequest& txLockRequest);
|
|
bool HasTxLockRequest(const uint256& txHash);
|
|
bool GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLockRequestRet);
|
|
|
|
bool GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet);
|
|
|
|
bool GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& hashRet);
|
|
|
|
// verify if transaction is currently locked
|
|
bool IsLockedInstantSendTransaction(const uint256& txHash);
|
|
// get the actual uber og accepted lock signatures
|
|
int GetTransactionLockSignatures(const uint256& txHash);
|
|
|
|
// remove expired entries from maps
|
|
void CheckAndRemove();
|
|
// verify if transaction lock timed out
|
|
bool IsTxLockRequestTimedOut(const uint256& txHash);
|
|
|
|
void Relay(const uint256& txHash);
|
|
|
|
void UpdatedBlockTip(const CBlockIndex *pindex);
|
|
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
|
};
|
|
|
|
class CTxLockRequest : public CTransaction
|
|
{
|
|
private:
|
|
static const int TIMEOUT_SECONDS = 5 * 60;
|
|
static const CAmount MIN_FEE = 0.001 * COIN;
|
|
|
|
int64_t nTimeCreated;
|
|
|
|
public:
|
|
static const int WARN_MANY_INPUTS = 100;
|
|
|
|
CTxLockRequest() :
|
|
CTransaction(),
|
|
nTimeCreated(GetTime())
|
|
{}
|
|
CTxLockRequest(const CTransaction& tx) :
|
|
CTransaction(tx),
|
|
nTimeCreated(GetTime())
|
|
{}
|
|
|
|
bool IsValid(bool fRequireUnspent = true) const;
|
|
CAmount GetMinFee() const;
|
|
int GetMaxSignatures() const;
|
|
bool IsTimedOut() const;
|
|
};
|
|
|
|
class CTxLockVote
|
|
{
|
|
private:
|
|
uint256 txHash;
|
|
COutPoint outpoint;
|
|
COutPoint outpointMasternode;
|
|
std::vector<unsigned char> vchMasternodeSignature;
|
|
// local memory only
|
|
int nConfirmedHeight; // when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
|
|
int64_t nTimeCreated;
|
|
|
|
public:
|
|
CTxLockVote() :
|
|
txHash(),
|
|
outpoint(),
|
|
outpointMasternode(),
|
|
vchMasternodeSignature(),
|
|
nConfirmedHeight(-1),
|
|
nTimeCreated(GetTime())
|
|
{}
|
|
|
|
CTxLockVote(const uint256& txHashIn, const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn) :
|
|
txHash(txHashIn),
|
|
outpoint(outpointIn),
|
|
outpointMasternode(outpointMasternodeIn),
|
|
vchMasternodeSignature(),
|
|
nConfirmedHeight(-1),
|
|
nTimeCreated(GetTime())
|
|
{}
|
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
template <typename Stream, typename Operation>
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
|
READWRITE(txHash);
|
|
READWRITE(outpoint);
|
|
READWRITE(outpointMasternode);
|
|
READWRITE(vchMasternodeSignature);
|
|
}
|
|
|
|
uint256 GetHash() const;
|
|
|
|
uint256 GetTxHash() const { return txHash; }
|
|
COutPoint GetOutpoint() const { return outpoint; }
|
|
COutPoint GetMasternodeOutpoint() const { return outpointMasternode; }
|
|
int64_t GetTimeCreated() const { return nTimeCreated; }
|
|
|
|
bool IsValid(CNode* pnode) const;
|
|
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
|
|
bool IsExpired(int nHeight) const;
|
|
|
|
bool Sign();
|
|
bool CheckSignature() const;
|
|
|
|
void Relay() const;
|
|
};
|
|
|
|
class COutPointLock
|
|
{
|
|
private:
|
|
COutPoint outpoint; // utxo
|
|
std::map<COutPoint, CTxLockVote> mapMasternodeVotes; // masternode outpoint - vote
|
|
|
|
public:
|
|
static const int SIGNATURES_REQUIRED = 6;
|
|
static const int SIGNATURES_TOTAL = 10;
|
|
|
|
COutPointLock(const COutPoint& outpointIn) :
|
|
outpoint(outpointIn),
|
|
mapMasternodeVotes()
|
|
{}
|
|
|
|
COutPoint GetOutpoint() const { return outpoint; }
|
|
|
|
bool AddVote(const CTxLockVote& vote);
|
|
std::vector<CTxLockVote> GetVotes() const;
|
|
bool HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const;
|
|
int CountVotes() const { return mapMasternodeVotes.size(); }
|
|
bool IsReady() const { return CountVotes() >= SIGNATURES_REQUIRED; }
|
|
|
|
void Relay() const;
|
|
};
|
|
|
|
class CTxLockCandidate
|
|
{
|
|
private:
|
|
int nConfirmedHeight; // when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
|
|
|
|
public:
|
|
CTxLockCandidate(const CTxLockRequest& txLockRequestIn) :
|
|
nConfirmedHeight(-1),
|
|
txLockRequest(txLockRequestIn),
|
|
mapOutPointLocks()
|
|
{}
|
|
|
|
CTxLockRequest txLockRequest;
|
|
std::map<COutPoint, COutPointLock> mapOutPointLocks;
|
|
|
|
uint256 GetHash() const { return txLockRequest.GetHash(); }
|
|
|
|
void AddOutPointLock(const COutPoint& outpoint);
|
|
bool AddVote(const CTxLockVote& vote);
|
|
bool IsAllOutPointsReady() const;
|
|
|
|
bool HasMasternodeVoted(const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn);
|
|
int CountVotes() const;
|
|
|
|
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
|
|
bool IsExpired(int nHeight) const;
|
|
|
|
void Relay() const;
|
|
};
|
|
|
|
#endif
|