Merge #928: Refactor All The Things - part1

86d8505 Refactor CActiveMasternode
+ move strMasterNodeAddr to CActiveMasternode

a005c79 Refactor InstantSend
+ new lock cs_instantsend to protect maps on CleanTransactionLocksList()
+ new DEFAULT_INSTANTSEND_DEPTH constant
+ rename MIN_INSTANTX_PROTO_VERSION to MIN_INSTANTSEND_PROTO_VERSION and bump it

d24182c Refactor Privatesend
+ decouple from util.h and version.h
+ more functions for CDarksendBroadcastTx: constructors, signing, serialization
+ move from rand() to insecure_rand() in general but to GetRand() for session id
+ fix defaults
This commit is contained in:
UdjinM6 2016-08-05 23:49:45 +04:00 committed by Holger Schinzel
parent 08703cebe6
commit 5a8c0c9b9d
28 changed files with 1829 additions and 1993 deletions

View File

@ -2,35 +2,36 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "addrman.h"
#include "protocol.h"
#include "activemasternode.h"
#include "masternode.h"
#include "masternode-sync.h"
#include "masternodeman.h"
#include "spork.h"
#include "protocol.h"
//
// Bootup the Masternode, look for a 1000DRK input and register on the network
//
void CActiveMasternode::ManageStatus()
{
std::string errorMessage;
extern CWallet* pwalletMain;
// Keep track of the active Masternode
CActiveMasternode activeMasternode;
// Bootup the Masternode, look for a 1000DASH input and register on the network
void CActiveMasternode::ManageState()
{
std::string strErrorMessage;
if(!fMasterNode) return;
if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n");
if (fDebug) LogPrintf("CActiveMasternode::ManageState -- Begin\n");
//need correct blocks to send ping
if(Params().NetworkIDString() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
status = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
LogPrintf("CActiveMasternode::ManageStatus() - %s\n", GetStatus());
nState = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
LogPrintf("CActiveMasternode::ManageState -- %s\n", GetStatus());
return;
}
if(status == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) status = ACTIVE_MASTERNODE_INITIAL;
if(nState == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) nState = ACTIVE_MASTERNODE_INITIAL;
if(status == ACTIVE_MASTERNODE_INITIAL) {
if(nState == ACTIVE_MASTERNODE_INITIAL) {
CMasternode *pmn;
pmn = mnodeman.Find(pubKeyMasternode);
if(pmn != NULL) {
@ -40,28 +41,28 @@ void CActiveMasternode::ManageStatus()
}
}
if(status != ACTIVE_MASTERNODE_STARTED) {
if(nState != ACTIVE_MASTERNODE_STARTED) {
// Set defaults
status = ACTIVE_MASTERNODE_NOT_CAPABLE;
notCapableReason = "";
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = "";
if(pwalletMain->IsLocked()){
notCapableReason = "Wallet is locked.";
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
if(pwalletMain->IsLocked()) {
strNotCapableReason = "Wallet is locked.";
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
return;
}
if(pwalletMain->GetBalance() == 0){
notCapableReason = "Hot node, waiting for remote activation.";
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
if(pwalletMain->GetBalance() == 0) {
nState = ACTIVE_MASTERNODE_INITIAL;
LogPrintf("CActiveMasternode::ManageState() -- %s\n", GetStatus());
return;
}
if(strMasterNodeAddr.empty()) {
if(!GetLocal(service)) {
notCapableReason = "Can't detect external address. Please use the masternodeaddr configuration option.";
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
strNotCapableReason = "Can't detect external address. Please use the masternodeaddr configuration option.";
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
return;
}
} else {
@ -71,126 +72,124 @@ void CActiveMasternode::ManageStatus()
int mainnetDefaultPort = Params(CBaseChainParams::MAIN).GetDefaultPort();
if(Params().NetworkIDString() == CBaseChainParams::MAIN) {
if(service.GetPort() != mainnetDefaultPort) {
notCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
strNotCapableReason = strprintf("Invalid port: %u - only %d is supported on mainnet.", service.GetPort(), mainnetDefaultPort);
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
return;
}
} else if(service.GetPort() == mainnetDefaultPort) {
notCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
strNotCapableReason = strprintf("Invalid port: %u - %d is only supported on mainnet.", service.GetPort(), mainnetDefaultPort);
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
return;
}
LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString());
LogPrintf("CActiveMasternode::ManageState -- Checking inbound connection to '%s'\n", service.ToString());
if(!ConnectNode((CAddress)service, NULL, true)){
notCapableReason = "Could not connect to " + service.ToString();
LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
if(!ConnectNode((CAddress)service, NULL, true)) {
strNotCapableReason = "Could not connect to " + service.ToString();
LogPrintf("CActiveMasternode::ManageState -- not capable: %s\n", strNotCapableReason);
return;
}
// Choose coins to use
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyCollateral;
CKey keyCollateral;
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateralAddress, keyCollateralAddress)) {
if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateral, keyCollateral)) {
if(GetInputAge(vin) < Params().GetConsensus().nMasternodeMinimumConfirmations){
status = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
notCapableReason = strprintf("%s - %d confirmations", GetStatus(), GetInputAge(vin));
LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason);
int nInputAge = GetInputAge(vin);
if(nInputAge < Params().GetConsensus().nMasternodeMinimumConfirmations){
nState = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
strNotCapableReason = strprintf("%s - %d confirmations", GetStatus(), nInputAge);
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
return;
}
LOCK(pwalletMain->cs_wallet);
pwalletMain->LockCoin(vin.prevout);
// send to all nodes
CMasternodeBroadcast mnb;
if(!CMasternodeBroadcast::Create(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb)) {
notCapableReason = "Error on CreateBroadcast: " + errorMessage;
LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason);
if(!CMasternodeBroadcast::Create(vin, service, keyCollateral, pubKeyCollateral, keyMasternode, pubKeyMasternode, strErrorMessage, mnb)) {
strNotCapableReason = "Error on CMasternodeBroadcast::Create -- " + strErrorMessage;
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
return;
}
//update to masternode list
LogPrintf("CActiveMasternode::ManageStatus() - Update Masternode List\n");
LogPrintf("CActiveMasternode::ManageState -- Update Masternode List\n");
mnodeman.UpdateMasternodeList(mnb);
//send to all peers
LogPrintf("CActiveMasternode::ManageStatus() - Relay broadcast vin = %s\n", vin.ToString());
LogPrintf("CActiveMasternode::ManageState -- Relay broadcast, vin=%s\n", vin.ToString());
mnb.Relay();
LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n");
status = ACTIVE_MASTERNODE_STARTED;
LogPrintf("CActiveMasternode::ManageState -- Is capable master node!\n");
nState = ACTIVE_MASTERNODE_STARTED;
return;
} else {
notCapableReason = "Could not find suitable coins!";
LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason);
strNotCapableReason = "Could not find suitable coins!";
LogPrintf("CActiveMasternode::ManageState -- %s\n", strNotCapableReason);
return;
}
}
//send to all peers
if(!SendMasternodePing(errorMessage)) {
LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage);
if(!SendMasternodePing(strErrorMessage)) {
LogPrintf("CActiveMasternode::ManageState -- Error on SendMasternodePing(): %s\n", strErrorMessage);
}
}
std::string CActiveMasternode::GetStatus() {
switch (status) {
case ACTIVE_MASTERNODE_INITIAL: return "Node just started, not yet activated";
case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable masternode: " + notCapableReason;
case ACTIVE_MASTERNODE_STARTED: return "Masternode successfully started";
default: return "unknown";
std::string CActiveMasternode::GetStatus()
{
switch (nState) {
case ACTIVE_MASTERNODE_INITIAL: return "Node just started, not yet activated";
case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return strprintf("Masternode input must have at least %d confirmations", Params().GetConsensus().nMasternodeMinimumConfirmations);
case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable masternode: " + strNotCapableReason;
case ACTIVE_MASTERNODE_STARTED: return "Masternode successfully started";
default: return "unknown";
}
}
bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) {
if(status != ACTIVE_MASTERNODE_STARTED) {
errorMessage = "Masternode is not in a running status";
bool CActiveMasternode::SendMasternodePing(std::string& strErrorMessage)
{
if(nState != ACTIVE_MASTERNODE_STARTED) {
strErrorMessage = "Masternode is not in a running status";
return false;
}
LogPrintf("CActiveMasternode::SendMasternodePing() - Relay Masternode Ping vin = %s\n", vin.ToString());
CMasternodePing mnp(vin);
if(!mnp.Sign(keyMasternode, pubKeyMasternode))
{
errorMessage = "Couldn't sign Masternode Ping";
if(!mnp.Sign(keyMasternode, pubKeyMasternode)) {
strErrorMessage = "Couldn't sign Masternode Ping";
return false;
}
// Update lastPing for our masternode in Masternode list
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
if(pmn->IsPingedWithin(MASTERNODE_PING_SECONDS, mnp.sigTime)){
errorMessage = "Too early to send Masternode Ping";
if(pmn != NULL) {
if(pmn->IsPingedWithin(MASTERNODE_MIN_MNP_SECONDS, mnp.sigTime)) {
strErrorMessage = "Too early to send Masternode Ping";
return false;
}
pmn->lastPing = mnp;
mnodeman.mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp));
mnodeman.mapSeenMasternodePing.insert(std::make_pair(mnp.GetHash(), mnp));
//mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it
CMasternodeBroadcast mnb(*pmn);
uint256 hash = mnb.GetHash();
if(mnodeman.mapSeenMasternodeBroadcast.count(hash)) mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = mnp;
if(mnodeman.mapSeenMasternodeBroadcast.count(hash))
mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = mnp;
LogPrintf("CActiveMasternode::SendMasternodePing -- Relaying ping, collateral=%s\n", vin.ToString());
mnp.Relay();
return true;
}
else
{
} else {
// Seems like we are trying to send a ping while the Masternode is not registered in the network
errorMessage = "PrivateSend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString();
status = ACTIVE_MASTERNODE_NOT_CAPABLE;
notCapableReason = errorMessage;
strErrorMessage = "PrivateSend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString();
nState = ACTIVE_MASTERNODE_NOT_CAPABLE;
strNotCapableReason = strErrorMessage;
return false;
}
}
@ -200,13 +199,13 @@ bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newServ
{
if(!fMasterNode) return false;
status = ACTIVE_MASTERNODE_STARTED;
nState = ACTIVE_MASTERNODE_STARTED;
//The values below are needed for signing mnping messages going forward
vin = newVin;
service = newService;
LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n");
LogPrintf("CActiveMasternode::EnableHotColdMasterNode -- Enabled! You may shut down the cold daemon.\n");
return true;
}

View File

@ -1,23 +1,23 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2014-2016 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 ACTIVEMASTERNODE_H
#define ACTIVEMASTERNODE_H
#include "sync.h"
#include "net.h"
#include "key.h"
#include "init.h"
#include "wallet/wallet.h"
#include "darksend.h"
#include "masternode.h"
#define ACTIVE_MASTERNODE_INITIAL 0 // initial state
#define ACTIVE_MASTERNODE_SYNC_IN_PROCESS 1
#define ACTIVE_MASTERNODE_INPUT_TOO_NEW 2
#define ACTIVE_MASTERNODE_NOT_CAPABLE 3
#define ACTIVE_MASTERNODE_STARTED 4
class CActiveMasternode;
static const int ACTIVE_MASTERNODE_INITIAL = 0; // initial state
static const int ACTIVE_MASTERNODE_SYNC_IN_PROCESS = 1;
static const int ACTIVE_MASTERNODE_INPUT_TOO_NEW = 2;
static const int ACTIVE_MASTERNODE_NOT_CAPABLE = 3;
static const int ACTIVE_MASTERNODE_STARTED = 4;
extern CActiveMasternode activeMasternode;
// Responsible for activating the Masternode and pinging the network
class CActiveMasternode
@ -27,11 +27,12 @@ private:
mutable CCriticalSection cs;
/// Ping Masternode
bool SendMasternodePing(std::string& errorMessage);
bool SendMasternodePing(std::string& strErrorMessage);
public:
// Initialized by init.cpp
// Keys for the main Masternode
std::string strMasterNodeAddr;
// Keys for the active Masternode
CPubKey pubKeyMasternode;
CKey keyMasternode;
@ -39,19 +40,16 @@ public:
CTxIn vin;
CService service;
int status;
std::string notCapableReason;
int nState; // should be one of ACTIVE_MASTERNODE_XXXX
std::string strNotCapableReason;
CActiveMasternode()
{
status = ACTIVE_MASTERNODE_INITIAL;
}
CActiveMasternode() : nState(ACTIVE_MASTERNODE_INITIAL) {}
/// Manage state of active Masternode
void ManageState();
/// Manage status of main Masternode
void ManageStatus();
std::string GetStatus();
/// Enable cold wallet mode (run a Masternode with no funds)
bool EnableHotColdMasterNode(CTxIn& vin, CService& addr);
};

View File

@ -1,4 +1,4 @@
#include "darksend.h"
#include "darksend-relay.h"
@ -42,7 +42,7 @@ bool CDarkSendRelay::Sign(std::string strSharedKey)
CPubKey pubkey2;
std::string errorMessage = "";
if(!darkSendSigner.SetKey(strSharedKey, errorMessage, key2, pubkey2))
if(!darkSendSigner.GetKeysFromSecret(strSharedKey, errorMessage, key2, pubkey2))
{
LogPrintf("CDarkSendRelay():Sign - ERROR: Invalid shared key: '%s'\n", errorMessage);
return false;
@ -69,7 +69,7 @@ bool CDarkSendRelay::VerifyMessage(std::string strSharedKey)
CPubKey pubkey2;
std::string errorMessage = "";
if(!darkSendSigner.SetKey(strSharedKey, errorMessage, key2, pubkey2))
if(!darkSendSigner.GetKeysFromSecret(strSharedKey, errorMessage, key2, pubkey2))
{
LogPrintf("CDarkSendRelay()::VerifyMessage - ERROR: Invalid shared key: '%s'\n", errorMessage);
return false;
@ -85,7 +85,7 @@ bool CDarkSendRelay::VerifyMessage(std::string strSharedKey)
void CDarkSendRelay::Relay()
{
int nCount = std::min(mnodeman.CountEnabled(MIN_POOL_PEER_PROTO_VERSION), 20);
int nCount = std::min(mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION), 20);
int nRank1 = (rand() % nCount)+1;
int nRank2 = (rand() % nCount)+1;
@ -101,7 +101,7 @@ void CDarkSendRelay::Relay()
void CDarkSendRelay::RelayThroughNode(int nRank)
{
CMasternode* pmn = mnodeman.GetMasternodeByRank(nRank, nBlockHeight, MIN_POOL_PEER_PROTO_VERSION);
CMasternode* pmn = mnodeman.GetMasternodeByRank(nRank, nBlockHeight, MIN_PRIVATESEND_PEER_PROTO_VERSION);
if(pmn != NULL){
//printf("RelayThroughNode %s\n", pmn->addr.ToString().c_str());

File diff suppressed because it is too large Load Diff

View File

@ -5,63 +5,68 @@
#ifndef DARKSEND_H
#define DARKSEND_H
#include "main.h"
#include "sync.h"
#include "activemasternode.h"
#include "masternodeman.h"
#include "darksend-relay.h"
#include "masternode.h"
#include "wallet/wallet.h"
class CTxIn;
class CDarksendPool;
class CDarkSendSigner;
class CMasterNodeVote;
class CBitcoinAddress;
class CDarksendQueue;
class CDarksendBroadcastTx;
class CActiveMasternode;
// pool states for mixing
#define POOL_STATUS_UNKNOWN 0 // waiting for update
#define POOL_STATUS_IDLE 1 // waiting for update
#define POOL_STATUS_QUEUE 2 // waiting in a queue
#define POOL_STATUS_ACCEPTING_ENTRIES 3 // accepting entries
#define POOL_STATUS_FINALIZE_TRANSACTION 4 // master node will broadcast what it accepted
#define POOL_STATUS_SIGNING 5 // check inputs/outputs, sign final tx
#define POOL_STATUS_TRANSMISSION 6 // transmit transaction
#define POOL_STATUS_ERROR 7 // error
#define POOL_STATUS_SUCCESS 8 // success
static const int POOL_STATE_UNKNOWN = 0; // waiting for initialization
static const int POOL_STATE_IDLE = 1; // waiting for update
static const int POOL_STATE_QUEUE = 2; // waiting in a queue
static const int POOL_STATE_ACCEPTING_ENTRIES = 3; // accepting entries
static const int POOL_STATE_FINALIZE_TRANSACTION = 4; // master node will broadcast what it accepted
static const int POOL_STATE_SIGNING = 5; // check inputs/outputs, sign final tx
static const int POOL_STATE_TRANSMISSION = 6; // transmit transaction
static const int POOL_STATE_ERROR = 7; // error
static const int POOL_STATE_SUCCESS = 8; // success
// status update message constants
#define MASTERNODE_ACCEPTED 1
#define MASTERNODE_REJECTED 0
#define MASTERNODE_RESET -1
static const int MASTERNODE_ACCEPTED = 1;
static const int MASTERNODE_REJECTED = 0;
static const int MASTERNODE_RESET = -1;
#define DARKSEND_AUTO_TIMEOUT_MIN 5
#define DARKSEND_AUTO_TIMEOUT_MAX 15
#define DARKSEND_QUEUE_TIMEOUT 30
#define DARKSEND_SIGNING_TIMEOUT 15
// timeouts
static const int DARKSEND_AUTO_TIMEOUT_MIN = 5;
static const int DARKSEND_AUTO_TIMEOUT_MAX = 15;
static const int DARKSEND_QUEUE_TIMEOUT = 30;
static const int DARKSEND_SIGNING_TIMEOUT = 15;
// used for anonymous relaying of inputs/outputs/sigs
#define DARKSEND_RELAY_IN 1
#define DARKSEND_RELAY_OUT 2
#define DARKSEND_RELAY_SIG 3
//! minimum peer version accepted by DarksendPool
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70201;
static const CAmount DARKSEND_COLLATERAL = 0.01 * COIN;
static const CAmount DARKSEND_POOL_MAX = 999.99 * COIN;
static const int DENOMS_COUNT_MAX = 100;
static const int DEFAULT_PRIVATESEND_ROUNDS = 2;
static const int DEFAULT_PRIVATESEND_AMOUNT = 1000;
static const bool DEFAULT_PRIVATESEND_MULTISESSION = false;
static const CAmount DARKSEND_COLLATERAL = (0.01*COIN);
static const CAmount DARKSEND_POOL_MAX = (999.99*COIN);
static const CAmount DENOMS_COUNT_MAX = 100;
// Warn user if mixing in gui or try to create backup if mixing in daemon mode
// when we have only this many keys left
static const int PS_KEYS_THRESHOLD_WARNING = 100;
static const int PRIVATESEND_KEYS_THRESHOLD_WARNING = 100;
// Stop mixing completely, it's too dangerous to continue when we have only this many keys left
static const int PS_KEYS_THRESHOLD_STOP = 50;
static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50;
extern int nPrivateSendRounds;
extern int nPrivateSendAmount;
extern int nLiquidityProvider;
extern bool fEnablePrivateSend;
extern bool fPrivateSendMultiSession;
// The main object for accessing mixing
extern CDarksendPool darkSendPool;
// A helper object for signing messages from Masternodes
extern CDarkSendSigner darkSendSigner;
extern std::vector<CDarksendQueue> vecDarksendQueue;
extern map<uint256, CDarksendBroadcastTx> mapDarksendBroadcastTxes;
extern CActiveMasternode activeMasternode;
/** Holds an Darksend input
extern std::map<uint256, CDarksendBroadcastTx> mapDarksendBroadcastTxes;
extern std::vector<CAmount> vecPrivateSendDenominations;
/** Holds an mixing input
*/
class CTxDSIn : public CTxIn
{
@ -69,114 +74,69 @@ public:
bool fHasSig; // flag to indicate if signed
int nSentTimes; //times we've sent this anonymously
CTxDSIn(const CTxIn& in)
{
prevout = in.prevout;
scriptSig = in.scriptSig;
prevPubKey = in.prevPubKey;
nSequence = in.nSequence;
nSentTimes = 0;
fHasSig = false;
}
CTxDSIn(const CTxIn& txin) :
CTxIn(txin),
fHasSig(false),
nSentTimes(0) {}
};
/** Holds an Darksend output
/** Holds an mixing output
*/
class CTxDSOut : public CTxOut
{
public:
int nSentTimes; //times we've sent this anonymously
CTxDSOut(const CTxOut& out)
{
nValue = out.nValue;
nRounds = out.nRounds;
scriptPubKey = out.scriptPubKey;
nSentTimes = 0;
}
CTxDSOut(const CTxOut& out) :
CTxOut(out),
nSentTimes(0) {}
};
// A clients transaction in the darksend pool
// A clients transaction in the mixing pool
class CDarkSendEntry
{
public:
std::vector<CTxDSIn> vecTxDSIn;
std::vector<CTxDSOut> vecTxDSOut;
CTransaction txCollateral;
CAmount nAmount;
int64_t nTimeAdded; // time in UTC milliseconds
bool isSet;
std::vector<CTxDSIn> sev;
std::vector<CTxDSOut> vout;
CAmount amount;
CTransaction collateral;
CTransaction txSupporting;
int64_t addedTime; // time in UTC milliseconds
CDarkSendEntry()
{
isSet = false;
collateral = CTransaction();
amount = 0;
}
CDarkSendEntry() :
txCollateral(CTransaction()),
nAmount(0),
nTimeAdded(0),
isSet(false) {}
/// Add entries to use for Darksend
bool Add(const std::vector<CTxIn> vinIn, CAmount amountIn, const CTransaction collateralIn, const std::vector<CTxOut> voutIn)
{
if(isSet){return false;}
/// Add entries to use for mixing
bool Add(const std::vector<CTxIn> vecTxIn, CAmount nAmount, const CTransaction txCollateral, const std::vector<CTxOut> vecTxOut);
BOOST_FOREACH(const CTxIn& in, vinIn)
sev.push_back(in);
bool AddScriptSig(const CTxIn& txin);
BOOST_FOREACH(const CTxOut& out, voutIn)
vout.push_back(out);
amount = amountIn;
collateral = collateralIn;
isSet = true;
addedTime = GetTime();
return true;
}
bool AddSig(const CTxIn& vin)
{
BOOST_FOREACH(CTxDSIn& s, sev) {
if(s.prevout == vin.prevout && s.nSequence == vin.nSequence){
if(s.fHasSig){return false;}
s.scriptSig = vin.scriptSig;
s.prevPubKey = vin.prevPubKey;
s.fHasSig = true;
return true;
}
}
return false;
}
bool IsExpired()
{
return (GetTime() - addedTime) > DARKSEND_QUEUE_TIMEOUT;// 30 seconds
}
bool IsExpired() { return GetTime() - nTimeAdded > DARKSEND_QUEUE_TIMEOUT; }
};
/**
* A currently inprogress Darksend merge and denomination information
* A currently inprogress mixing merge and denomination information
*/
class CDarksendQueue
{
public:
CTxIn vin;
int64_t time;
int nDenom;
bool ready; //ready for submit
CTxIn vin;
int64_t nTime;
bool fReady; //ready for submit
std::vector<unsigned char> vchSig;
CDarksendQueue()
{
nDenom = 0;
vin = CTxIn();
time = 0;
vchSig.clear();
ready = false;
}
CDarksendQueue() { CDarksendQueue(0, CTxIn(), 0, false); }
CDarksendQueue(int nDenom, CTxIn vin, int64_t nTime, bool fReady) :
nDenom(nDenom),
vin(vin),
nTime(nTime),
fReady(fReady) { vchSig = std::vector<unsigned char>(); }
ADD_SERIALIZE_METHODS;
@ -184,35 +144,15 @@ public:
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(nDenom);
READWRITE(vin);
READWRITE(time);
READWRITE(ready);
READWRITE(nTime);
READWRITE(fReady);
READWRITE(vchSig);
}
bool GetAddress(CService &addr)
{
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
addr = pmn->addr;
return true;
}
return false;
}
bool GetAddress(CService &addrRet);
bool GetProtocolVersion(int &nProtocolVersionRet);
/// Get the protocol version
bool GetProtocolVersion(int &protocolVersion)
{
CMasternode* pmn = mnodeman.Find(vin);
if(pmn != NULL)
{
protocolVersion = pmn->protocolVersion;
return true;
}
return false;
}
/** Sign this Darksend transaction
/** 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,
@ -220,29 +160,42 @@ public:
* 4) we verified the message successfully
*/
bool Sign();
bool Relay();
/// Is this Darksend expired?
bool IsExpired()
{
return (GetTime() - time) > DARKSEND_QUEUE_TIMEOUT;// 30 seconds
}
/// Check if we have a valid Masternode address
bool CheckSignature();
bool Relay();
/// Is this queue expired?
bool IsExpired() { return GetTime() - nTime > DARKSEND_QUEUE_TIMEOUT; }
};
/** Helper class to store Darksend transaction (tx) information.
/** Helper class to store mixing transaction (tx) information.
*/
class CDarksendBroadcastTx
{
public:
CTransaction tx;
CTxIn vin;
vector<unsigned char> vchSig;
std::vector<unsigned char> vchSig;
int64_t sigTime;
CDarksendBroadcastTx() { CDarksendBroadcastTx(CTransaction(), CTxIn(), 0); }
CDarksendBroadcastTx(CTransaction tx, CTxIn vin, int64_t sigTime) :
tx(tx), vin(vin), sigTime(sigTime) { vchSig = std::vector<unsigned char>(); }
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);
}
bool Sign();
bool CheckSignature();
};
/** Helper object for signing and checking signatures
@ -251,59 +204,20 @@ class CDarkSendSigner
{
public:
/// Is the inputs associated with this public key? (and there is 1000 DASH - checking if valid masternode)
bool IsVinAssociatedWithPubkey(CTxIn& vin, CPubKey& pubkey);
bool IsVinAssociatedWithPubkey(const CTxIn& vin, const CPubKey& pubkey);
/// Set the private/public key values, returns true if successful
bool SetKey(std::string strSecret, std::string& errorMessage, CKey& key, CPubKey& pubkey);
bool GetKeysFromSecret(std::string strSecret, std::string& strErrorMessageRet, CKey& keyRet, CPubKey& pubkeyRet);
/// Sign the message, returns true if successful
bool SignMessage(std::string strMessage, std::string& errorMessage, std::vector<unsigned char>& vchSig, CKey key);
bool SignMessage(std::string strMessage, std::string& strErrorMessageRet, std::vector<unsigned char>& vchSigRet, CKey key);
/// Verify the message, returns true if succcessful
bool VerifyMessage(CPubKey pubkey, std::vector<unsigned char>& vchSig, std::string strMessage, std::string& errorMessage);
bool VerifyMessage(CPubKey pubkey, const std::vector<unsigned char>& vchSig, std::string strMessage, std::string& strErrorMessageRet);
};
/** Used to keep track of current status of Darksend pool
/** Used to keep track of current status of mixing pool
*/
class CDarksendPool
{
private:
mutable CCriticalSection cs_darksend;
std::vector<CDarkSendEntry> entries; // Masternode/clients entries
CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing
int64_t lastTimeChanged; // last time the 'state' changed, in UTC milliseconds
unsigned int state; // should be one of the POOL_STATUS_XXX values
unsigned int entriesCount;
unsigned int lastEntryAccepted;
unsigned int countEntriesAccepted;
std::vector<CTxIn> lockedCoins;
std::string lastMessage;
bool unitTest;
int sessionID;
int sessionUsers; //N Users have said they'll join
bool sessionFoundMasternode; //If we've found a compatible Masternode
std::vector<CTransaction> vecSessionCollateral;
int cachedLastSuccess;
int minBlockSpacing; //required blocks between mixes
CMutableTransaction txCollateral;
int64_t lastNewBlock;
// Keep track of current block index
const CBlockIndex *pCurrentBlockIndex;
std::vector<CAmount> darkSendDenominationsSkipped;
//debugging data
std::string strAutoDenomResult;
public:
enum messages {
ERR_ALREADY_HAVE,
ERR_DENOM,
@ -329,219 +243,177 @@ public:
MSG_ENTRIES_ADDED
};
CMasternode* pSubmittedToMasternode;
int sessionDenom; //Users must submit an denom matching this
int cachedNumBlocks; //used for the overview screen
bool fCreateAutoBackups; //builtin support for automatic backups
mutable CCriticalSection cs_darksend;
CDarksendPool()
{
/* Darksend uses collateral addresses to trust parties entering the pool
to behave themselves. If they don't it takes their money. */
// The current mixing sessions in progress on the network
std::vector<CDarksendQueue> vecDarksendQueue;
// Keep track of the used Masternodes
std::vector<CTxIn> vecMasternodesUsed;
cachedLastSuccess = 0;
cachedNumBlocks = std::numeric_limits<int>::max();
unitTest = false;
txCollateral = CMutableTransaction();
minBlockSpacing = 0;
lastNewBlock = 0;
fCreateAutoBackups = true;
std::vector<CAmount> vecDenominationsSkipped;
std::vector<COutPoint> vecOutPointLocked;
// Mixing uses collateral transactions to trust parties entering the pool
// to behave honestly. If they don't it takes their money.
std::vector<CTransaction> vecSessionCollateral;
std::vector<CDarkSendEntry> vecEntries; // Masternode/clients entries
SetNull();
}
unsigned int nState; // should be one of the POOL_STATE_XXX values
int64_t nLastTimeChanged; // last time the 'state' changed, in UTC milliseconds
/** Process a Darksend message using the Darksend protocol
* \param pfrom
* \param strCommand lower case command string; valid values are:
* Command | Description
* -------- | -----------------
* dsa | Darksend Acceptable
* dsc | Darksend Complete
* dsf | Darksend Final tx
* dsi | Darksend vIn
* dsq | Darksend Queue
* dss | Darksend Signal Final Tx
* dssu | Darksend status update
* dssub | Darksend Subscribe To
* \param vRecv
*/
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
int nCachedLastSuccessBlock;
int nMinBlockSpacing; //required blocks between mixes
const CBlockIndex *pCurrentBlockIndex; // Keep track of current block index
void ClearSkippedDenominations() {
darkSendDenominationsSkipped.clear();
}
int nSessionID;
int nSessionUsers; //N Users have said they'll join
bool fSessionFoundMasternode; //If we've found a compatible Masternode
bool IsDenomSkipped(CAmount denom) {
BOOST_FOREACH(CAmount d, darkSendDenominationsSkipped) {
if (d == denom) {
return true;
}
}
return false;
}
unsigned int nEntriesCount;
bool fLastEntryAccepted;
unsigned int nAcceptedEntriesCount;
void InitDenominations() {
darkSendDenominations.clear();
/* Denominations
std::string strLastMessage;
std::string strAutoDenomResult;
A note about convertability. Within Darksend pools, each denomination
is convertable to another.
bool fUnitTest;
For example:
1DRK+1000 == (.1DRK+100)*10
10DRK+10000 == (1DRK+1000)*10
*/
darkSendDenominations.push_back( (100 * COIN)+100000 );
darkSendDenominations.push_back( (10 * COIN)+10000 );
darkSendDenominations.push_back( (1 * COIN)+1000 );
darkSendDenominations.push_back( (.1 * COIN)+100 );
/* Disabled till we need them
darkSendDenominations.push_back( (.01 * COIN)+10 );
darkSendDenominations.push_back( (.001 * COIN)+1 );
*/
}
CMutableTransaction txMyCollateral; // client side collateral
CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing
void SetMinBlockSpacing(int minBlockSpacingIn){
minBlockSpacing = minBlockSpacingIn;
}
/// Add a clients entry to the pool
bool AddEntry(const std::vector<CTxIn>& vecTxInNew, const CAmount nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& vecTxOutNew, int& nErrorID);
/// Add signature to a txin
bool AddScriptSig(const CTxIn& txin);
void Reset();
void SetNull();
void UnlockCoins();
bool IsNull() const
{
return state == POOL_STATUS_ACCEPTING_ENTRIES && entries.empty();
}
int GetState() const
{
return state;
}
std::string GetStatus();
int GetEntriesCount() const
{
return entries.size();
}
/// Get the time the last entry was accepted (time in UTC milliseconds)
int GetLastEntryAccepted() const
{
return lastEntryAccepted;
}
/// Get the count of the accepted entries
int GetCountEntriesAccepted() const
{
return countEntriesAccepted;
}
// Set the 'state' value, with some logging and capturing when the state changed
void UpdateState(unsigned int newState)
{
if (fMasterNode && (newState == POOL_STATUS_ERROR || newState == POOL_STATUS_SUCCESS)){
LogPrint("privatesend", "CDarksendPool::UpdateState() - Can't set state to ERROR or SUCCESS as a Masternode. \n");
return;
}
LogPrintf("CDarksendPool::UpdateState() == %d | %d \n", state, newState);
if(state != newState){
lastTimeChanged = GetTimeMillis();
if(fMasterNode) {
RelayStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET);
}
}
state = newState;
}
/// Get the maximum number of transactions for the pool
int GetMaxPoolTransactions()
{
return Params().PoolMaxTransactions();
}
/// Do we have enough users to take entries?
bool IsSessionReady(){
return sessionUsers >= GetMaxPoolTransactions();
}
/// Are these outputs compatible with other client in the pool?
bool IsCompatibleWithEntries(std::vector<CTxOut>& vout);
/// Is this amount compatible with other client in the pool?
bool IsCompatibleWithSession(int nDenom, CTransaction txCollateral, int &errorID);
/// Passively run Darksend in the background according to the configuration in settings
bool DoAutomaticDenominating(bool fDryRun=false);
bool PrepareDarksendDenominate();
/// Check for process in Darksend
void Check();
void CheckFinalTransaction();
/// Charge fees to bad actors (Charge clients a fee if they're abusive)
void ChargeFees();
/// Rarely charge fees to pay miners
void ChargeRandomFees();
void CheckTimeout();
void CheckForCompleteQueue();
/// Check to make sure a signature matches an input in the pool
bool SignatureValid(const CScript& newSig, const CTxIn& newVin);
/// Check for process
void CheckPool();
void CheckFinalTransaction();
void CompletedTransaction(bool fError, int nErrorID);
/// Get the denominations for a specific amount of dash.
int GetDenominationsByAmounts(const std::vector<CAmount>& vecAmount);
std::string GetMessageByID(int nMessageID);
/// Get the maximum number of transactions for the pool
int GetMaxPoolTransactions() { return Params().PoolMaxTransactions(); }
/// Are these outputs compatible with other client in the pool?
bool IsOutputsCompatibleWithSessionDenom(const std::vector<CTxOut>& vecTxOut);
/// Is this nDenom compatible with other client in the pool?
bool IsDenomCompatibleWithSession(int nDenom, CTransaction txCollateral, int &nErrorID);
/// If the collateral is valid given by a client
bool IsCollateralValid(const CTransaction& txCollateral);
/// Add a clients entry to the pool
bool AddEntry(const std::vector<CTxIn>& newInput, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, int& errorID);
/// Add signature to a vin
bool AddScriptSig(const CTxIn& newVin);
/// Check that all inputs are signed. (Are all inputs signed?)
bool SignaturesComplete();
/// As a client, send a transaction to a Masternode to start the denomination process
void SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout, CAmount amount);
/// Get Masternode updates about the progress of Darksend
bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, int &errorID, int newSessionID=0);
bool IsSignaturesComplete();
/// Check to make sure a signature matches an input in the pool
bool IsSignatureValid(const CScript& scriptSig, const CTxIn& txin);
/// As a client, check and sign the final transaction
bool SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node);
bool IsDenomSkipped(CAmount nDenomValue) {
return std::find(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue) != vecDenominationsSkipped.end();
}
/// Get the last valid block hash for a given modulus
bool GetLastValidBlockHash(uint256& hash, int mod=1, int nBlockHeight=0);
/// Process a new block
void NewBlock();
void CompletedTransaction(bool error, int errorID);
void ClearLastMessage();
bool IsNull() const { return nState == POOL_STATE_ACCEPTING_ENTRIES && vecEntries.empty(); }
/// Split up large inputs or make fee sized inputs
bool MakeCollateralAmounts();
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem);
/// Create denominations
bool CreateDenominated();
bool CreateDenominated(const CompactTallyItem& tallyItem);
/// Split up large inputs or make fee sized inputs
bool MakeCollateralAmounts();
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem);
bool PrepareDenominate();
/// Get the denominations for a list of outputs (returns a bitshifted integer)
int GetDenominations(const std::vector<CTxOut>& vout, bool fSingleRandomDenom = false);
int GetDenominations(const std::vector<CTxDSOut>& vout);
/// Get Masternode updates about the progress of mixing
bool UpdatePoolStateOnClient(int nStateNew, int nEntriesCountNew, int nAcceptedEntriesCountNew, int &nErrorID, int nSessionIDNew=0);
// Set the 'state' value, with some logging and capturing when the state changed
void SetState(unsigned int nStateNew);
void GetDenominationsToString(int nDenom, std::string& strDenom);
/// As a client, check and sign the final transaction
bool SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* node);
/// Get the denominations for a specific amount of dash.
int GetDenominationsByAmount(CAmount nAmount, int nDenomTarget=0); // is not used anymore?
int GetDenominationsByAmounts(std::vector<CAmount>& vecAmount);
std::string GetMessageByID(int messageID);
//
// Relay Darksend Messages
//
void RelayFinalTransaction(const int sessionID, const CTransaction& txNew);
/// Relay mixing Messages
void RelayFinalTransaction(const CTransaction& txFinal);
void RelaySignaturesAnon(std::vector<CTxIn>& vin);
void RelayInAnon(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout);
void RelayIn(const std::vector<CTxDSIn>& vin, const CAmount& nAmount, const CTransaction& txCollateral, const std::vector<CTxDSOut>& vout);
void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID=MSG_NOERR);
void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID);
void RelayStatus(int nErrorID=MSG_NOERR);
void RelayCompletedTransaction(bool fError, int nErrorID);
public:
CMasternode* pSubmittedToMasternode;
int nSessionDenom; //Users must submit an denom matching this
int nCachedNumBlocks; //used for the overview screen
bool fCreateAutoBackups; //builtin support for automatic backups
CDarksendPool() :
nCachedLastSuccessBlock(0),
nMinBlockSpacing(0),
fUnitTest(false),
txMyCollateral(CMutableTransaction()),
nCachedNumBlocks(std::numeric_limits<int>::max()),
fCreateAutoBackups(true) { SetNull(); }
/** Process a mixing message using the protocol below
* \param pfrom
* \param strCommand lower case command string; valid values are:
* Command | Description
* -------- | -----------------
* dsa | Acceptable
* dsc | Complete
* dsf | Final tx
* dsi | Vector of CTxIn
* dsq | Queue
* dss | Signal Final Tx
* dssu | status update
* \param vRecv
*/
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
void InitDenominations();
void ClearSkippedDenominations() { vecDenominationsSkipped.clear(); }
/// Get the denominations for a list of outputs (returns a bitshifted integer)
int GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fSingleRandomDenom = false);
int GetDenominations(const std::vector<CTxDSOut>& vecTxDSOut);
std::string GetDenominationsToString(int nDenom);
void SetMinBlockSpacing(int nMinBlockSpacingIn) { nMinBlockSpacing = nMinBlockSpacingIn; }
void ResetPool();
void SetNull();
void UnlockCoins();
int GetQueueSize() const { return vecDarksendQueue.size(); }
int GetState() const { return nState; }
std::string GetStatus();
int GetEntriesCount() const { return vecEntries.size(); }
/// Get the count of the accepted entries
int GetCountEntriesAccepted() const { return nAcceptedEntriesCount; }
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(bool fDryRun=false);
void CheckTimeout();
void CheckForCompleteQueue();
/// Do we have enough users to take entries?
bool IsSessionReady(){ return nSessionUsers >= GetMaxPoolTransactions(); }
/// As a client, send a transaction to a Masternode to start the denomination process
void SendDarksendDenominate(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, CAmount nAmount);
/// Process a new block
void NewBlock();
void UpdatedBlockTip(const CBlockIndex *pindex);
};

