dash/src/instantx.h

369 lines
11 KiB
C
Raw Normal View History

2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash 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 "chain.h"
#include "net.h"
#include "primitives/transaction.h"
class CTxLockVote;
class COutPointLock;
class CTxLockRequest;
class CTxLockCandidate;
class CInstantSend;
extern CInstantSend instantsend;
2015-04-03 00:51:08 +02:00
/*
At 15 signatures, 1/2 of the masternode network can be owned by
one party without compromising 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
2015-04-03 00:51:08 +02:00
*/
static const int MIN_INSTANTSEND_PROTO_VERSION = 70210;
/// 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;
extern bool fEnableInstantSend;
extern int nCompleteTXLocks;
/**
* Manages InstantSend. Processes lock requests, candidates, and votes.
*/
class CInstantSend
{
private:
static const std::string SERIALIZATION_VERSION_STRING;
// Keep track of current block height
int nCachedBlockHeight;
// 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
2015-02-04 11:44:41 +01:00
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 txlockrequest (for DOS protection)
std::map<COutPoint, int64_t> mapMasternodeOrphanVotes; ///< MN outpoint - Time
bool CreateTxLockCandidate(const CTxLockRequest& txLockRequest);
void CreateEmptyTxLockCandidate(const uint256& txHash);
void Vote(CTxLockCandidate& txLockCandidate, CConnman& connman);
/// Process consensus vote message
bool ProcessNewTxLockVote(CNode* pfrom, const CTxLockVote& vote, CConnman& connman);
void UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidate& txLockCandidate);
bool ProcessOrphanTxLockVote(const CTxLockVote& vote);
void ProcessOrphanTxLockVotes();
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);
public:
mutable CCriticalSection cs_instantsend;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
std::string strVersion;
if(ser_action.ForRead()) {
READWRITE(strVersion);
}
else {
strVersion = SERIALIZATION_VERSION_STRING;
READWRITE(strVersion);
}
READWRITE(mapLockRequestAccepted);
READWRITE(mapLockRequestRejected);
READWRITE(mapTxLockVotes);
READWRITE(mapTxLockVotesOrphan);
READWRITE(mapTxLockCandidates);
READWRITE(mapVotedOutpoints);
READWRITE(mapLockedOutpoints);
READWRITE(mapMasternodeOrphanVotes);
READWRITE(nCachedBlockHeight);
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
Clear();
}
}
void Clear();
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
bool ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman);
void Vote(const uint256& txHash, CConnman& connman);
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 number of accepted lock signatures
int GetTransactionLockSignatures(const uint256& txHash);
/// Remove expired entries from maps
void CheckAndRemove();
/// Verify if transaction lock timed out
bool IsTxLockCandidateTimedOut(const uint256& txHash);
void Relay(const uint256& txHash, CConnman& connman);
void UpdatedBlockTip(const CBlockIndex *pindex);
void SyncTransaction(const CTransaction& tx, const CBlockIndex *pindex, int posInBlock);
std::string ToString() const;
void DoMaintenance() { CheckAndRemove(); }
};
/**
* An InstantSend transaction lock request.
*/
class CTxLockRequest
{
private:
static const CAmount MIN_FEE = 0.0001 * COIN;
public:
/// Warn for a large number of inputs to an IS tx - fees could be substantial
/// and the number txlvote responses requested large (10 * # of inputs)
static const int WARN_MANY_INPUTS = 100;
CTransactionRef tx;
CTxLockRequest() : tx(MakeTransactionRef()) {}
CTxLockRequest(const CTransaction& _tx) : tx(MakeTransactionRef(_tx)) {};
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(tx);
}
bool IsValid() const;
CAmount GetMinFee() const;
int GetMaxSignatures() const;
const uint256 &GetHash() const {
return tx->GetHash();
}
std::string ToString() const {
return tx->ToString();
}
friend bool operator==(const CTxLockRequest& a, const CTxLockRequest& b)
{
return *a.tx == *b.tx;
}
friend bool operator!=(const CTxLockRequest& a, const CTxLockRequest& b)
{
return *a.tx != *b.tx;
}
explicit operator bool() const
{
return *this != CTxLockRequest();
}
};
2015-02-01 16:53:49 +01:00
/**
* An InstantSend transaction lock vote. Sent by a masternode in response to a
* transaction lock request (ix message) to indicate the transaction input can
* be locked. Contains the proposed transaction's hash and the outpoint being
* locked along with the masternodes outpoint and signature.
* @see CTxLockRequest
*/
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())
{}
2015-04-03 00:51:08 +02:00
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(txHash);
READWRITE(outpoint);
READWRITE(outpointMasternode);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchMasternodeSignature);
}
2015-04-03 00:51:08 +02:00
}
uint256 GetHash() const;
uint256 GetSignatureHash() const;
uint256 GetTxHash() const { return txHash; }
COutPoint GetOutpoint() const { return outpoint; }
COutPoint GetMasternodeOutpoint() const { return outpointMasternode; }
Eliminate remaining uses of g_connman in Dash-specific code. (#1635) This monstrous change eliminates all remaining uses of g_connman global variable in Dash-specific code. Unlike previous changes eliminating g_connman use that were isolated to particular modules, this one covers multiple modules simultaneously because they are so interdependent that change in one module was quickly spreading to others. This is mostly invariant change that was done by * changing all functions using g_connman to use connman argument, * changing all functions calling these functions to use connman argument, * repeating previous step until there's nothing to change. After multiple iterations, this process converged to final result, producing code that is mostly equivalent to original one, but passing CConnman instance through arguments instead of global variable. The only exception to equivalence of resulting code is that I had to create overload of CMasternodeMan::CheckAndRemove() method without arguments that does nothing just for use in CFlatDB<CMasternodeMan>::Dump() and CFlatDB<CMasternodeMan>::Load() methods. Normal CMasternodeMan::CheckAndRemove() overload now has argument of CConnman& type and is used everywhere else. The normal overload has this code in the beginning: if(!masternodeSync.IsMasternodeListSynced()) return; Masternode list is not synced yet when we load "mncache.dat" file, and we save "mncache.dat" file on shutdown, so I presume that it's OK to use overload that does nothing in both cases. Signed-off-by: Oleg Girko <ol@infoserver.lv>
2017-09-19 16:51:38 +02:00
bool IsValid(CNode* pnode, CConnman& connman) const;
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
bool IsExpired(int nHeight) const;
bool IsTimedOut() const;
bool IsFailed() const;
bool Sign();
bool CheckSignature() const;
void Relay(CConnman& connman) const;
};
/**
* An InstantSend OutpointLock.
*/
class COutPointLock
{
private:
COutPoint outpoint; ///< UTXO
std::map<COutPoint, CTxLockVote> mapMasternodeVotes; ///< Masternode outpoint - vote
bool fAttacked = false;
public:
static const int SIGNATURES_REQUIRED = 6;
static const int SIGNATURES_TOTAL = 10;
COutPointLock() {}
COutPointLock(const COutPoint& outpointIn) :
outpoint(outpointIn),
mapMasternodeVotes()
{}
COutPoint GetOutpoint() const { return outpoint; }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(outpoint);
READWRITE(mapMasternodeVotes);
READWRITE(fAttacked);
}
bool AddVote(const CTxLockVote& vote);
std::vector<CTxLockVote> GetVotes() const;
bool HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const;
int CountVotes() const { return fAttacked ? 0 : mapMasternodeVotes.size(); }
bool IsReady() const { return !fAttacked && CountVotes() >= SIGNATURES_REQUIRED; }
void MarkAsAttacked() { fAttacked = true; }
void Relay(CConnman& connman) const;
};
/**
* An InstantSend transaction lock candidate.
*/
class CTxLockCandidate
{
private:
int nConfirmedHeight; ///<When corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
int64_t nTimeCreated;
public:
CTxLockCandidate() :
nConfirmedHeight(-1),
nTimeCreated(GetTime())
{}
CTxLockCandidate(const CTxLockRequest& txLockRequestIn) :
nConfirmedHeight(-1),
nTimeCreated(GetTime()),
txLockRequest(txLockRequestIn),
mapOutPointLocks()
{}
CTxLockRequest txLockRequest;
std::map<COutPoint, COutPointLock> mapOutPointLocks;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(txLockRequest);
READWRITE(mapOutPointLocks);
READWRITE(nTimeCreated);
READWRITE(nConfirmedHeight);
}
uint256 GetHash() const { return txLockRequest.GetHash(); }
void AddOutPointLock(const COutPoint& outpoint);
void MarkOutpointAsAttacked(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;
bool IsTimedOut() const;
void Relay(CConnman& connman) const;
};
2015-04-03 00:51:08 +02:00
#endif