dash/src/instantx.h

385 lines
12 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;
Automatic InstantSend locks for "simple" transactions (#2140) * add locktransaction rpc call * Remove special instantsend fee for simple transactions * Function to check if trx is simple enough to be autolocked * Automatic lock for all received from peers simple trxes If we get a new transaction with CInv message and it is "simple" and is accepted in mempool, we initiate its lock. We don't lock orphan trxes that accepted in mempool after this trx because they are locked by other peers. * Automatically lock simple trxes in wallet * protocol bump for InstantSend without special fee * Add function to detect used mempool share * Mempool threshold for auto IX locks * Add SPORK_16_INSTANTSEND_AUTOLOCKS spork * Make autolocks active only when spork SPORK_16_INSTANTSEND_AUTOLOCKS is active * BIP9 autolocks activation * revert increasing min peer protocol version for mn rank * move IsTrxSimple check to CTxLockRequest class * make MAX_INPUTS_FOR_AUTO_IX private member of CTxLockRequest class * make AUTO_IX_MEMPOOL_THRESHOLD private member of CInstantSend class * remove locktransaction RPC call * tests for automatic IS locks * fix mempool threshod calculation * bump mocktime in activate_autoix_bip9 * set node times * no need to spam the node with gettransaction rpc requests that often * use `spork active` instead of leaking spork logic into tests * codestyle fixes * add test description in comments * fix typo * sync test nodes more often during BIP9 activation * Use 4th bit in BIP9 activation * Fix comments according codestyle guide * Call AcceptLockRequest and Vote at the first node creating autoix lock * fix mempool used memory calculation * rallback not necessary change in CWallet::CreateTransaction * test for stopping autolocks for full mempool * Inject "simple autolockable" txes into txlockrequest logic
2018-09-26 16:17:47 +02:00
/// Automatic locks of "simple" transactions are only allowed
/// when mempool usage is lower than this threshold
static const double AUTO_IX_MEMPOOL_THRESHOLD;
// 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(); }
Automatic InstantSend locks for "simple" transactions (#2140) * add locktransaction rpc call * Remove special instantsend fee for simple transactions * Function to check if trx is simple enough to be autolocked * Automatic lock for all received from peers simple trxes If we get a new transaction with CInv message and it is "simple" and is accepted in mempool, we initiate its lock. We don't lock orphan trxes that accepted in mempool after this trx because they are locked by other peers. * Automatically lock simple trxes in wallet * protocol bump for InstantSend without special fee * Add function to detect used mempool share * Mempool threshold for auto IX locks * Add SPORK_16_INSTANTSEND_AUTOLOCKS spork * Make autolocks active only when spork SPORK_16_INSTANTSEND_AUTOLOCKS is active * BIP9 autolocks activation * revert increasing min peer protocol version for mn rank * move IsTrxSimple check to CTxLockRequest class * make MAX_INPUTS_FOR_AUTO_IX private member of CTxLockRequest class * make AUTO_IX_MEMPOOL_THRESHOLD private member of CInstantSend class * remove locktransaction RPC call * tests for automatic IS locks * fix mempool threshod calculation * bump mocktime in activate_autoix_bip9 * set node times * no need to spam the node with gettransaction rpc requests that often * use `spork active` instead of leaking spork logic into tests * codestyle fixes * add test description in comments * fix typo * sync test nodes more often during BIP9 activation * Use 4th bit in BIP9 activation * Fix comments according codestyle guide * Call AcceptLockRequest and Vote at the first node creating autoix lock * fix mempool used memory calculation * rallback not necessary change in CWallet::CreateTransaction * test for stopping autolocks for full mempool * Inject "simple autolockable" txes into txlockrequest logic
2018-09-26 16:17:47 +02:00
/// checks if we can automatically lock "simple" transactions
static bool CanAutoLock();
/// flag of the AutoLock Bip9 activation
static std::atomic<bool> isAutoLockBip9Active;
};
/**
* An InstantSend transaction lock request.
*/
class CTxLockRequest
{
private:
static const CAmount MIN_FEE = 0.0001 * COIN;
Automatic InstantSend locks for "simple" transactions (#2140) * add locktransaction rpc call * Remove special instantsend fee for simple transactions * Function to check if trx is simple enough to be autolocked * Automatic lock for all received from peers simple trxes If we get a new transaction with CInv message and it is "simple" and is accepted in mempool, we initiate its lock. We don't lock orphan trxes that accepted in mempool after this trx because they are locked by other peers. * Automatically lock simple trxes in wallet * protocol bump for InstantSend without special fee * Add function to detect used mempool share * Mempool threshold for auto IX locks * Add SPORK_16_INSTANTSEND_AUTOLOCKS spork * Make autolocks active only when spork SPORK_16_INSTANTSEND_AUTOLOCKS is active * BIP9 autolocks activation * revert increasing min peer protocol version for mn rank * move IsTrxSimple check to CTxLockRequest class * make MAX_INPUTS_FOR_AUTO_IX private member of CTxLockRequest class * make AUTO_IX_MEMPOOL_THRESHOLD private member of CInstantSend class * remove locktransaction RPC call * tests for automatic IS locks * fix mempool threshod calculation * bump mocktime in activate_autoix_bip9 * set node times * no need to spam the node with gettransaction rpc requests that often * use `spork active` instead of leaking spork logic into tests * codestyle fixes * add test description in comments * fix typo * sync test nodes more often during BIP9 activation * Use 4th bit in BIP9 activation * Fix comments according codestyle guide * Call AcceptLockRequest and Vote at the first node creating autoix lock * fix mempool used memory calculation * rallback not necessary change in CWallet::CreateTransaction * test for stopping autolocks for full mempool * Inject "simple autolockable" txes into txlockrequest logic
2018-09-26 16:17:47 +02:00
/// If transaction has less or equal inputs than MAX_INPUTS_FOR_AUTO_IX,
/// it will be automatically locked
static const int MAX_INPUTS_FOR_AUTO_IX = 4;
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)) {};
Automatic InstantSend locks for "simple" transactions (#2140) * add locktransaction rpc call * Remove special instantsend fee for simple transactions * Function to check if trx is simple enough to be autolocked * Automatic lock for all received from peers simple trxes If we get a new transaction with CInv message and it is "simple" and is accepted in mempool, we initiate its lock. We don't lock orphan trxes that accepted in mempool after this trx because they are locked by other peers. * Automatically lock simple trxes in wallet * protocol bump for InstantSend without special fee * Add function to detect used mempool share * Mempool threshold for auto IX locks * Add SPORK_16_INSTANTSEND_AUTOLOCKS spork * Make autolocks active only when spork SPORK_16_INSTANTSEND_AUTOLOCKS is active * BIP9 autolocks activation * revert increasing min peer protocol version for mn rank * move IsTrxSimple check to CTxLockRequest class * make MAX_INPUTS_FOR_AUTO_IX private member of CTxLockRequest class * make AUTO_IX_MEMPOOL_THRESHOLD private member of CInstantSend class * remove locktransaction RPC call * tests for automatic IS locks * fix mempool threshod calculation * bump mocktime in activate_autoix_bip9 * set node times * no need to spam the node with gettransaction rpc requests that often * use `spork active` instead of leaking spork logic into tests * codestyle fixes * add test description in comments * fix typo * sync test nodes more often during BIP9 activation * Use 4th bit in BIP9 activation * Fix comments according codestyle guide * Call AcceptLockRequest and Vote at the first node creating autoix lock * fix mempool used memory calculation * rallback not necessary change in CWallet::CreateTransaction * test for stopping autolocks for full mempool * Inject "simple autolockable" txes into txlockrequest logic
2018-09-26 16:17:47 +02:00
CTxLockRequest(const CTransactionRef& _tx) : tx(_tx) {};
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(tx);
}
bool IsValid() const;
CAmount GetMinFee(bool fForceMinFee) const;
int GetMaxSignatures() const;
Automatic InstantSend locks for "simple" transactions (#2140) * add locktransaction rpc call * Remove special instantsend fee for simple transactions * Function to check if trx is simple enough to be autolocked * Automatic lock for all received from peers simple trxes If we get a new transaction with CInv message and it is "simple" and is accepted in mempool, we initiate its lock. We don't lock orphan trxes that accepted in mempool after this trx because they are locked by other peers. * Automatically lock simple trxes in wallet * protocol bump for InstantSend without special fee * Add function to detect used mempool share * Mempool threshold for auto IX locks * Add SPORK_16_INSTANTSEND_AUTOLOCKS spork * Make autolocks active only when spork SPORK_16_INSTANTSEND_AUTOLOCKS is active * BIP9 autolocks activation * revert increasing min peer protocol version for mn rank * move IsTrxSimple check to CTxLockRequest class * make MAX_INPUTS_FOR_AUTO_IX private member of CTxLockRequest class * make AUTO_IX_MEMPOOL_THRESHOLD private member of CInstantSend class * remove locktransaction RPC call * tests for automatic IS locks * fix mempool threshod calculation * bump mocktime in activate_autoix_bip9 * set node times * no need to spam the node with gettransaction rpc requests that often * use `spork active` instead of leaking spork logic into tests * codestyle fixes * add test description in comments * fix typo * sync test nodes more often during BIP9 activation * Use 4th bit in BIP9 activation * Fix comments according codestyle guide * Call AcceptLockRequest and Vote at the first node creating autoix lock * fix mempool used memory calculation * rallback not necessary change in CWallet::CreateTransaction * test for stopping autolocks for full mempool * Inject "simple autolockable" txes into txlockrequest logic
2018-09-26 16:17:47 +02:00
// checks if related transaction is "simple" to lock it automatically
bool IsSimple() 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