View File

@ -34,6 +34,8 @@
#include "ui_interface.h"
#include "util.h"
#include "activemasternode.h"
#include "instantx.h"
#include "darksend.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "masternodeman.h"
@ -556,15 +558,15 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-budgetvotemode=<mode>", _("Change automatic finalized budget voting behavior. mode=auto: Vote for only exact finalized budget match to my generated budget. (string, default: auto)"));
strUsage += HelpMessageGroup(_("PrivateSend options:"));
strUsage += HelpMessageOpt("-enableprivatesend=<n>", strprintf(_("Enable use of automated PrivateSend for funds stored in this wallet (0-1, default: %u)"), fEnablePrivateSend));
strUsage += HelpMessageOpt("-privatesendmultisession=<n>", strprintf(_("Enable multiple PrivateSend mixing sessions per block, experimental (0-1, default: %u)"), fPrivateSendMultiSession));
strUsage += HelpMessageOpt("-privatesendrounds=<n>", strprintf(_("Use N separate masternodes to anonymize funds (2-8, default: %u)"), nPrivateSendRounds));
strUsage += HelpMessageOpt("-privatesendamount=<n>", strprintf(_("Keep N DASH anonymized (default: %u)"), nPrivateSendAmount));
strUsage += HelpMessageOpt("-enableprivatesend=<n>", strprintf(_("Enable use of automated PrivateSend for funds stored in this wallet (0-1, default: %u)"), 0));
strUsage += HelpMessageOpt("-privatesendmultisession=<n>", strprintf(_("Enable multiple PrivateSend mixing sessions per block, experimental (0-1, default: %u)"), DEFAULT_PRIVATESEND_MULTISESSION));
strUsage += HelpMessageOpt("-privatesendrounds=<n>", strprintf(_("Use N separate masternodes to anonymize funds (2-8, default: %u)"), DEFAULT_PRIVATESEND_ROUNDS));
strUsage += HelpMessageOpt("-privatesendamount=<n>", strprintf(_("Keep N DASH anonymized (default: %u)"), DEFAULT_PRIVATESEND_AMOUNT));
strUsage += HelpMessageOpt("-liquidityprovider=<n>", strprintf(_("Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (0-100, default: %u, 1=very frequent, high fees, 100=very infrequent, low fees)"), nLiquidityProvider));
strUsage += HelpMessageGroup(_("InstantSend options:"));
strUsage += HelpMessageOpt("-enableinstantsend=<n>", strprintf(_("Enable InstantSend, show confirmations for locked transactions (0-1, default: %u)"), fEnableInstantSend));
strUsage += HelpMessageOpt("-instantsenddepth=<n>", strprintf(_("Show N confirmations for a successfully locked transaction (0-9999, default: %u)"), nInstantSendDepth));
strUsage += HelpMessageOpt("-enableinstantsend=<n>", strprintf(_("Enable InstantSend, show confirmations for locked transactions (0-1, default: %u)"), 1));
strUsage += HelpMessageOpt("-instantsenddepth=<n>", strprintf(_("Show N confirmations for a successfully locked transaction (0-9999, default: %u)"), DEFAULT_INSTANTSEND_DEPTH));
strUsage += HelpMessageOpt("-instantsendnotify=<cmd>", _("Execute command when a wallet IS transaction is successfully locked (%s in cmd is replaced by TxID)"));
@ -1774,23 +1776,28 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
}
if(fMasterNode) {
LogPrintf("IS DARKSEND MASTER NODE\n");
strMasterNodeAddr = GetArg("-masternodeaddr", "");
LogPrintf("MASTERNODE:\n");
activeMasternode.strMasterNodeAddr = GetArg("-masternodeaddr", "");
LogPrintf(" addr %s\n", strMasterNodeAddr);
if(!strMasterNodeAddr.empty()){
CService addrTest = CService(strMasterNodeAddr);
if (!addrTest.IsValid()) {
return InitError("Invalid -masternodeaddr address: " + strMasterNodeAddr);
CService service;
if(activeMasternode.strMasterNodeAddr.empty()) {
if(!GetLocal(service)) {
LogPrintf("Can't detect external address. Please consider using the masternodeaddr configuration option.\n");
}
} else {
service = CService(activeMasternode.strMasterNodeAddr);
if (!service.IsValid()) {
return InitError("Invalid masternodeaddr: " + activeMasternode.strMasterNodeAddr);
}
}
LogPrintf(" service: %s\n", service.ToString());
std::string strMasterNodePrivKey = GetArg("-masternodeprivkey", "");
if(!strMasterNodePrivKey.empty()){
std::string errorMessage;
if(!strMasterNodePrivKey.empty()) {
std::string strErrorMessage;
if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, activeMasternode.keyMasternode, activeMasternode.pubKeyMasternode))
if(!darkSendSigner.GetKeysFromSecret(strMasterNodePrivKey, strErrorMessage, activeMasternode.keyMasternode, activeMasternode.pubKeyMasternode))
return InitError(_("Invalid masternodeprivkey. Please see documenation."));
LogPrintf(" pubKeyMasternode: %s\n", CBitcoinAddress(activeMasternode.pubKeyMasternode.GetID()).ToString());
@ -1825,15 +1832,15 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
nLiquidityProvider = std::min(std::max(nLiquidityProvider, 0), 100);
darkSendPool.SetMinBlockSpacing(nLiquidityProvider * 15);
fEnablePrivateSend = GetBoolArg("-enableprivatesend", fEnablePrivateSend);
fPrivateSendMultiSession = GetBoolArg("-privatesendmultisession", fPrivateSendMultiSession);
nPrivateSendRounds = GetArg("-privatesendrounds", nPrivateSendRounds);
fEnablePrivateSend = GetBoolArg("-enableprivatesend", 0);
fPrivateSendMultiSession = GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION);
nPrivateSendRounds = GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS);
nPrivateSendRounds = std::min(std::max(nPrivateSendRounds, 1), 99999);
nPrivateSendAmount = GetArg("-privatesendamount", nPrivateSendAmount);
nPrivateSendAmount = GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT);
nPrivateSendAmount = std::min(std::max(nPrivateSendAmount, 2), 999999);
fEnableInstantSend = GetBoolArg("-enableinstantsend", fEnableInstantSend);
nInstantSendDepth = GetArg("-instantsenddepth", nInstantSendDepth);
fEnableInstantSend = GetBoolArg("-enableinstantsend", 1);
nInstantSendDepth = GetArg("-instantsenddepth", DEFAULT_INSTANTSEND_DEPTH);
nInstantSendDepth = std::min(std::max(nInstantSendDepth, 0), 60);
//lite mode disables all Masternode and Darksend related functionality

