2016-12-20 14:26:45 +01:00
|
|
|
// Copyright (c) 2014-2017 The Dash Core developers
|
2014-12-09 02:17:57 +01:00
|
|
|
// 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
|
|
|
|
|
2017-08-25 14:56:48 +02:00
|
|
|
#include "chain.h"
|
2014-12-09 02:17:57 +01:00
|
|
|
#include "net.h"
|
2016-12-20 14:27:59 +01:00
|
|
|
#include "primitives/transaction.h"
|
2016-08-05 21:49:45 +02:00
|
|
|
|
2016-11-17 01:31:35 +01:00
|
|
|
class CTxLockVote;
|
2017-01-29 09:22:14 +01:00
|
|
|
class COutPointLock;
|
|
|
|
class CTxLockRequest;
|
2016-11-17 01:31:35 +01:00
|
|
|
class CTxLockCandidate;
|
2017-01-29 09:22:14 +01:00
|
|
|
class CInstantSend;
|
|
|
|
|
|
|
|
extern CInstantSend instantsend;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-04-03 00:51:08 +02:00
|
|
|
/*
|
|
|
|
At 15 signatures, 1/2 of the masternode network can be owned by
|
2018-01-06 11:05:55 +01:00
|
|
|
one party without compromising the security of InstantSend
|
2015-07-25 18:29:29 +02:00
|
|
|
(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
|
2015-04-03 00:51:08 +02:00
|
|
|
*/
|
2017-01-29 09:22:14 +01:00
|
|
|
static const int INSTANTSEND_CONFIRMATIONS_REQUIRED = 6;
|
2016-08-05 21:49:45 +02:00
|
|
|
static const int DEFAULT_INSTANTSEND_DEPTH = 5;
|
2015-04-03 00:51:08 +02:00
|
|
|
|
2017-09-22 03:52:35 +02:00
|
|
|
static const int MIN_INSTANTSEND_PROTO_VERSION = 70208;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-10-31 15:50:03 +01:00
|
|
|
// For how long we are going to accept votes/locks
|
|
|
|
// after we saw the first one for a specific transaction
|
|
|
|
static const int INSTANTSEND_LOCK_TIMEOUT_SECONDS = 15;
|
|
|
|
// For how long we are going to keep invalid votes and votes for failed lock attempts,
|
|
|
|
// must be greater than INSTANTSEND_LOCK_TIMEOUT_SECONDS
|
|
|
|
static const int INSTANTSEND_FAILED_TIMEOUT_SECONDS = 60;
|
|
|
|
|
2016-08-05 21:49:45 +02:00
|
|
|
extern bool fEnableInstantSend;
|
|
|
|
extern int nInstantSendDepth;
|
|
|
|
extern int nCompleteTXLocks;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
class CInstantSend
|
|
|
|
{
|
|
|
|
private:
|
2017-08-25 14:57:05 +02:00
|
|
|
// Keep track of current block height
|
|
|
|
int nCachedBlockHeight;
|
2015-02-04 22:59:19 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
// 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
|
2015-02-04 22:59:19 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
std::map<uint256, CTxLockCandidate> mapTxLockCandidates; // tx hash - lock candidate
|
2015-02-04 11:44:41 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
std::map<COutPoint, std::set<uint256> > mapVotedOutpoints; // utxo - tx hash set
|
|
|
|
std::map<COutPoint, uint256> mapLockedOutpoints; // utxo - tx hash
|
2016-11-22 15:54:26 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
//track masternodes who voted with no txreq (for DOS protection)
|
|
|
|
std::map<COutPoint, int64_t> mapMasternodeOrphanVotes; // mn outpoint - time
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
bool CreateTxLockCandidate(const CTxLockRequest& txLockRequest);
|
2017-09-14 13:41:40 +02:00
|
|
|
void CreateEmptyTxLockCandidate(const uint256& txHash);
|
2017-09-15 20:05:13 +02:00
|
|
|
void Vote(CTxLockCandidate& txLockCandidate, CConnman& connman);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
//process consensus vote message
|
2017-09-15 20:05:13 +02:00
|
|
|
bool ProcessTxLockVote(CNode* pfrom, CTxLockVote& vote, CConnman& connman);
|
|
|
|
void ProcessOrphanTxLockVotes(CConnman& connman);
|
2017-01-29 09:22:14 +01:00
|
|
|
bool IsEnoughOrphanVotesForTx(const CTxLockRequest& txLockRequest);
|
|
|
|
bool IsEnoughOrphanVotesForTxAndOutPoint(const uint256& txHash, const COutPoint& outpoint);
|
|
|
|
int64_t GetAverageMasternodeOrphanVoteTime();
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
void TryToFinalizeLockCandidate(const CTxLockCandidate& txLockCandidate);
|
|
|
|
void LockTransactionInputs(const CTxLockCandidate& txLockCandidate);
|
|
|
|
//update UI and notify external script if any
|
|
|
|
void UpdateLockedTransaction(const CTxLockCandidate& txLockCandidate);
|
2017-09-14 13:41:40 +02:00
|
|
|
bool ResolveConflicts(const CTxLockCandidate& txLockCandidate);
|
2016-11-22 15:54:26 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
bool IsInstantSendReadyToLock(const uint256 &txHash);
|
2016-03-24 16:54:29 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
public:
|
|
|
|
CCriticalSection cs_instantsend;
|
2016-03-24 16:54:29 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman);
|
2016-03-24 16:54:29 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman);
|
2016-03-24 16:54:29 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
bool AlreadyHave(const uint256& hash);
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
void AcceptLockRequest(const CTxLockRequest& txLockRequest);
|
|
|
|
void RejectLockRequest(const CTxLockRequest& txLockRequest);
|
|
|
|
bool HasTxLockRequest(const uint256& txHash);
|
|
|
|
bool GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLockRequestRet);
|
2016-03-23 15:49:35 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
bool GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet);
|
2016-03-23 15:49:35 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
bool GetLockedOutPointTxHash(const COutPoint& outpoint, uint256& hashRet);
|
2016-03-23 15:49:35 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
// verify if transaction is currently locked
|
|
|
|
bool IsLockedInstantSendTransaction(const uint256& txHash);
|
2017-09-14 13:41:40 +02:00
|
|
|
// get the actual number of accepted lock signatures
|
2017-01-29 09:22:14 +01:00
|
|
|
int GetTransactionLockSignatures(const uint256& txHash);
|
2017-08-25 14:56:48 +02:00
|
|
|
// get instantsend confirmations (only)
|
|
|
|
int GetConfirmations(const uint256 &nTXHash);
|
2015-02-02 18:33:52 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
// remove expired entries from maps
|
|
|
|
void CheckAndRemove();
|
|
|
|
// verify if transaction lock timed out
|
2017-09-14 13:41:40 +02:00
|
|
|
bool IsTxLockCandidateTimedOut(const uint256& txHash);
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
void Relay(const uint256& txHash, CConnman& connman);
|
2017-01-29 09:22:14 +01:00
|
|
|
|
|
|
|
void UpdatedBlockTip(const CBlockIndex *pindex);
|
|
|
|
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
2017-06-06 01:47:23 +02:00
|
|
|
|
|
|
|
std::string ToString();
|
2017-01-29 09:22:14 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
class CTxLockRequest : public CTransaction
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
2017-01-29 09:22:14 +01:00
|
|
|
private:
|
2017-12-07 10:43:23 +01:00
|
|
|
static const CAmount MIN_FEE = 0.0001 * COIN;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
public:
|
2017-02-02 23:38:33 +01:00
|
|
|
static const int WARN_MANY_INPUTS = 100;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-14 13:41:40 +02:00
|
|
|
CTxLockRequest() = default;
|
|
|
|
CTxLockRequest(const CTransaction& tx) : CTransaction(tx) {};
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-14 13:41:40 +02:00
|
|
|
bool IsValid() const;
|
2017-01-29 09:22:14 +01:00
|
|
|
CAmount GetMinFee() const;
|
|
|
|
int GetMaxSignatures() const;
|
2017-09-14 13:41:40 +02:00
|
|
|
|
|
|
|
explicit operator bool() const
|
|
|
|
{
|
|
|
|
return *this != CTxLockRequest();
|
|
|
|
}
|
2017-01-29 09:22:14 +01:00
|
|
|
};
|
2015-02-01 16:53:49 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
class CTxLockVote
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
uint256 txHash;
|
|
|
|
COutPoint outpoint;
|
|
|
|
COutPoint outpointMasternode;
|
|
|
|
std::vector<unsigned char> vchMasternodeSignature;
|
2016-11-22 15:54:26 +01:00
|
|
|
// local memory only
|
2017-01-29 09:22:14 +01:00
|
|
|
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())
|
|
|
|
{}
|
2016-11-22 15:54:26 +01:00
|
|
|
|
2015-04-03 00:51:08 +02:00
|
|
|
ADD_SERIALIZE_METHODS;
|
|
|
|
|
|
|
|
template <typename Stream, typename Operation>
|
|
|
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
2015-02-02 13:24:04 +01:00
|
|
|
READWRITE(txHash);
|
2017-01-29 09:22:14 +01:00
|
|
|
READWRITE(outpoint);
|
|
|
|
READWRITE(outpointMasternode);
|
|
|
|
READWRITE(vchMasternodeSignature);
|
2015-04-03 00:51:08 +02:00
|
|
|
}
|
2016-08-12 07:55:41 +02:00
|
|
|
|
|
|
|
uint256 GetHash() const;
|
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
uint256 GetTxHash() const { return txHash; }
|
|
|
|
COutPoint GetOutpoint() const { return outpoint; }
|
|
|
|
COutPoint GetMasternodeOutpoint() const { return outpointMasternode; }
|
|
|
|
|
2017-09-19 16:51:38 +02:00
|
|
|
bool IsValid(CNode* pnode, CConnman& connman) const;
|
2017-01-29 09:22:14 +01:00
|
|
|
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
|
|
|
|
bool IsExpired(int nHeight) const;
|
2017-09-14 13:41:40 +02:00
|
|
|
bool IsTimedOut() const;
|
2017-10-31 15:50:03 +01:00
|
|
|
bool IsFailed() const;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2016-08-12 07:55:41 +02:00
|
|
|
bool Sign();
|
2016-11-21 21:40:32 +01:00
|
|
|
bool CheckSignature() const;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
void Relay(CConnman& connman) const;
|
2014-12-09 02:17:57 +01:00
|
|
|
};
|
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
class COutPointLock
|
2014-12-09 02:17:57 +01:00
|
|
|
{
|
2017-01-29 09:22:14 +01:00
|
|
|
private:
|
|
|
|
COutPoint outpoint; // utxo
|
|
|
|
std::map<COutPoint, CTxLockVote> mapMasternodeVotes; // masternode outpoint - vote
|
2017-09-14 13:41:40 +02:00
|
|
|
bool fAttacked = false;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2014-12-09 02:17:57 +01:00
|
|
|
public:
|
2017-01-29 09:22:14 +01:00
|
|
|
static const int SIGNATURES_REQUIRED = 6;
|
|
|
|
static const int SIGNATURES_TOTAL = 10;
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
COutPointLock(const COutPoint& outpointIn) :
|
|
|
|
outpoint(outpointIn),
|
|
|
|
mapMasternodeVotes()
|
|
|
|
{}
|
2015-02-02 13:24:04 +01:00
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
COutPoint GetOutpoint() const { return outpoint; }
|
|
|
|
|
|
|
|
bool AddVote(const CTxLockVote& vote);
|
2017-02-04 19:17:45 +01:00
|
|
|
std::vector<CTxLockVote> GetVotes() const;
|
|
|
|
bool HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const;
|
2017-09-14 13:41:40 +02:00
|
|
|
int CountVotes() const { return fAttacked ? 0 : mapMasternodeVotes.size(); }
|
|
|
|
bool IsReady() const { return !fAttacked && CountVotes() >= SIGNATURES_REQUIRED; }
|
|
|
|
void MarkAsAttacked() { fAttacked = true; }
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
void Relay(CConnman& connman) const;
|
2014-12-09 02:17:57 +01:00
|
|
|
};
|
|
|
|
|
2017-01-29 09:22:14 +01:00
|
|
|
class CTxLockCandidate
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
int nConfirmedHeight; // when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
|
2017-09-14 13:41:40 +02:00
|
|
|
int64_t nTimeCreated;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
CTxLockCandidate(const CTxLockRequest& txLockRequestIn) :
|
|
|
|
nConfirmedHeight(-1),
|
2017-09-14 13:41:40 +02:00
|
|
|
nTimeCreated(GetTime()),
|
2017-01-29 09:22:14 +01:00
|
|
|
txLockRequest(txLockRequestIn),
|
|
|
|
mapOutPointLocks()
|
|
|
|
{}
|
|
|
|
|
|
|
|
CTxLockRequest txLockRequest;
|
|
|
|
std::map<COutPoint, COutPointLock> mapOutPointLocks;
|
|
|
|
|
|
|
|
uint256 GetHash() const { return txLockRequest.GetHash(); }
|
|
|
|
|
|
|
|
void AddOutPointLock(const COutPoint& outpoint);
|
2017-09-14 13:41:40 +02:00
|
|
|
void MarkOutpointAsAttacked(const COutPoint& outpoint);
|
2017-01-29 09:22:14 +01:00
|
|
|
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;
|
2017-09-14 13:41:40 +02:00
|
|
|
bool IsTimedOut() const;
|
2017-01-29 09:22:14 +01:00
|
|
|
|
2017-09-15 20:05:13 +02:00
|
|
|
void Relay(CConnman& connman) const;
|
2017-01-29 09:22:14 +01:00
|
|
|
};
|
2014-12-09 02:17:57 +01:00
|
|
|
|
2015-04-03 00:51:08 +02:00
|
|
|
#endif
|