neobytes/src/privatesend.h

427 lines
11 KiB
C
Raw Normal View History

// Copyright (c) 2014-2019 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.
2015-02-04 14:24:56 +01:00
#ifndef PRIVATESEND_H
#define PRIVATESEND_H
2018-11-05 10:29:07 +01:00
#include "bls/bls.h"
#include "chain.h"
#include "chainparams.h"
#include "primitives/transaction.h"
#include "pubkey.h"
#include "sync.h"
#include "timedata.h"
2018-11-05 10:29:07 +01:00
#include "tinyformat.h"
class CPrivateSend;
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
class CConnman;
// timeouts
2018-11-05 10:29:07 +01:00
static const int PRIVATESEND_AUTO_TIMEOUT_MIN = 5;
static const int PRIVATESEND_AUTO_TIMEOUT_MAX = 15;
static const int PRIVATESEND_QUEUE_TIMEOUT = 30;
static const int PRIVATESEND_SIGNING_TIMEOUT = 15;
2016-09-30 20:19:26 +02:00
//! minimum peer version accepted by mixing pool
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70213;
2018-11-05 10:29:07 +01:00
static const size_t PRIVATESEND_ENTRY_MAX_SIZE = 9;
// pool responses
enum PoolMessage {
ERR_ALREADY_HAVE,
ERR_DENOM,
ERR_ENTRIES_FULL,
ERR_EXISTING_TX,
ERR_FEES,
ERR_INVALID_COLLATERAL,
ERR_INVALID_INPUT,
ERR_INVALID_SCRIPT,
ERR_INVALID_TX,
ERR_MAXIMUM,
ERR_MN_LIST,
ERR_MODE,
ERR_NON_STANDARD_PUBKEY,
ERR_NOT_A_MN, // not used
ERR_QUEUE_FULL,
ERR_RECENT,
ERR_SESSION,
ERR_MISSING_TX,
ERR_VERSION,
MSG_NOERR,
MSG_SUCCESS,
MSG_ENTRIES_ADDED,
MSG_POOL_MIN = ERR_ALREADY_HAVE,
MSG_POOL_MAX = MSG_ENTRIES_ADDED
};
2015-04-03 00:51:08 +02:00
// pool states
enum PoolState {
POOL_STATE_IDLE,
POOL_STATE_QUEUE,
POOL_STATE_ACCEPTING_ENTRIES,
POOL_STATE_SIGNING,
POOL_STATE_ERROR,
POOL_STATE_SUCCESS,
POOL_STATE_MIN = POOL_STATE_IDLE,
POOL_STATE_MAX = POOL_STATE_SUCCESS
};
// status update message constants
enum PoolStatusUpdate {
STATUS_REJECTED,
STATUS_ACCEPTED
};
/** Holds an mixing input
2015-03-05 08:49:50 +01:00
*/
2015-03-02 00:09:33 +01:00
class CTxDSIn : public CTxIn
{
public:
// memory only
CScript prevPubKey;
2015-03-06 08:24:34 +01:00
bool fHasSig; // flag to indicate if signed
CTxDSIn(const CTxIn& txin, const CScript& script) :
CTxIn(txin),
prevPubKey(script),
fHasSig(false)
2018-11-05 10:29:07 +01:00
{
}
CTxDSIn() :
CTxIn(),
prevPubKey(),
fHasSig(false)
2018-11-05 10:29:07 +01:00
{
}
};
class CPrivateSendAccept
{
public:
int nDenom;
CMutableTransaction txCollateral;
CPrivateSendAccept() :
nDenom(0),
2018-11-05 10:29:07 +01:00
txCollateral(CMutableTransaction()){};
CPrivateSendAccept(int nDenom, const CMutableTransaction& txCollateral) :
nDenom(nDenom),
2018-11-05 10:29:07 +01:00
txCollateral(txCollateral){};
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
2018-11-05 10:29:07 +01:00
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nDenom);
READWRITE(txCollateral);
}
friend bool operator==(const CPrivateSendAccept& a, const CPrivateSendAccept& b)
{
return a.nDenom == b.nDenom && a.txCollateral == b.txCollateral;
}
};
// A clients transaction in the mixing pool
class CPrivateSendEntry
{
public:
std::vector<CTxDSIn> vecTxDSIn;
std::vector<CTxOut> vecTxOut;
CTransactionRef txCollateral;
// memory only
CService addr;
CPrivateSendEntry() :
vecTxDSIn(std::vector<CTxDSIn>()),
vecTxOut(std::vector<CTxOut>()),
txCollateral(MakeTransactionRef()),
addr(CService())
2018-11-05 10:29:07 +01:00
{
}
CPrivateSendEntry(const std::vector<CTxDSIn>& vecTxDSIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral) :
vecTxDSIn(vecTxDSIn),
vecTxOut(vecTxOut),
txCollateral(MakeTransactionRef(txCollateral)),
addr(CService())
2018-11-05 10:29:07 +01:00
{
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
2018-11-05 10:29:07 +01:00
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(vecTxDSIn);
READWRITE(txCollateral);
READWRITE(vecTxOut);
}
bool AddScriptSig(const CTxIn& txin);
};
2015-03-02 00:09:33 +01:00
2015-03-05 08:49:50 +01:00
/**
* A currently in progress mixing merge and denomination information
2015-03-05 08:49:50 +01:00
*/
class CPrivateSendQueue
{
public:
int nDenom;
COutPoint masternodeOutpoint;
int64_t nTime;
bool fReady; //ready for submit
std::vector<unsigned char> vchSig;
// memory only
bool fTried;
CPrivateSendQueue() :
nDenom(0),
masternodeOutpoint(COutPoint()),
nTime(0),
fReady(false),
vchSig(std::vector<unsigned char>()),
fTried(false)
2018-11-05 10:29:07 +01:00
{
}
CPrivateSendQueue(int nDenom, COutPoint outpoint, int64_t nTime, bool fReady) :
nDenom(nDenom),
masternodeOutpoint(outpoint),
nTime(nTime),
fReady(fReady),
vchSig(std::vector<unsigned char>()),
fTried(false)
2018-11-05 10:29:07 +01:00
{
}
2015-04-03 00:51:08 +02:00
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
2018-11-05 10:29:07 +01:00
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nDenom);
READWRITE(masternodeOutpoint);
READWRITE(nTime);
READWRITE(fReady);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
}
2015-04-03 00:51:08 +02:00
}
uint256 GetSignatureHash() const;
/** Sign this mixing transaction
2015-03-05 08:49:50 +01:00
* \return true if all conditions are met:
2015-03-05 09:10:15 +01:00
* 1) we have an active Masternode,
* 2) we have a valid Masternode private key,
2015-03-05 08:49:50 +01:00
* 3) we signed the message successfully, and
* 4) we verified the message successfully
*/
bool Sign();
2015-03-05 09:10:15 +01:00
/// Check if we have a valid Masternode address
bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
2018-11-05 10:29:07 +01:00
bool Relay(CConnman& connman);
/// Is this queue expired?
bool IsExpired() { return GetAdjustedTime() - nTime > PRIVATESEND_QUEUE_TIMEOUT; }
std::string ToString() const
{
return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s",
2018-11-05 10:29:07 +01:00
nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", masternodeOutpoint.ToStringShort());
}
friend bool operator==(const CPrivateSendQueue& a, const CPrivateSendQueue& b)
{
return a.nDenom == b.nDenom && a.masternodeOutpoint == b.masternodeOutpoint && a.nTime == b.nTime && a.fReady == b.fReady;
}
};
/** Helper class to store mixing transaction (tx) information.
2015-03-05 08:49:50 +01:00
*/
class CPrivateSendBroadcastTx
{
private:
// memory only
// when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
int nConfirmedHeight;
public:
CTransactionRef tx;
COutPoint masternodeOutpoint;
std::vector<unsigned char> vchSig;
int64_t sigTime;
CPrivateSendBroadcastTx() :
nConfirmedHeight(-1),
tx(MakeTransactionRef()),
masternodeOutpoint(),
vchSig(),
sigTime(0)
2018-11-05 10:29:07 +01:00
{
}
CPrivateSendBroadcastTx(const CTransactionRef& _tx, COutPoint _outpoint, int64_t _sigTime) :
nConfirmedHeight(-1),
tx(_tx),
masternodeOutpoint(_outpoint),
vchSig(),
sigTime(_sigTime)
2018-11-05 10:29:07 +01:00
{
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
2018-11-05 10:29:07 +01:00
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(tx);
READWRITE(masternodeOutpoint);
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(vchSig);
}
READWRITE(sigTime);
}
friend bool operator==(const CPrivateSendBroadcastTx& a, const CPrivateSendBroadcastTx& b)
{
return *a.tx == *b.tx;
}
friend bool operator!=(const CPrivateSendBroadcastTx& a, const CPrivateSendBroadcastTx& b)
{
return !(a == b);
}
explicit operator bool() const
{
return *this != CPrivateSendBroadcastTx();
}
uint256 GetSignatureHash() const;
bool Sign();
bool CheckSignature(const CBLSPublicKey& blsPubKey) const;
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
bool IsExpired(int nHeight);
};
// base class
class CPrivateSendBaseSession
{
protected:
mutable CCriticalSection cs_privatesend;
std::vector<CPrivateSendEntry> vecEntries; // Masternode/clients entries
2018-11-05 10:29:07 +01:00
PoolState nState; // should be one of the POOL_STATE_XXX values
int64_t nTimeLastSuccessfulStep; // the time when last successful mixing step was performed
int nSessionID; // 0 if no mixing session is active
CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing
void SetNull();
public:
int nSessionDenom; //Users must submit a denom matching this
CPrivateSendBaseSession() :
vecEntries(),
nState(POOL_STATE_IDLE),
nTimeLastSuccessfulStep(0),
nSessionID(0),
finalMutableTransaction(),
nSessionDenom(0)
2018-11-05 10:29:07 +01:00
{
}
int GetState() const { return nState; }
std::string GetStateString() const;
int GetEntriesCount() const { return vecEntries.size(); }
};
// base class
class CPrivateSendBaseManager
{
protected:
mutable CCriticalSection cs_vecqueue;
// The current mixing sessions in progress on the network
std::vector<CPrivateSendQueue> vecPrivateSendQueue;
void SetNull();
void CheckQueue();
public:
2018-11-05 10:29:07 +01:00
CPrivateSendBaseManager() :
vecPrivateSendQueue() {}
int GetQueueSize() const { return vecPrivateSendQueue.size(); }
bool GetQueueItemAndTry(CPrivateSendQueue& dsqRet);
};
// helper class
class CPrivateSend
{
private:
// make constructor, destructor and copying not available
CPrivateSend() {}
~CPrivateSend() {}
CPrivateSend(CPrivateSend const&) = delete;
2018-11-05 10:29:07 +01:00
CPrivateSend& operator=(CPrivateSend const&) = delete;
// static members
static std::vector<CAmount> vecStandardDenominations;
static std::map<uint256, CPrivateSendBroadcastTx> mapDSTX;
static CCriticalSection cs_mapdstx;
static void CheckDSTXes(int nHeight);
public:
static void InitStandardDenominations();
static std::vector<CAmount> GetStandardDenominations() { return vecStandardDenominations; }
static CAmount GetSmallestDenomination() { return vecStandardDenominations.back(); }
/// Get the denominations for a specific amount of dash.
static int GetDenominationsByAmounts(const std::vector<CAmount>& vecAmount);
2015-03-18 18:19:13 +01:00
static bool IsDenominatedAmount(CAmount nInputAmount);
2015-03-05 08:49:50 +01:00
/// Get the denominations for a list of outputs (returns a bitshifted integer)
static int GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fSingleRandomDenom = false);
static std::string GetDenominationsToString(int nDenom);
2018-11-05 10:29:07 +01:00
static bool GetDenominationsBits(int nDenom, std::vector<int>& vecBitsRet);
static std::string GetMessageByID(PoolMessage nMessageID);
/// Get the minimum/maximum number of participants for the pool
static int GetMinPoolParticipants() { return Params().PoolMinParticipants(); }
static int GetMaxPoolParticipants() { return Params().PoolMaxParticipants(); }
2015-03-02 00:09:33 +01:00
static CAmount GetMaxPoolAmount() { return vecStandardDenominations.empty() ? 0 : PRIVATESEND_ENTRY_MAX_SIZE * vecStandardDenominations.front(); }
/// If the collateral is valid given by a client
static bool IsCollateralValid(const CTransaction& txCollateral);
static CAmount GetCollateralAmount() { return GetSmallestDenomination() / 10; }
static CAmount GetMaxCollateralAmount() { return GetCollateralAmount() * 4; }
static bool IsCollateralAmount(CAmount nInputAmount);
static void AddDSTX(const CPrivateSendBroadcastTx& dstx);
static CPrivateSendBroadcastTx GetDSTX(const uint256& hash);
2018-11-05 10:29:07 +01:00
static void UpdatedBlockTip(const CBlockIndex* pindex);
static void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int posInBlock);
2015-03-02 00:09:33 +01:00
};
#endif