View File

@ -20,33 +20,38 @@
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
using namespace std;
using namespace boost;
extern CWallet* pwalletMain;
bool fEnableInstantSend = true;
int nInstantSendDepth = DEFAULT_INSTANTSEND_DEPTH;
int nCompleteTXLocks;
std::map<uint256, CTransaction> mapTxLockReq;
std::map<uint256, CTransaction> mapTxLockReqRejected;
std::map<uint256, CConsensusVote> mapTxLockVote;
std::map<uint256, CTransactionLock> mapTxLocks;
std::map<COutPoint, uint256> mapLockedInputs;
std::map<uint256, CTransactionLock> mapTxLocks;
std::map<uint256, int64_t> mapUnknownVotes; //track votes with no tx for DOS
int nCompleteTXLocks;
CCriticalSection cs_instantsend;
//txlock - Locks transaction
//
//step 1.) Broadcast intention to lock transaction inputs, "txlreg", CTransaction
//step 2.) Top INSTANTX_SIGNATURES_TOTAL masternodes, open connect to top 1 masternode.
//step 2.) Top INSTANTSEND_SIGNATURES_TOTAL masternodes, open connect to top 1 masternode.
// Send "txvote", CTransaction, Signature, Approve
//step 3.) Top 1 masternode, waits for INSTANTX_SIGNATURES_REQUIRED messages. Upon success, sends "txlock'
//step 3.) Top 1 masternode, waits for INSTANTSEND_SIGNATURES_REQUIRED messages. Upon success, sends "txlock'
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
void ProcessMessageInstantSend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if(fLiteMode) return; //disable all darksend/masternode related functionality
if(fLiteMode) return; // disable all Dash specific functionality
if(!sporkManager.IsSporkActive(SPORK_2_INSTANTX)) return;
if(!masternodeSync.IsBlockchainSynced()) return;
if (strCommand == NetMsgType::IX)
{
//LogPrintf("ProcessMessageInstantX::ix\n");
//LogPrintf("ProcessMessageInstantSend\n");
CDataStream vMsg(vRecv);
CTransaction tx;
vRecv >> tx;
@ -60,13 +65,13 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
// have we seen it already?
if(mapTxLockReq.count(inv.hash) || mapTxLockReqRejected.count(inv.hash)) return;
// is it a valid one?
if(!IsIXTXValid(tx)) return;
if(!IsInstantSendTxValid(tx)) return;
BOOST_FOREACH(const CTxOut o, tx.vout){
BOOST_FOREACH(const CTxOut o, tx.vout) {
// IX supports normal scripts and unspendable scripts (used in DS collateral and Budget collateral).
// TODO: Look into other script types that are normal and can be included
if(!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()){
LogPrintf("ProcessMessageInstantX::ix - Invalid Script %s", tx.ToString());
if(!o.scriptPubKey.IsNormalPaymentScript() && !o.scriptPubKey.IsUnspendable()) {
LogPrintf("ProcessMessageInstantSend -- Invalid Script %s", tx.ToString());
return;
}
}
@ -81,15 +86,14 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
LOCK(cs_main);
fAccepted = AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs);
}
if (fAccepted)
{
if(fAccepted) {
RelayInv(inv);
DoConsensusVote(tx, nBlockHeight);
mapTxLockReq.insert(make_pair(tx.GetHash(), tx));
mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx));
LogPrintf("ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : accepted %s\n",
LogPrintf("ProcessMessageInstantSend -- Transaction Lock Request: %s %s : accepted %s\n",
pfrom->addr.ToString(), pfrom->cleanSubVer,
tx.GetHash().ToString()
);
@ -97,7 +101,7 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
// Masternodes will sometimes propagate votes before the transaction is known to the client.
// If this just happened - update transaction status, try forcing external script notification,
// lock inputs and resolve conflicting locks
if(IsLockedIXTransaction(tx.GetHash())) {
if(IsLockedInstandSendTransaction(tx.GetHash())) {
UpdateLockedTransaction(tx, true);
LockTransactionInputs(tx);
ResolveConflicts(tx);
@ -106,11 +110,11 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
return;
} else {
mapTxLockReqRejected.insert(make_pair(tx.GetHash(), tx));
mapTxLockReqRejected.insert(std::make_pair(tx.GetHash(), tx));
// can we get the conflicting transaction as proof?
LogPrintf("ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : rejected %s\n",
LogPrintf("ProcessMessageInstantSend -- Transaction Lock Request: %s %s : rejected %s\n",
pfrom->addr.ToString(), pfrom->cleanSubVer,
tx.GetHash().ToString()
);
@ -123,39 +127,35 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
}
else if (strCommand == NetMsgType::IXLOCKVOTE) //InstantX Lock Consensus Votes
{
CConsensusVote ctx;
vRecv >> ctx;
CConsensusVote vote;
vRecv >> vote;
CInv inv(MSG_TXLOCK_VOTE, ctx.GetHash());
CInv inv(MSG_TXLOCK_VOTE, vote.GetHash());
pfrom->AddInventoryKnown(inv);
if(mapTxLockVote.count(ctx.GetHash())){
return;
}
if(mapTxLockVote.count(vote.GetHash())) return;
mapTxLockVote.insert(std::make_pair(vote.GetHash(), vote));
mapTxLockVote.insert(make_pair(ctx.GetHash(), ctx));
if(ProcessConsensusVote(pfrom, ctx)){
if(ProcessConsensusVote(pfrom, vote)) {
//Spam/Dos protection
/*
Masternodes will sometimes propagate votes before the transaction is known to the client.
This tracks those messages and allows it at the same rate of the rest of the network, if
a peer violates it, it will simply be ignored
*/
if(!mapTxLockReq.count(ctx.txHash) && !mapTxLockReqRejected.count(ctx.txHash)){
if(!mapUnknownVotes.count(ctx.vinMasternode.prevout.hash)){
mapUnknownVotes[ctx.vinMasternode.prevout.hash] = GetTime()+(60*10);
}
if(!mapTxLockReq.count(vote.txHash) && !mapTxLockReqRejected.count(vote.txHash)) {
if(!mapUnknownVotes.count(vote.vinMasternode.prevout.hash))
mapUnknownVotes[vote.vinMasternode.prevout.hash] = GetTime()+(60*10);
if(mapUnknownVotes[ctx.vinMasternode.prevout.hash] > GetTime() &&
mapUnknownVotes[ctx.vinMasternode.prevout.hash] - GetAverageVoteTime() > 60*10){
LogPrintf("ProcessMessageInstantX::ix - masternode is spamming transaction votes: %s %s\n",
ctx.vinMasternode.ToString(),
ctx.txHash.ToString()
if(mapUnknownVotes[vote.vinMasternode.prevout.hash] > GetTime() &&
mapUnknownVotes[vote.vinMasternode.prevout.hash] - GetAverageVoteTime() > 60*10) {
LogPrintf("ProcessMessageInstantSend -- masternode is spamming transaction votes: %s %s\n",
vote.vinMasternode.ToString(),
vote.txHash.ToString()
);
return;
} else {
mapUnknownVotes[ctx.vinMasternode.prevout.hash] = GetTime()+(60*10);
mapUnknownVotes[vote.vinMasternode.prevout.hash] = GetTime()+(60*10);
}
}
RelayInv(inv);
@ -165,11 +165,12 @@ void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream&
}
}
bool IsIXTXValid(const CTransaction& txCollateral){
bool IsInstantSendTxValid(const CTransaction& txCollateral)
{
if(txCollateral.vout.size() < 1) return false;
if(!CheckFinalTx(txCollateral)) {
LogPrint("instantsend", "IsIXTXValid - Transaction is not final - %s\n", txCollateral.ToString());
LogPrint("instantsend", "IsInstantSendTxValid -- Transaction is not final: txCollateral=%s", txCollateral.ToString());
return false;
}
@ -177,28 +178,27 @@ bool IsIXTXValid(const CTransaction& txCollateral){
int64_t nValueOut = 0;
bool missingTx = false;
BOOST_FOREACH(const CTxOut o, txCollateral.vout)
nValueOut += o.nValue;
BOOST_FOREACH(const CTxOut txout, txCollateral.vout)
nValueOut += txout.nValue;
BOOST_FOREACH(const CTxIn i, txCollateral.vin){
BOOST_FOREACH(const CTxIn txin, txCollateral.vin) {
CTransaction tx2;
uint256 hash;
if(GetTransaction(i.prevout.hash, tx2, Params().GetConsensus(), hash, true)){
if(tx2.vout.size() > i.prevout.n) {
nValueIn += tx2.vout[i.prevout.n].nValue;
}
} else{
if(GetTransaction(txin.prevout.hash, tx2, Params().GetConsensus(), hash, true)) {
if(tx2.vout.size() > txin.prevout.n)
nValueIn += tx2.vout[txin.prevout.n].nValue;
} else {
missingTx = true;
}
}
if(nValueOut > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)*COIN){
LogPrint("instantsend", "IsIXTXValid -- Transaction value too high: nValueOut=%d, txCollateral=%s", nValueOut, txCollateral.ToString());
if(nValueOut > sporkManager.GetSporkValue(SPORK_5_MAX_VALUE)*COIN) {
LogPrint("instantsend", "IsInstantSendTxValid -- Transaction value too high: nValueOut=%d, txCollateral=%s", nValueOut, txCollateral.ToString());
return false;
}
if(missingTx){
LogPrint("instantsend", "IsIXTXValid - Unknown inputs in IX transaction - %s\n", txCollateral.ToString());
if(missingTx) {
LogPrint("instantsend", "IsInstantSendTxValid -- Unknown inputs in IX transaction: txCollateral=%s", txCollateral.ToString());
/*
This happens sometimes for an unknown reason, so we'll return that it's a valid transaction.
If someone submits an invalid transaction it will be rejected by the network anyway and this isn't
@ -208,7 +208,7 @@ bool IsIXTXValid(const CTransaction& txCollateral){
}
if(nValueIn-nValueOut < INSTANTSEND_MIN_FEE) {
LogPrint("instantsend", "IsIXTXValid - did not include enough fees in transaction %d\n%s\n", nValueOut-nValueIn, txCollateral.ToString());
LogPrint("instantsend", "IsInstantSendTxValid -- did not include enough fees in transaction: fees=%d, txCollateral=%s", nValueOut-nValueIn, txCollateral.ToString());
return false;
}
@ -219,11 +219,10 @@ int64_t CreateNewLock(CTransaction tx)
{
int64_t nTxAge = 0;
BOOST_REVERSE_FOREACH(CTxIn i, tx.vin){
nTxAge = GetInputAge(i);
if(nTxAge < 5) //1 less than the "send IX" gui requires, incase of a block propagating the network at the time
{
LogPrintf("CreateNewLock - Transaction not found / too new: %d / %s\n", nTxAge, tx.GetHash().ToString());
BOOST_REVERSE_FOREACH(CTxIn txin, tx.vin) {
nTxAge = GetInputAge(txin);
if(nTxAge < 5) { //1 less than the "send IX" gui requires, incase of a block propagating the network at the time
LogPrintf("CreateNewLock -- Transaction not found / too new: nTxAge=%d, txid=%s\n", nTxAge, tx.GetHash().ToString());
return 0;
}
}
@ -237,22 +236,24 @@ int64_t CreateNewLock(CTransaction tx)
{
LOCK(cs_main);
CBlockIndex* tip = chainActive.Tip();
if(tip) nBlockHeight = tip->nHeight - nTxAge + 4;
else return 0;
if(tip)
nBlockHeight = tip->nHeight - nTxAge + 4;
else
return 0;
}
if (!mapTxLocks.count(tx.GetHash())){
LogPrintf("CreateNewLock - New Transaction Lock %s !\n", tx.GetHash().ToString());
if(!mapTxLocks.count(tx.GetHash())) {
LogPrintf("CreateNewLock -- New Transaction Lock! txid=%s\n", tx.GetHash().ToString());
CTransactionLock newLock;
newLock.nBlockHeight = nBlockHeight;
newLock.nExpiration = GetTime()+(60*60); //locks expire after 60 minutes (24 confirmations)
newLock.nTimeout = GetTime()+(60*5);
newLock.txHash = tx.GetHash();
mapTxLocks.insert(make_pair(tx.GetHash(), newLock));
mapTxLocks.insert(std::make_pair(tx.GetHash(), newLock));
} else {
mapTxLocks[tx.GetHash()].nBlockHeight = nBlockHeight;
LogPrint("instantsend", "CreateNewLock - Transaction Lock Exists %s !\n", tx.GetHash().ToString());
LogPrint("instantsend", "CreateNewLock -- Transaction Lock Exists! txid=%s\n", tx.GetHash().ToString());
}
@ -265,110 +266,110 @@ void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight)
{
if(!fMasterNode) return;
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight, MIN_INSTANTSEND_PROTO_VERSION);
if(n == -1)
{
LogPrint("instantsend", "InstantX::DoConsensusVote - Unknown Masternode %s\n", activeMasternode.vin.ToString());
if(n == -1) {
LogPrint("instantsend", "DoConsensusVote -- Unknown Masternode %s\n", activeMasternode.vin.ToString());
return;
}
if(n > INSTANTX_SIGNATURES_TOTAL)
{
LogPrint("instantsend", "InstantX::DoConsensusVote - Masternode not in the top %d (%d)\n", INSTANTX_SIGNATURES_TOTAL, n);
if(n > INSTANTSEND_SIGNATURES_TOTAL) {
LogPrint("instantsend", "DoConsensusVote -- Masternode not in the top %d (%d)\n", INSTANTSEND_SIGNATURES_TOTAL, n);
return;
}
/*
nBlockHeight calculated from the transaction is the authoritive source
*/
LogPrint("instantsend", "InstantX::DoConsensusVote - In the top %d (%d)\n", INSTANTX_SIGNATURES_TOTAL, n);
LogPrint("instantsend", "DoConsensusVote -- In the top %d (%d)\n", INSTANTSEND_SIGNATURES_TOTAL, n);
CConsensusVote ctx;
ctx.vinMasternode = activeMasternode.vin;
ctx.txHash = tx.GetHash();
ctx.nBlockHeight = nBlockHeight;
if(!ctx.Sign()){
LogPrintf("InstantX::DoConsensusVote - Failed to sign consensus vote\n");
CConsensusVote vote;
vote.vinMasternode = activeMasternode.vin;
vote.txHash = tx.GetHash();
vote.nBlockHeight = nBlockHeight;
if(!vote.Sign()) {
LogPrintf("DoConsensusVote -- Failed to sign consensus vote\n");
return;
}
if(!ctx.SignatureValid()) {
LogPrintf("InstantX::DoConsensusVote - Signature invalid\n");
if(!vote.SignatureValid()) {
LogPrintf("DoConsensusVote -- Signature invalid\n");
return;
}
mapTxLockVote[ctx.GetHash()] = ctx;
{
LOCK(cs_instantsend);
mapTxLockVote[vote.GetHash()] = vote;
}
CInv inv(MSG_TXLOCK_VOTE, ctx.GetHash());
CInv inv(MSG_TXLOCK_VOTE, vote.GetHash());
RelayInv(inv);
}
//received a consensus vote
bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx)
bool ProcessConsensusVote(CNode* pnode, CConsensusVote& vote)
{
int n = mnodeman.GetMasternodeRank(ctx.vinMasternode, ctx.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTSEND_PROTO_VERSION);
CMasternode* pmn = mnodeman.Find(ctx.vinMasternode);
CMasternode* pmn = mnodeman.Find(vote.vinMasternode);
if(pmn != NULL)
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Masternode ADDR %s %d\n", pmn->addr.ToString(), n);
LogPrint("instantsend", "ProcessConsensusVote -- Masternode addr=%s, rank: %d\n", pmn->addr.ToString(), n);
if(n == -1)
{
if(n == -1) {
//can be caused by past versions trying to vote with an invalid protocol
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Unknown Masternode %s\n", ctx.vinMasternode.ToString());
mnodeman.AskForMN(pnode, ctx.vinMasternode);
LogPrint("instantsend", "ProcessConsensusVote -- Unknown Masternode: txin=%s\n", vote.vinMasternode.ToString());
mnodeman.AskForMN(pnode, vote.vinMasternode);
return false;
}
if(n > INSTANTX_SIGNATURES_TOTAL)
{
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Masternode not in the top %d (%d) - %s\n", INSTANTX_SIGNATURES_TOTAL, n, ctx.GetHash().ToString());
if(n > INSTANTSEND_SIGNATURES_TOTAL) {
LogPrint("instantsend", "ProcessConsensusVote -- Masternode not in the top %d (%d): vote hash %s\n", INSTANTSEND_SIGNATURES_TOTAL, n, vote.GetHash().ToString());
return false;
}
if(!ctx.SignatureValid()) {
LogPrintf("InstantX::ProcessConsensusVote - Signature invalid\n");
if(!vote.SignatureValid()) {
LogPrintf("ProcessConsensusVote -- Signature invalid\n");
// don't ban, it could just be a non-synced masternode
mnodeman.AskForMN(pnode, ctx.vinMasternode);
mnodeman.AskForMN(pnode, vote.vinMasternode);
return false;
}
if (!mapTxLocks.count(ctx.txHash)){
LogPrintf("InstantX::ProcessConsensusVote - New Transaction Lock %s !\n", ctx.txHash.ToString());
if (!mapTxLocks.count(vote.txHash)) {
LogPrintf("ProcessConsensusVote -- New Transaction Lock! txid=%s\n", vote.txHash.ToString());
CTransactionLock newLock;
newLock.nBlockHeight = 0;
newLock.nExpiration = GetTime()+(60*60);
newLock.nTimeout = GetTime()+(60*5);
newLock.txHash = ctx.txHash;
mapTxLocks.insert(make_pair(ctx.txHash, newLock));
} else
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Transaction Lock Exists %s !\n", ctx.txHash.ToString());
newLock.txHash = vote.txHash;
mapTxLocks.insert(std::make_pair(vote.txHash, newLock));
} else {
LogPrint("instantsend", "ProcessConsensusVote -- Transaction Lock Exists! txid=%s\n", vote.txHash.ToString());
}
//compile consessus vote
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(ctx.txHash);
if (i != mapTxLocks.end()){
(*i).second.AddSignature(ctx);
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(vote.txHash);
if (i != mapTxLocks.end()) {
(*i).second.AddVote(vote);
int nSignatures = (*i).second.CountSignatures();
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Transaction Lock Votes %d - %s !\n", nSignatures, ctx.GetHash().ToString());
int nSignatures = (*i).second.CountVotes();
LogPrint("instantsend", "ProcessConsensusVote -- Transaction Lock signatures count: %d, vote hash=%s\n", nSignatures, vote.GetHash().ToString());
if(nSignatures >= INSTANTX_SIGNATURES_REQUIRED){
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s !\n", ctx.txHash.ToString());
if(nSignatures >= INSTANTSEND_SIGNATURES_REQUIRED) {
LogPrint("instantsend", "ProcessConsensusVote -- Transaction Lock Is Complete! txid=%s\n", vote.txHash.ToString());
// Masternodes will sometimes propagate votes before the transaction is known to the client,
// will check for conflicting locks and update transaction status on a new vote message
// only after the lock itself has arrived
if(!mapTxLockReq.count(ctx.txHash) && !mapTxLockReqRejected.count(ctx.txHash)) return true;
if(!mapTxLockReq.count(vote.txHash) && !mapTxLockReqRejected.count(vote.txHash)) return true;
if(!FindConflictingLocks(mapTxLockReq[ctx.txHash])) { //?????
if(mapTxLockReq.count(ctx.txHash)) {
UpdateLockedTransaction(mapTxLockReq[ctx.txHash]);
LockTransactionInputs(mapTxLockReq[ctx.txHash]);
} else if(mapTxLockReqRejected.count(ctx.txHash)) {
ResolveConflicts(mapTxLockReqRejected[ctx.txHash]); ///?????
if(!FindConflictingLocks(mapTxLockReq[vote.txHash])) { //?????
if(mapTxLockReq.count(vote.txHash)) {
UpdateLockedTransaction(mapTxLockReq[vote.txHash]);
LockTransactionInputs(mapTxLockReq[vote.txHash]);
} else if(mapTxLockReqRejected.count(vote.txHash)) {
ResolveConflicts(mapTxLockReqRejected[vote.txHash]); ///?????
} else {
LogPrint("instantsend", "InstantX::ProcessConsensusVote - Transaction Lock Request is missing %s ! votes %d\n", ctx.GetHash().ToString(), nSignatures);
LogPrint("instantsend", "ProcessConsensusVote -- Transaction Lock Request is missing! nSignatures=%d, vote hash %s\n", nSignatures, vote.GetHash().ToString());
}
}
}
@ -379,25 +380,25 @@ bool ProcessConsensusVote(CNode* pnode, CConsensusVote& ctx)
return false;
}
void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification) {
void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification)
{
// there should be no conflicting locks
if(FindConflictingLocks(tx)) return;
uint256 txHash = tx.GetHash();
// there must be a successfully verified lock request
if (!mapTxLockReq.count(txHash)) return;
if(!mapTxLockReq.count(txHash)) return;
int nSignatures = GetTransactionLockSignatures(txHash);
#ifdef ENABLE_WALLET
if(pwalletMain && pwalletMain->UpdatedTransaction(txHash)){
if(pwalletMain && pwalletMain->UpdatedTransaction(txHash)) {
// bumping this to update UI
nCompleteTXLocks++;
// a transaction lock must have enough signatures to trigger this notification
if(nSignatures == INSTANTX_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTX_SIGNATURES_REQUIRED)) {
if(nSignatures == INSTANTSEND_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTSEND_SIGNATURES_REQUIRED)) {
// notify an external script once threshold is reached
std::string strCmd = GetArg("-instantsendnotify", "");
if ( !strCmd.empty())
{
if(!strCmd.empty()) {
boost::replace_all(strCmd, "%s", txHash.GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
@ -405,19 +406,16 @@ void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification) {
}
#endif
if(nSignatures == INSTANTX_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTX_SIGNATURES_REQUIRED)) {
if(nSignatures == INSTANTSEND_SIGNATURES_REQUIRED || (fForceNotification && nSignatures > INSTANTSEND_SIGNATURES_REQUIRED))
GetMainSignals().NotifyTransactionLock(tx);
}
}
void LockTransactionInputs(CTransaction& tx) {
if(mapTxLockReq.count(tx.GetHash())){
BOOST_FOREACH(const CTxIn& in, tx.vin){
if(!mapLockedInputs.count(in.prevout)){
mapLockedInputs.insert(make_pair(in.prevout, tx.GetHash()));
}
}
}
if(!mapTxLockReq.count(tx.GetHash())) return;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if(!mapLockedInputs.count(txin.prevout))
mapLockedInputs.insert(std::make_pair(txin.prevout, tx.GetHash()));
}
bool FindConflictingLocks(CTransaction& tx)
@ -429,12 +427,17 @@ bool FindConflictingLocks(CTransaction& tx)
Blocks could have been rejected during this time, which is OK. After they cancel out, the client will
rescan the blocks and find they're acceptable and then take the chain with the most work.
*/
BOOST_FOREACH(const CTxIn& in, tx.vin){
if(mapLockedInputs.count(in.prevout)){
if(mapLockedInputs[in.prevout] != tx.GetHash()){
LogPrintf("InstantX::FindConflictingLocks - found two complete conflicting locks - removing both. %s %s", tx.GetHash().ToString(), mapLockedInputs[in.prevout].ToString());
if(mapTxLocks.count(tx.GetHash())) mapTxLocks[tx.GetHash()].nExpiration = GetTime();
if(mapTxLocks.count(mapLockedInputs[in.prevout])) mapTxLocks[mapLockedInputs[in.prevout]].nExpiration = GetTime();
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
if(mapLockedInputs.count(txin.prevout)) {
if(mapLockedInputs[txin.prevout] != tx.GetHash()) {
LogPrintf("FindConflictingLocks -- found two complete conflicting locks, removing both: txid=%s, txin=%s", tx.GetHash().ToString(), mapLockedInputs[txin.prevout].ToString());
if(mapTxLocks.count(tx.GetHash()))
mapTxLocks[tx.GetHash()].nExpiration = GetTime();
if(mapTxLocks.count(mapLockedInputs[txin.prevout]))
mapTxLocks[mapLockedInputs[txin.prevout]].nExpiration = GetTime();
return true;
}
}
@ -443,14 +446,16 @@ bool FindConflictingLocks(CTransaction& tx)
return false;
}
void ResolveConflicts(CTransaction& tx) {
void ResolveConflicts(CTransaction& tx)
{
// resolve conflicts
if (IsLockedIXTransaction(tx.GetHash()) && !FindConflictingLocks(tx)){ //?????
LogPrintf("ResolveConflicts - Found Existing Complete IX Lock, resolving...\n");
if (IsLockedInstandSendTransaction(tx.GetHash()) && !FindConflictingLocks(tx)) { //?????
LogPrintf("ResolveConflicts -- Found Existing Complete IX Lock, resolving...\n");
//reprocess the last 15 blocks
ReprocessBlocks(15);
if(!mapTxLockReq.count(tx.GetHash())) mapTxLockReq.insert(make_pair(tx.GetHash(), tx)); //?????
if(!mapTxLockReq.count(tx.GetHash()))
mapTxLockReq.insert(std::make_pair(tx.GetHash(), tx)); //?????
}
}
@ -471,23 +476,27 @@ int64_t GetAverageVoteTime()
void CleanTransactionLocksList()
{
LOCK(cs_instantsend);
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.begin();
while(it != mapTxLocks.end()) {
if(GetTime() > it->second.nExpiration){ //keep them for an hour
LogPrintf("Removing old transaction lock %s\n", it->second.txHash.ToString());
CTransactionLock &txLock = it->second;
if(GetTime() > txLock.nExpiration){
LogPrintf("Removing old transaction lock: txid=%s\n", txLock.txHash.ToString());
if(mapTxLockReq.count(it->second.txHash)){
CTransaction& tx = mapTxLockReq[it->second.txHash];
if(mapTxLockReq.count(txLock.txHash)){
CTransaction& tx = mapTxLockReq[txLock.txHash];
BOOST_FOREACH(const CTxIn& in, tx.vin)
mapLockedInputs.erase(in.prevout);
BOOST_FOREACH(const CTxIn& txin, tx.vin)
mapLockedInputs.erase(txin.prevout);
mapTxLockReq.erase(it->second.txHash);
mapTxLockReqRejected.erase(it->second.txHash);
mapTxLockReq.erase(txLock.txHash);
mapTxLockReqRejected.erase(txLock.txHash);
BOOST_FOREACH(CConsensusVote& v, it->second.vecConsensusVotes)
mapTxLockVote.erase(v.GetHash());
BOOST_FOREACH(const CConsensusVote& vote, txLock.vecConsensusVotes)
if(mapTxLockVote.count(vote.GetHash()))
mapTxLockVote.erase(vote.GetHash());
}
mapTxLocks.erase(it++);
@ -497,12 +506,13 @@ void CleanTransactionLocksList()
}
}
bool IsLockedIXTransaction(uint256 txHash) {
bool IsLockedInstandSendTransaction(uint256 txHash)
{
// there must be a successfully verified lock request...
if (!mapTxLockReq.count(txHash)) return false;
// ...and corresponding lock must have enough signatures
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(txHash);
return i != mapTxLocks.end() && (*i).second.CountSignatures() >= INSTANTX_SIGNATURES_REQUIRED;
return i != mapTxLocks.end() && (*i).second.CountVotes() >= INSTANTSEND_SIGNATURES_REQUIRED;
}
int GetTransactionLockSignatures(uint256 txHash)
@ -511,10 +521,8 @@ int GetTransactionLockSignatures(uint256 txHash)
if(!sporkManager.IsSporkActive(SPORK_2_INSTANTX)) return -3;
if(!fEnableInstantSend) return -1;
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(txHash);
if (i != mapTxLocks.end()){
return (*i).second.CountSignatures();
}
std::map<uint256, CTransactionLock>::iterator it = mapTxLocks.find(txHash);
if(it != mapTxLocks.end()) return it->second.CountVotes();
return -1;
}
@ -524,9 +532,7 @@ bool IsTransactionLockTimedOut(uint256 txHash)
if(!fEnableInstantSend) return 0;
std::map<uint256, CTransactionLock>::iterator i = mapTxLocks.find(txHash);
if (i != mapTxLocks.end()){
return GetTime() > (*i).second.nTimeout;
}
if (i != mapTxLocks.end()) return GetTime() > (*i).second.nTimeout;
return false;
}
@ -545,14 +551,13 @@ bool CConsensusVote::SignatureValid()
CMasternode* pmn = mnodeman.Find(vinMasternode);
if(pmn == NULL)
{
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Unknown Masternode %s\n", vinMasternode.ToString());
if(pmn == NULL) {
LogPrintf("CConsensusVote::SignatureValid -- Unknown Masternode: txin=%s\n", vinMasternode.ToString());
return false;
}
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchMasterNodeSignature, strMessage, errorMessage)) {
LogPrintf("InstantX::CConsensusVote::SignatureValid() - Verify message failed\n");
LogPrintf("CConsensusVote::SignatureValid -- VerifyMessage() failed\n");
return false;
}
@ -564,15 +569,14 @@ bool CConsensusVote::Sign()
std::string errorMessage;
std::string strMessage = txHash.ToString().c_str() + boost::lexical_cast<std::string>(nBlockHeight);
//LogPrintf("signing strMessage %s \n", strMessage);
if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, activeMasternode.keyMasternode)) {
LogPrintf("CConsensusVote::Sign() - Sign message failed");
LogPrintf("CConsensusVote::Sign -- SignMessage() failed");
return false;
}
if(!darkSendSigner.VerifyMessage(activeMasternode.pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage)) {
LogPrintf("CConsensusVote::Sign() - Verify message failed");
LogPrintf("CConsensusVote::Sign -- VerifyMessage() failed");
return false;
}
@ -580,27 +584,25 @@ bool CConsensusVote::Sign()
}
bool CTransactionLock::SignaturesValid()
bool CTransactionLock::VotesValid()
{
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
{
int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTX_PROTO_VERSION);
int n = mnodeman.GetMasternodeRank(vote.vinMasternode, vote.nBlockHeight, MIN_INSTANTSEND_PROTO_VERSION);
if(n == -1)
{
LogPrintf("CTransactionLock::SignaturesValid() - Unknown Masternode %s\n", vote.vinMasternode.ToString());
if(n == -1) {
LogPrintf("CTransactionLock::VotesValid -- Unknown Masternode, txin=%s\n", vote.vinMasternode.ToString());
return false;
}
if(n > INSTANTX_SIGNATURES_TOTAL)
{
LogPrintf("CTransactionLock::SignaturesValid() - Masternode not in the top %s\n", INSTANTX_SIGNATURES_TOTAL);
if(n > INSTANTSEND_SIGNATURES_TOTAL) {
LogPrintf("CTransactionLock::VotesValid -- Masternode not in the top %s\n", INSTANTSEND_SIGNATURES_TOTAL);
return false;
}
if(!vote.SignatureValid()){
LogPrintf("CTransactionLock::SignaturesValid() - Signature not valid\n");
if(!vote.SignatureValid()) {
LogPrintf("CTransactionLock::VotesValid -- Signature not valid\n");
return false;
}
}
@ -608,12 +610,12 @@ bool CTransactionLock::SignaturesValid()
return true;
}
void CTransactionLock::AddSignature(CConsensusVote& cv)
void CTransactionLock::AddVote(CConsensusVote& vote)
{
vecConsensusVotes.push_back(cv);
vecConsensusVotes.push_back(vote);
}
int CTransactionLock::CountSignatures()
int CTransactionLock::CountVotes()
{
/*
Only count signatures where the BlockHeight matches the transaction's blockheight.
@ -622,11 +624,10 @@ int CTransactionLock::CountSignatures()
if(nBlockHeight == 0) return -1;
int n = 0;
BOOST_FOREACH(CConsensusVote v, vecConsensusVotes){
if(v.nBlockHeight == nBlockHeight){
n++;
}
}
return n;
int nCount = 0;
BOOST_FOREACH(CConsensusVote vote, vecConsensusVotes)
if(vote.nBlockHeight == nBlockHeight)
nCount++;
return nCount;
}

View File

@ -1,5 +1,4 @@
// Copyright (c) 2009-2012 The Dash Core developers
// Copyright (c) 2009-2016 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
@ -11,7 +10,10 @@
#include "util.h"
#include "base58.h"
#include "main.h"
#include "spork.h"
class CConsensusVote;
class CTransaction;
class CTransactionLock;
/*
At 15 signatures, 1/2 of the masternode network can be owned by
@ -22,37 +24,34 @@
### getting 5 of 10 signatures w/ 1000 nodes of 2900
(1000/2900.0)**5 = 0.004875397277841433
*/
#define INSTANTX_SIGNATURES_REQUIRED 6
#define INSTANTX_SIGNATURES_TOTAL 10
static const int INSTANTSEND_SIGNATURES_REQUIRED = 6;
static const int INSTANTSEND_SIGNATURES_TOTAL = 10;
static const int DEFAULT_INSTANTSEND_DEPTH = 5;
using namespace std;
using namespace boost;
static const int MIN_INSTANTSEND_PROTO_VERSION = 70201;
static const CAmount INSTANTSEND_MIN_FEE = 1 * CENT;
class CConsensusVote;
class CTransaction;
class CTransactionLock;
static const int MIN_INSTANTX_PROTO_VERSION = 70103;
static const CAmount INSTANTSEND_MIN_FEE = 1 * CENT;
extern map<uint256, CTransaction> mapTxLockReq;
extern map<uint256, CTransaction> mapTxLockReqRejected;
extern map<uint256, CConsensusVote> mapTxLockVote;
extern std::map<COutPoint, uint256> mapLockedInputs;
extern bool fEnableInstantSend;
extern int nInstantSendDepth;
extern int nCompleteTXLocks;
extern std::map<uint256, CTransaction> mapTxLockReq;
extern std::map<uint256, CTransaction> mapTxLockReqRejected;
extern std::map<uint256, CConsensusVote> mapTxLockVote;
extern std::map<COutPoint, uint256> mapLockedInputs;
int64_t CreateNewLock(CTransaction tx);
bool IsIXTXValid(const CTransaction& txCollateral);
bool IsInstantSendTxValid(const CTransaction& txCollateral);
void ProcessMessageInstantX(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
void ProcessMessageInstantSend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
//check if we need to vote on this transaction
void DoConsensusVote(CTransaction& tx, int64_t nBlockHeight);
//process consensus vote message
bool ProcessConsensusVote(CNode *pnode, CConsensusVote& ctx);
bool ProcessConsensusVote(CNode *pnode, CConsensusVote& vote);
//update UI and notify external script if any
void UpdateLockedTransaction(CTransaction& tx, bool fForceNotification = false);
@ -69,7 +68,7 @@ void ResolveConflicts(CTransaction& tx);
void CleanTransactionLocksList();
// verify if transaction is currently locked
bool IsLockedIXTransaction(uint256 txHash);
bool IsLockedInstandSendTransaction(uint256 txHash);
// get the actual uber og accepted lock signatures
int GetTransactionLockSignatures(uint256 txHash);
@ -112,9 +111,9 @@ public:
int nExpiration;
int nTimeout;
bool SignaturesValid();
int CountSignatures();
void AddSignature(CConsensusVote& cv);
bool VotesValid();
int CountVotes();
void AddVote(CConsensusVote& vote);
uint256 GetHash()
{

View File

@ -962,7 +962,7 @@ int GetInputAgeIX(uint256 nTXHash, CTxIn& vin)
int nResult = GetInputAge(vin);
if(nResult < 0) return -1;
if (nResult < 6 && IsLockedIXTransaction(nTXHash))
if (nResult < 6 && IsLockedInstandSendTransaction(nTXHash))
return nInstantSendDepth + nResult;
return nResult;
@ -970,7 +970,7 @@ int GetInputAgeIX(uint256 nTXHash, CTxIn& vin)
int GetIXConfirmations(uint256 nTXHash)
{
if (IsLockedIXTransaction(nTXHash))
if (IsLockedInstandSendTransaction(nTXHash))
return nInstantSendDepth;
return 0;
@ -4887,12 +4887,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
if(mapDarksendBroadcastTxes.count(inv.hash)) {
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss.reserve(1000);
ss <<
mapDarksendBroadcastTxes[inv.hash].tx <<
mapDarksendBroadcastTxes[inv.hash].vin <<
mapDarksendBroadcastTxes[inv.hash].vchSig <<
mapDarksendBroadcastTxes[inv.hash].sigTime;
ss << mapDarksendBroadcastTxes[inv.hash];
pfrom->PushMessage(NetMsgType::DSTX, ss);
pushed = true;
}
@ -5401,46 +5396,30 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vector<uint256> vEraseQueue;
CTransaction tx;
//masternode signed transaction
CTxIn vin;
vector<unsigned char> vchSig;
int64_t sigTime;
if(strCommand == NetMsgType::TX) {
vRecv >> tx;
} else if (strCommand == NetMsgType::DSTX) {
//these allow masternodes to publish a limited amount of free transactions
vRecv >> tx >> vin >> vchSig >> sigTime;
CDarksendBroadcastTx dstx;
vRecv >> dstx;
tx = dstx.tx;
CMasternode* pmn = mnodeman.Find(vin);
CMasternode* pmn = mnodeman.Find(dstx.vin);
if(pmn != NULL)
{
if(!pmn->allowFreeTx){
//multiple peers can send us a valid masternode transaction
if(fDebug) LogPrintf("dstx: Masternode sending too many transactions %s\n", tx.GetHash().ToString());
LogPrint("privatesend", "dstx: Masternode sending too many transactions %s\n", tx.GetHash().ToString());
return true;
}
std::string strMessage = tx.GetHash().ToString() + boost::lexical_cast<std::string>(sigTime);
std::string errorMessage = "";
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, errorMessage)){
LogPrintf("dstx: Got bad Masternode transaction signature %s\n", vin.ToString());
//pfrom->Misbehaving(20);
return false;
}
if(!dstx.CheckSignature()) return false;
LogPrintf("dstx: Got Masternode transaction %s\n", tx.GetHash().ToString());
pmn->allowFreeTx = false;
if(!mapDarksendBroadcastTxes.count(tx.GetHash())){
CDarksendBroadcastTx dstx;
dstx.tx = tx;
dstx.vin = vin;
dstx.vchSig = vchSig;
dstx.sigTime = sigTime;
mapDarksendBroadcastTxes.insert(make_pair(tx.GetHash(), dstx));
}
}
@ -5947,7 +5926,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
darkSendPool.ProcessMessage(pfrom, strCommand, vRecv);
mnodeman.ProcessMessage(pfrom, strCommand, vRecv);
mnpayments.ProcessMessage(pfrom, strCommand, vRecv);
ProcessMessageInstantX(pfrom, strCommand, vRecv);
ProcessMessageInstantSend(pfrom, strCommand, vRecv);
sporkManager.ProcessSpork(pfrom, strCommand, vRecv);
masternodeSync.ProcessMessage(pfrom, strCommand, vRecv);
governance.ProcessMessage(pfrom, strCommand, vRecv);

View File

@ -7,6 +7,7 @@
#include "masternode-sync.h"
#include "masternodeman.h"
#include "darksend.h"
#include "activemasternode.h"
#include "util.h"
#include "sync.h"
#include "spork.h"

View File

@ -150,7 +150,7 @@ void CMasternodeSync::GetNextAsset()
RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
uiInterface.NotifyAdditionalDataSyncProgressChanged(1);
//try to activate our masternode if possible
activeMasternode.ManageStatus();
activeMasternode.ManageState();
break;
}
RequestedMasternodeAttempt = 0;
@ -402,7 +402,6 @@ void CMasternodeSync::Process()
// }
// }
if (pnode->nVersion < MSG_GOVERNANCE_PEER_PROTO_VERSION) continue;
// only request once from each peer
if(pnode->HasFulfilledRequest("governance-sync")) continue;

View File

@ -3,7 +3,9 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "consensus/validation.h"
#include "activemasternode.h"
#include "darksend.h"
#include "init.h"
#include "masternode.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
@ -369,7 +371,7 @@ bool CMasternodeBroadcast::Create(std::string strService, std::string strKeyMast
return false;
}
if(!darkSendSigner.SetKey(strKeyMasternode, strErrorMessage, keyMasternodeNew, pubKeyMasternodeNew)) {
if(!darkSendSigner.GetKeysFromSecret(strKeyMasternode, strErrorMessage, keyMasternodeNew, pubKeyMasternodeNew)) {
strErrorMessage = strprintf("Can't find keys for masternode %s, error: %s", strService, strErrorMessage);
LogPrintf("CMasternodeBroadcast::Create -- %s\n", strErrorMessage);
return false;

View File

@ -394,7 +394,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fConnectToMas
{
if (pszDest == NULL) {
// we clean masternode connections in CMasternodeMan::ProcessMasternodeConnections()
// so should be safe to skip this and connect to local Hot MN on CActiveMasternode::ManageStatus()
// so should be safe to skip this and connect to local Hot MN on CActiveMasternode::ManageState()
if (IsLocal(addrConnect) && !fConnectToMasternode)
return NULL;
@ -2077,11 +2077,7 @@ void RelayTransaction(const CTransaction& tx)
ss.reserve(10000);
uint256 hash = tx.GetHash();
if(mapDarksendBroadcastTxes.count(hash)) { // MSG_DSTX
ss <<
mapDarksendBroadcastTxes[hash].tx <<
mapDarksendBroadcastTxes[hash].vin <<
mapDarksendBroadcastTxes[hash].vchSig <<
mapDarksendBroadcastTxes[hash].sigTime;
ss << mapDarksendBroadcastTxes[hash];
} else if(mapTxLockReq.count(hash)) { // MSG_TXLOCK_REQUEST
ss << mapTxLockReq[hash];
} else { // MSG_TX

View File

@ -13,6 +13,7 @@
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
#include "darksend.h"
#include "net.h"
#include "txmempool.h"
#include "ui_interface.h"
@ -74,7 +75,7 @@ int ClientModel::getNumConnections(unsigned int flags) const
QString ClientModel::getMasternodeCountString() const
{
return tr("Total: %1 (PS compatible: %2 / Enabled: %3)").arg(QString::number((int)mnodeman.size()))
.arg(QString::number((int)mnodeman.CountEnabled(MIN_POOL_PEER_PROTO_VERSION)))
.arg(QString::number((int)mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION)))
.arg(QString::number((int)mnodeman.CountEnabled()));
}

View File

@ -2,10 +2,10 @@
#include "ui_darksendconfig.h"
#include "bitcoinunits.h"
#include "darksend.h"
#include "guiconstants.h"
#include "optionsmodel.h"
#include "walletmodel.h"
#include "init.h"
#include <QMessageBox>
#include <QPushButton>

View File

@ -661,7 +661,7 @@ int main(int argc, char *argv[])
#ifdef ENABLE_WALLET
/// 7a. parse masternode.conf
string strErr;
std::string strErr;
if(!masternodeConfig.read(strErr)) {
QMessageBox::critical(0, QObject::tr("Dash Core"),
QObject::tr("Error reading masternode configuration file: %1").arg(strErr.c_str()));

View File

@ -31,6 +31,8 @@
#include <QMessageBox>
#include <QTimer>
extern CWallet* pwalletMain;
OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
QDialog(parent),
ui(new Ui::OptionsDialog),
@ -257,7 +259,7 @@ void OptionsDialog::on_resetButton_clicked()
void OptionsDialog::on_okButton_clicked()
{
mapper->submit();
darkSendPool.cachedNumBlocks = std::numeric_limits<int>::max();
darkSendPool.nCachedNumBlocks = std::numeric_limits<int>::max();
pwalletMain->MarkDirty();
accept();
updateDefaultProxyNets();

View File

@ -13,6 +13,7 @@
#include "guiutil.h"
#include "amount.h"
#include "darksend.h"
#include "init.h"
#include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS
#include "net.h"
@ -119,7 +120,7 @@ void OptionsModel::Init(bool resetSettings)
// PrivateSend
if (!settings.contains("nPrivateSendRounds"))
settings.setValue("nPrivateSendRounds", 2);
settings.setValue("nPrivateSendRounds", DEFAULT_PRIVATESEND_ROUNDS);
if (!SoftSetArg("-privatesendrounds", settings.value("nPrivateSendRounds").toString().toStdString()))
addOverriddenOption("-privatesendrounds");
nPrivateSendRounds = settings.value("nPrivateSendRounds").toInt();
@ -127,7 +128,7 @@ void OptionsModel::Init(bool resetSettings)
if (!settings.contains("nPrivateSendAmount")) {
// for migration from old settings
if (!settings.contains("nAnonymizeDashAmount"))
settings.setValue("nPrivateSendAmount", 1000);
settings.setValue("nPrivateSendAmount", DEFAULT_PRIVATESEND_AMOUNT);
else
settings.setValue("nPrivateSendAmount", settings.value("nAnonymizeDashAmount").toInt());
}
@ -136,7 +137,7 @@ void OptionsModel::Init(bool resetSettings)
nPrivateSendAmount = settings.value("nPrivateSendAmount").toInt();
if (!settings.contains("fPrivateSendMultiSession"))
settings.setValue("fPrivateSendMultiSession", fPrivateSendMultiSession);
settings.setValue("fPrivateSendMultiSession", DEFAULT_PRIVATESEND_MULTISESSION);
if (!SoftSetBoolArg("-privatesendmultisession", settings.value("fPrivateSendMultiSession").toBool()))
addOverriddenOption("-privatesendmultisession");
fPrivateSendMultiSession = settings.value("fPrivateSendMultiSession").toBool();

View File

@ -452,17 +452,17 @@ void OverviewPage::privateSendStatus()
int nBestHeight = clientModel->getNumBlocks();
// We are processing more then 1 block per second, we'll just leave
if(((nBestHeight - darkSendPool.cachedNumBlocks) / (GetTimeMillis() - nLastDSProgressBlockTime + 1) > 1)) return;
if(((nBestHeight - darkSendPool.nCachedNumBlocks) / (GetTimeMillis() - nLastDSProgressBlockTime + 1) > 1)) return;
nLastDSProgressBlockTime = GetTimeMillis();
QString strKeysLeftText(tr("keys left: %1").arg(pwalletMain->nKeysLeftSinceAutoBackup));
if(pwalletMain->nKeysLeftSinceAutoBackup < PS_KEYS_THRESHOLD_WARNING) {
if(pwalletMain->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
strKeysLeftText = "<span style='color:red;'>" + strKeysLeftText + "</span>";
}
ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText);
// Warn user that wallet is running out of keys
if (nWalletBackups > 0 && pwalletMain->nKeysLeftSinceAutoBackup < PS_KEYS_THRESHOLD_WARNING) {
if (nWalletBackups > 0 && pwalletMain->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
QSettings settings;
if(settings.value("fLowKeysWarning").toBool()) {
QString strWarn = tr("Very low number of keys left since last automatic backup!") + "<br><br>" +
@ -521,8 +521,8 @@ void OverviewPage::privateSendStatus()
}
if(!fEnablePrivateSend) {
if(nBestHeight != darkSendPool.cachedNumBlocks) {
darkSendPool.cachedNumBlocks = nBestHeight;
if(nBestHeight != darkSendPool.nCachedNumBlocks) {
darkSendPool.nCachedNumBlocks = nBestHeight;
updatePrivateSendProgress();
}
@ -533,9 +533,9 @@ void OverviewPage::privateSendStatus()
}
// check darksend status and unlock if needed
if(nBestHeight != darkSendPool.cachedNumBlocks) {
if(nBestHeight != darkSendPool.nCachedNumBlocks) {
// Balance and number of transactions might have changed
darkSendPool.cachedNumBlocks = nBestHeight;
darkSendPool.nCachedNumBlocks = nBestHeight;
updatePrivateSendProgress();
}
@ -548,13 +548,11 @@ void OverviewPage::privateSendStatus()
ui->labelPrivateSendLastMessage->setText(s);
if(darkSendPool.sessionDenom == 0){
if(darkSendPool.nSessionDenom == 0){
ui->labelSubmittedDenom->setText(tr("N/A"));
} else {
std::string out;
darkSendPool.GetDenominationsToString(darkSendPool.sessionDenom, out);
QString s2(out.c_str());
ui->labelSubmittedDenom->setText(s2);
QString strDenom(darkSendPool.GetDenominationsToString(darkSendPool.nSessionDenom).c_str());
ui->labelSubmittedDenom->setText(strDenom);
}
}
@ -564,7 +562,7 @@ void OverviewPage::privateSendAuto(){
}
void OverviewPage::privateSendReset(){
darkSendPool.Reset();
darkSendPool.ResetPool();
QMessageBox::warning(this, tr("PrivateSend"),
tr("PrivateSend was successfully reset."),
@ -599,7 +597,7 @@ void OverviewPage::togglePrivateSend(){
if(!ctx.isValid())
{
//unlock was cancelled
darkSendPool.cachedNumBlocks = std::numeric_limits<int>::max();
darkSendPool.nCachedNumBlocks = std::numeric_limits<int>::max();
QMessageBox::warning(this, tr("PrivateSend"),
tr("Wallet is locked and user declined to unlock. Disabling PrivateSend."),
QMessageBox::Ok, QMessageBox::Ok);
@ -611,7 +609,7 @@ void OverviewPage::togglePrivateSend(){
}
fEnablePrivateSend = !fEnablePrivateSend;
darkSendPool.cachedNumBlocks = std::numeric_limits<int>::max();
darkSendPool.nCachedNumBlocks = std::numeric_limits<int>::max();
if(!fEnablePrivateSend){
ui->togglePrivateSend->setText(tr("Start Mixing"));

View File

@ -38,7 +38,7 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
QString strUsingIX = "";
if(signatures >= 0){
if(signatures >= INSTANTX_SIGNATURES_REQUIRED){
if(signatures >= INSTANTSEND_SIGNATURES_REQUIRED){
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0)
return tr("conflicted");
@ -54,11 +54,11 @@ QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
if (nDepth < 0)
return tr("conflicted");
else if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
return tr("%1/offline (InstantSend verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(INSTANTX_SIGNATURES_TOTAL);
return tr("%1/offline (InstantSend verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(INSTANTSEND_SIGNATURES_TOTAL);
else if (nDepth < 6)
return tr("%1/confirmed (InstantSend verification in progress - %2 of %3 signatures )").arg(nDepth).arg(signatures).arg(INSTANTX_SIGNATURES_TOTAL);
return tr("%1/confirmed (InstantSend verification in progress - %2 of %3 signatures )").arg(nDepth).arg(signatures).arg(INSTANTSEND_SIGNATURES_TOTAL);
else
return tr("%1 confirmations (InstantSend verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(INSTANTX_SIGNATURES_TOTAL);
return tr("%1 confirmations (InstantSend verification in progress - %2 of %3 signatures)").arg(nDepth).arg(signatures).arg(INSTANTSEND_SIGNATURES_TOTAL);
} else {
int nDepth = wtx.GetDepthInMainChain();
if (nDepth < 0)

View File

@ -13,6 +13,7 @@
#include "transactiontablemodel.h"
#include "base58.h"
#include "darksend.h"
#include "keystore.h"
#include "main.h"
#include "sync.h"

View File

@ -6,6 +6,7 @@
#include "db.h"
#include "init.h"
#include "activemasternode.h"
#include "darksend.h"
#include "governance.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
@ -234,7 +235,7 @@ UniValue mngovernance(const UniValue& params, bool fHelp)
UniValue statusObj(UniValue::VOBJ);
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
if(!darkSendSigner.GetKeysFromSecret(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
failed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Masternode signing error, could not set key correctly: " + errorMessage));

View File

@ -7,6 +7,7 @@
#include "db.h"
#include "init.h"
#include "activemasternode.h"
#include "darksend.h"
#include "governance.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
@ -51,7 +52,7 @@ UniValue privatesend(const UniValue& params, bool fHelp)
}
if(params[0].get_str() == "reset"){
darkSendPool.Reset();
darkSendPool.ResetPool();
return "Mixing was reset";
}
@ -59,7 +60,7 @@ UniValue privatesend(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("status", darkSendPool.GetStatus()));
obj.push_back(Pair("keys_left", pwalletMain->nKeysLeftSinceAutoBackup));
obj.push_back(Pair("warnings", (pwalletMain->nKeysLeftSinceAutoBackup < PS_KEYS_THRESHOLD_WARNING
obj.push_back(Pair("warnings", (pwalletMain->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING
? "WARNING: keypool is almost depleted!" : "")));
return obj;
}
@ -77,7 +78,7 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp)
UniValue obj(UniValue::VOBJ);
if (darkSendPool.pSubmittedToMasternode)
obj.push_back(Pair("masternode", darkSendPool.pSubmittedToMasternode->addr.ToString()));
obj.push_back(Pair("queue", (int64_t)vecDarksendQueue.size()));
obj.push_back(Pair("queue", darkSendPool.GetQueueSize()));
obj.push_back(Pair("state", darkSendPool.GetState()));
obj.push_back(Pair("entries", darkSendPool.GetEntriesCount()));
obj.push_back(Pair("entries_accepted", darkSendPool.GetCountEntriesAccepted()));
@ -161,12 +162,12 @@ UniValue masternode(const UniValue& params, bool fHelp)
mnodeman.GetNextMasternodeInQueueForPayment(chainActive.Tip()->nHeight, true, nCount);
}
if(params[1].get_str() == "ps") return mnodeman.CountEnabled(MIN_POOL_PEER_PROTO_VERSION);
if(params[1].get_str() == "ps") return mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION);
if(params[1].get_str() == "enabled") return mnodeman.CountEnabled();
if(params[1].get_str() == "qualify") return nCount;
if(params[1].get_str() == "all") return strprintf("Total: %d (PS Compatible: %d / Enabled: %d / Qualify: %d)",
mnodeman.size(),
mnodeman.CountEnabled(MIN_POOL_PEER_PROTO_VERSION),
mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION),
mnodeman.CountEnabled(),
nCount);
}
@ -199,7 +200,7 @@ UniValue masternode(const UniValue& params, bool fHelp)
if (strCommand == "debug")
{
if(activeMasternode.status != ACTIVE_MASTERNODE_INITIAL || !masternodeSync.IsBlockchainSynced())
if(activeMasternode.nState != ACTIVE_MASTERNODE_INITIAL || !masternodeSync.IsBlockchainSynced())
return activeMasternode.GetStatus();
CTxIn vin = CTxIn();
@ -236,9 +237,9 @@ UniValue masternode(const UniValue& params, bool fHelp)
}
}
if(activeMasternode.status != ACTIVE_MASTERNODE_STARTED){
activeMasternode.status = ACTIVE_MASTERNODE_INITIAL; // TODO: consider better way
activeMasternode.ManageStatus();
if(activeMasternode.nState != ACTIVE_MASTERNODE_STARTED){
activeMasternode.nState = ACTIVE_MASTERNODE_INITIAL; // TODO: consider better way
activeMasternode.ManageState();
pwalletMain->Lock();
}

View File

@ -202,7 +202,7 @@ bool CSporkMessage::Sign(std::string strSignKey)
CPubKey pubkey;
std::string errorMessage = "";
if(!darkSendSigner.SetKey(strSignKey, errorMessage, key, pubkey)) {
if(!darkSendSigner.GetKeysFromSecret(strSignKey, errorMessage, key, pubkey)) {
LogPrintf("CSporkMessage::Sign -- ERROR: '%s'\n", errorMessage);
return false;
}

View File

@ -104,13 +104,7 @@ using namespace std;
//Dash only features
bool fMasterNode = false;
string strMasterNodeAddr = "";
bool fLiteMode = false;
bool fEnableInstantSend = true;
int nInstantSendDepth = 5;
int nPrivateSendRounds = 2;
int nPrivateSendAmount = 1000;
int nLiquidityProvider = 0;
/**
nWalletBackups:
1..10 - number of automatic backups to keep
@ -122,10 +116,6 @@ int nWalletBackups = 10;
/** Spork enforcement enabled time */
int64_t enforceMasternodePaymentsTime = 4085657524;
bool fSucessfullyLoaded = false;
bool fEnablePrivateSend = false;
bool fPrivateSendMultiSession = false;
/** All denominations used by darksend */
std::vector<CAmount> darkSendDenominations;
string strBudgetMode = "";
const char * const BITCOIN_CONF_FILENAME = "dash.conf";

View File

@ -34,19 +34,10 @@
extern bool fMasterNode;
extern bool fLiteMode;
extern bool fEnableInstantSend;
extern int nInstantSendDepth;
extern int nPrivateSendRounds;
extern int nPrivateSendAmount;
extern int nLiquidityProvider;
extern int nWalletBackups;
extern bool fEnablePrivateSend;
extern bool fPrivateSendMultiSession;
extern int64_t enforceMasternodePaymentsTime;
extern std::string strMasterNodeAddr;
extern int keysLoaded;
extern bool fSucessfullyLoaded;
extern std::vector<CAmount> darkSendDenominations;
extern std::string strBudgetMode;
static const bool DEFAULT_LOGTIMEMICROS = false;

View File

@ -21,9 +21,6 @@ static const int GETHEADERS_VERSION = 70077;
//! disconnect from peers older than this proto version
static const int MIN_PEER_PROTO_VERSION = 70103;
//! minimum peer version accepted by DarksendPool
static const int MIN_POOL_PEER_PROTO_VERSION = 70201;
//! minimum peer version for masternode budgets
static const int MSG_GOVERNANCE_PEER_PROTO_VERSION = 70201;

View File

@ -82,7 +82,7 @@ std::string COutput::ToString() const
int COutput::Priority() const
{
BOOST_FOREACH(CAmount d, darkSendDenominations)
BOOST_FOREACH(CAmount d, vecPrivateSendDenominations)
if(tx->vout[i].nValue == d) return 10000;
if(tx->vout[i].nValue < 1*COIN) return 20000;
@ -1175,7 +1175,7 @@ bool CWallet::IsDenominated(const CTransaction& tx) const
bool CWallet::IsDenominatedAmount(CAmount nInputAmount) const
{
BOOST_FOREACH(CAmount d, darkSendDenominations)
BOOST_FOREACH(CAmount d, vecPrivateSendDenominations)
if(nInputAmount == d)
return true;
return false;
@ -1896,7 +1896,7 @@ CAmount CWallet::GetAnonymizableBalance() const
BOOST_FOREACH(CompactTallyItem& item, vecTally) {
// try to anonymize all denoms and anything greater than sum of 10 smallest denoms
if(IsDenominatedAmount(item.nAmount) || item.nAmount >= darkSendDenominations.back() * 10)
if(IsDenominatedAmount(item.nAmount) || item.nAmount >= vecPrivateSendDenominations.back() * 10)
nTotal += item.nAmount;
}
@ -2231,7 +2231,7 @@ bool less_then_denom (const COutput& out1, const COutput& out2)
bool found1 = false;
bool found2 = false;
BOOST_FOREACH(CAmount d, darkSendDenominations) // loop through predefined denoms
BOOST_FOREACH(CAmount d, vecPrivateSendDenominations) // loop through predefined denoms
{
if(pcoin1->vout[out1.i].nValue == d) found1 = true;
if(pcoin2->vout[out2.i].nValue == d) found2 = true;
@ -2392,7 +2392,7 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
//if we're doing only denominated, we need to round up to the nearest .1DRK
if(coin_type == ONLY_DENOMINATED) {
// Make outputs by looping through denominations, from large to small
BOOST_FOREACH(CAmount v, darkSendDenominations)
BOOST_FOREACH(CAmount v, vecPrivateSendDenominations)
{
BOOST_FOREACH(const COutput& out, vCoins)
{
@ -2638,7 +2638,7 @@ bool CWallet::SelectCoinsGrouppedByAddresses(std::vector<CompactTallyItem>& vecT
if(fMasterNode && wtx.vout[i].nValue == 1000*COIN) continue;
// ignore outputs that are 10 times smaller then the smallest denomination
// otherwise they will just lead to higher fee / lower priority
if(wtx.vout[i].nValue <= darkSendDenominations.back()/10) continue;
if(wtx.vout[i].nValue <= vecPrivateSendDenominations.back()/10) continue;
// ignore anonymized
if(GetInputPrivateSendRounds(CTxIn(wtx.GetHash(), i)) >= nPrivateSendRounds) continue;
}
@ -3421,7 +3421,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
if (IsLocked())
return _("Error: Wallet locked, unable to create transaction!");
if(darkSendPool.GetState() != POOL_STATUS_ERROR && darkSendPool.GetState() != POOL_STATUS_SUCCESS)
if(darkSendPool.GetState() != POOL_STATE_ERROR && darkSendPool.GetState() != POOL_STATE_SUCCESS)
if(darkSendPool.GetEntriesCount() > 0)
return _("Error: You already have pending entries in the PrivateSend pool");
@ -3438,7 +3438,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
if minRounds >= 0 it means only denominated inputs are going in and coming out
*/
if(minRounds >= 0){
if (!SelectCoinsByDenominations(darkSendPool.sessionDenom, 0.1*COIN, DARKSEND_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds))
if (!SelectCoinsByDenominations(darkSendPool.nSessionDenom, 0.1*COIN, DARKSEND_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds))
return _("Error: Can't select current denominated inputs");
}
@ -3465,13 +3465,13 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
int nStepsMax = 5 + GetRandInt(5);
while(nStep < nStepsMax) {
BOOST_FOREACH(CAmount v, darkSendDenominations){
BOOST_FOREACH(CAmount v, vecPrivateSendDenominations){
// only use the ones that are approved
bool fAccepted = false;
if((darkSendPool.sessionDenom & (1 << 0)) && v == ((100*COIN) +100000)) {fAccepted = true;}
else if((darkSendPool.sessionDenom & (1 << 1)) && v == ((10*COIN) +10000)) {fAccepted = true;}
else if((darkSendPool.sessionDenom & (1 << 2)) && v == ((1*COIN) +1000)) {fAccepted = true;}
else if((darkSendPool.sessionDenom & (1 << 3)) && v == ((.1*COIN) +100)) {fAccepted = true;}
if((darkSendPool.nSessionDenom & (1 << 0)) && v == ((100*COIN) +100000)) {fAccepted = true;}
else if((darkSendPool.nSessionDenom & (1 << 1)) && v == ((10*COIN) +10000)) {fAccepted = true;}
else if((darkSendPool.nSessionDenom & (1 << 2)) && v == ((1*COIN) +1000)) {fAccepted = true;}
else if((darkSendPool.nSessionDenom & (1 << 3)) && v == ((.1*COIN) +100)) {fAccepted = true;}
if(!fAccepted) continue;
// try to add it
@ -3522,7 +3522,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
UnlockCoin(v.prevout);
}
if(darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom) {
if(darkSendPool.GetDenominations(vOut) != darkSendPool.nSessionDenom) {
// unlock used coins on failure
LOCK(cs_wallet);
BOOST_FOREACH(CTxIn v, vCoinsResult)
@ -4261,7 +4261,7 @@ int CMerkleTx::GetDepthInMainChain(const CBlockIndex* &pindexRet, bool enableIX)
}
}
if(enableIX && nResult < 6 && IsLockedIXTransaction(GetHash()))
if(enableIX && nResult < 6 && IsLockedInstandSendTransaction(GetHash()))
return nInstantSendDepth + nResult;
return nResult;