neobytes/src/privatesend.h
UdjinM6 ea793a71f1 Make sure mixing masternode follows bip69 before signing final mixing tx (#1510)
* Make sure mixing tx follows bip69 before signing it

* bump MIN_PRIVATESEND_PEER_PROTO_VERSION to 70208
2017-09-22 04:53:15 +03:00

362 lines
9.8 KiB
C++

// 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 PRIVATESEND_H
#define PRIVATESEND_H
#include "chainparams.h"
#include "primitives/transaction.h"
#include "pubkey.h"
#include "sync.h"
#include "tinyformat.h"
#include "timedata.h"
class CPrivateSend;
class CConnman;
// timeouts
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;
//! minimum peer version accepted by mixing pool
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70208;
static const CAmount 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
};
// 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
*/
class CTxDSIn : public CTxIn
{
public:
bool fHasSig; // flag to indicate if signed
int nSentTimes; //times we've sent this anonymously
CTxDSIn(const CTxIn& txin) :
CTxIn(txin),
fHasSig(false),
nSentTimes(0)
{}
CTxDSIn() :
CTxIn(),
fHasSig(false),
nSentTimes(0)
{}
};
/** Holds an mixing output
*/
class CTxDSOut : public CTxOut
{
public:
int nSentTimes; //times we've sent this anonymously
CTxDSOut(const CTxOut& out) :
CTxOut(out),
nSentTimes(0)
{}
CTxDSOut() :
CTxOut(),
nSentTimes(0)
{}
};
// A clients transaction in the mixing pool
class CDarkSendEntry
{
public:
std::vector<CTxDSIn> vecTxDSIn;
std::vector<CTxDSOut> vecTxDSOut;
CTransaction txCollateral;
// memory only
CService addr;
CDarkSendEntry() :
vecTxDSIn(std::vector<CTxDSIn>()),
vecTxDSOut(std::vector<CTxDSOut>()),
txCollateral(CTransaction()),
addr(CService())
{}
CDarkSendEntry(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vecTxDSIn);
READWRITE(txCollateral);
READWRITE(vecTxDSOut);
}
bool AddScriptSig(const CTxIn& txin);
};
/**
* A currently inprogress mixing merge and denomination information
*/
class CDarksendQueue
{
public:
int nDenom;
CTxIn vin;
int64_t nTime;
bool fReady; //ready for submit
std::vector<unsigned char> vchSig;
// memory only
bool fTried;
CDarksendQueue() :
nDenom(0),
vin(CTxIn()),
nTime(0),
fReady(false),
vchSig(std::vector<unsigned char>()),
fTried(false)
{}
CDarksendQueue(int nDenom, COutPoint outpoint, int64_t nTime, bool fReady) :
nDenom(nDenom),
vin(CTxIn(outpoint)),
nTime(nTime),
fReady(fReady),
vchSig(std::vector<unsigned char>()),
fTried(false)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(nDenom);
READWRITE(vin);
READWRITE(nTime);
READWRITE(fReady);
READWRITE(vchSig);
}
/** Sign this mixing transaction
* \return true if all conditions are met:
* 1) we have an active Masternode,
* 2) we have a valid Masternode private key,
* 3) we signed the message successfully, and
* 4) we verified the message successfully
*/
bool Sign();
/// Check if we have a valid Masternode address
bool CheckSignature(const CPubKey& pubKeyMasternode);
bool Relay(CConnman &connman);
/// Is this queue expired?
bool IsExpired() { return GetAdjustedTime() - nTime > PRIVATESEND_QUEUE_TIMEOUT; }
std::string ToString()
{
return strprintf("nDenom=%d, nTime=%lld, fReady=%s, fTried=%s, masternode=%s",
nDenom, nTime, fReady ? "true" : "false", fTried ? "true" : "false", vin.prevout.ToStringShort());
}
friend bool operator==(const CDarksendQueue& a, const CDarksendQueue& b)
{
return a.nDenom == b.nDenom && a.vin.prevout == b.vin.prevout && a.nTime == b.nTime && a.fReady == b.fReady;
}
};
/** Helper class to store mixing transaction (tx) information.
*/
class CDarksendBroadcastTx
{
private:
// memory only
// when corresponding tx is 0-confirmed or conflicted, nConfirmedHeight is -1
int nConfirmedHeight;
public:
CTransaction tx;
CTxIn vin;
std::vector<unsigned char> vchSig;
int64_t sigTime;
CDarksendBroadcastTx() :
nConfirmedHeight(-1),
tx(),
vin(),
vchSig(),
sigTime(0)
{}
CDarksendBroadcastTx(CTransaction tx, COutPoint outpoint, int64_t sigTime) :
nConfirmedHeight(-1),
tx(tx),
vin(CTxIn(outpoint)),
vchSig(),
sigTime(sigTime)
{}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(tx);
READWRITE(vin);
READWRITE(vchSig);
READWRITE(sigTime);
}
friend bool operator==(const CDarksendBroadcastTx& a, const CDarksendBroadcastTx& b)
{
return a.tx == b.tx;
}
friend bool operator!=(const CDarksendBroadcastTx& a, const CDarksendBroadcastTx& b)
{
return !(a == b);
}
explicit operator bool() const
{
return *this != CDarksendBroadcastTx();
}
bool Sign();
bool CheckSignature(const CPubKey& pubKeyMasternode);
void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; }
bool IsExpired(int nHeight);
};
// base class
class CPrivateSendBase
{
protected:
// The current mixing sessions in progress on the network
std::vector<CDarksendQueue> vecDarksendQueue;
std::vector<CDarkSendEntry> vecEntries; // Masternode/clients entries
PoolState nState; // should be one of the POOL_STATE_XXX values
int64_t nTimeLastSuccessfulStep; // the time when last successful mixing step was performed, in UTC milliseconds
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 an denom matching this
CPrivateSendBase() { SetNull(); }
int GetQueueSize() const { return vecDarksendQueue.size(); }
int GetState() const { return nState; }
std::string GetStateString() const;
int GetEntriesCount() const { return vecEntries.size(); }
};
// helper class
class CPrivateSend
{
private:
// make constructor, destructor and copying not available
CPrivateSend() {}
~CPrivateSend() {}
CPrivateSend(CPrivateSend const&) = delete;
CPrivateSend& operator= (CPrivateSend const&) = delete;
static const CAmount COLLATERAL = 0.001 * COIN;
// static members
static std::vector<CAmount> vecStandardDenominations;
static std::map<uint256, CDarksendBroadcastTx> mapDSTX;
static CCriticalSection cs_mapdstx;
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);
/// Get the denominations for a list of outputs (returns a bitshifted integer)
static int GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fSingleRandomDenom = false);
static int GetDenominations(const std::vector<CTxDSOut>& vecTxDSOut);
static std::string GetDenominationsToString(int nDenom);
static bool GetDenominationsBits(int nDenom, std::vector<int> &vecBitsRet);
static std::string GetMessageByID(PoolMessage nMessageID);
/// Get the maximum number of transactions for the pool
static int GetMaxPoolTransactions() { return Params().PoolMaxTransactions(); }
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 COLLATERAL; }
static CAmount GetMaxCollateralAmount() { return COLLATERAL*4; }
static void AddDSTX(const CDarksendBroadcastTx& dstx);
static CDarksendBroadcastTx GetDSTX(const uint256& hash);
static void CheckDSTXes(int nHeight);
static void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
};
void ThreadCheckPrivateSend(CConnman& connman);
#endif