Refac: misc coinjoin refactoring and spelling / grammar fixes (#4304)

* refactor: misc coinjoin refactoring

* fix spelling / grammar recommendations in coinjoin
This commit is contained in:
PastaPastaPasta 2021-07-29 19:01:02 -05:00 committed by GitHub
parent f14e8eeada
commit f65b789f9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 292 additions and 266 deletions

View File

@ -87,7 +87,7 @@ void CCoinJoinClientQueueManager::ProcessMessage(CNode* pfrom, const std::string
// if the queue is ready, submit if we can
if (dsq.fReady) {
for (auto& pair : coinJoinClientManagers) {
for (const auto& pair : coinJoinClientManagers) {
if (pair.second->TrySubmitDenominate(dmn->pdmnState->addr, connman)) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
return;
@ -304,7 +304,7 @@ void CCoinJoinClientSession::UnlockCoins()
vecOutPointLocked.clear();
}
std::string CCoinJoinClientSession::GetStatus(bool fWaitForBlock)
std::string CCoinJoinClientSession::GetStatus(bool fWaitForBlock) const
{
static int nStatusMessageProgress = 0;
nStatusMessageProgress += 10;
@ -350,7 +350,7 @@ std::string CCoinJoinClientManager::GetStatuses()
std::string strStatus;
bool fWaitForBlock = WaitForAnotherBlock();
for (auto& session : deqSessions) {
for (const auto& session : deqSessions) {
strStatus += session.GetStatus(fWaitForBlock) + "; ";
}
return strStatus;
@ -361,7 +361,7 @@ std::string CCoinJoinClientManager::GetSessionDenoms()
LOCK(cs_deqsessions);
std::string strSessionDenoms;
for (auto& session : deqSessions) {
for (const auto& session : deqSessions) {
strSessionDenoms += CCoinJoin::DenominationToString(session.nSessionDenom) + "; ";
}
return strSessionDenoms.empty() ? "N/A" : strSessionDenoms;
@ -636,7 +636,7 @@ bool CCoinJoinClientSession::SignFinalTransaction(const CTransaction& finalTrans
// TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit)
if (!SignSignature(mixingWallet, prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- Unable to sign my own transaction!\n", __func__);
// not sure what to do here, it will timeout...?
// not sure what to do here, it will time out...?
}
sigs.push_back(finalMutableTransaction.vin[nMyInputIndex]);
@ -710,14 +710,14 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
return false;
case -1:
// Automatic backup failed, nothing else we can do until user fixes the issue manually.
// There is no way to bring user attention in daemon mode so we just update status and
// There is no way to bring user attention in daemon mode, so we just update status and
// keep spamming if debug is on.
LogPrint(BCLog::COINJOIN, "CCoinJoinClientManager::CheckAutomaticBackup -- ERROR! Failed to create automatic backup.\n");
strAutoDenomResult = _("ERROR! Failed to create automatic backup") + ", " + _("see debug.log for details.");
return false;
case -2:
// We were able to create automatic backup but keypool was not replenished because wallet is locked.
// There is no way to bring user attention in daemon mode so we just update status and
// There is no way to bring user attention in daemon mode, so we just update status and
// keep spamming if debug is on.
LogPrint(BCLog::COINJOIN, "CCoinJoinClientManager::CheckAutomaticBackup -- WARNING! Failed to create replenish keypool, please unlock your wallet to do so.\n");
strAutoDenomResult = _("WARNING! Failed to replenish keypool, please unlock your wallet to do so.") + ", " + _("see debug.log for details.");
@ -732,7 +732,7 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
StopMixing();
return false;
} else if (mixingWallet.nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_WARNING) {
// Low number of keys left but it's still more or less safe to continue
// Low number of keys left, but it's still more or less safe to continue
LogPrint(BCLog::COINJOIN, "CCoinJoinClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", mixingWallet.nKeysLeftSinceAutoBackup);
strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), mixingWallet.nKeysLeftSinceAutoBackup);
@ -1002,18 +1002,18 @@ CDeterministicMNCPtr CCoinJoinClientManager::GetRandomNotUsedMasternode()
{
auto mnList = deterministicMNManager->GetListAtChainTip();
int nCountEnabled = mnList.GetValidMNsCount();
int nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size();
size_t nCountEnabled = mnList.GetValidMNsCount();
size_t nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size();
LogPrint(BCLog::COINJOIN, "CCoinJoinClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded);
if(nCountNotExcluded < 1) {
if (nCountNotExcluded < 1) {
return nullptr;
}
// fill a vector
std::vector<CDeterministicMNCPtr> vpMasternodesShuffled;
vpMasternodesShuffled.reserve((size_t)nCountEnabled);
mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
vpMasternodesShuffled.reserve(nCountEnabled);
mnList.ForEachMN(true, [&vpMasternodesShuffled](const CDeterministicMNCPtr& dmn) {
vpMasternodesShuffled.emplace_back(dmn);
});
@ -1179,7 +1179,7 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)
{
if (!pendingDsaRequest) return false;
bool fDone = connman.ForNode(pendingDsaRequest.GetAddr(), [&](CNode* pnode) {
bool fDone = connman.ForNode(pendingDsaRequest.GetAddr(), [this, &connman](CNode* pnode) {
LogPrint(BCLog::COINJOIN, "-- processing dsa queue for addr=%s\n", pnode->addr.ToString());
nTimeLastSuccessfulStep = GetTime();
// TODO: this vvvv should be here after new state POOL_STATE_CONNECTING is added and MIN_COINJOIN_PEER_PROTO_VERSION is bumped
@ -1260,7 +1260,7 @@ bool CCoinJoinClientSession::SubmitDenominate(CConnman& connman)
}
}
// more inputs first, for equal input count prefer the one with less rounds
// more inputs first, for equal input count prefer the one with fewer rounds
std::sort(vecInputsByRounds.begin(), vecInputsByRounds.end(), [](const auto& a, const auto& b) {
return a.second > b.second || (a.second == b.second && a.first < b.first);
});
@ -1384,9 +1384,9 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
LOCK2(cs_main, mempool.cs);
LOCK(mixingWallet.cs_wallet);
// NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
// NOTE: We do not allow txes larger than 100 kB, so we have to limit number of inputs here.
// We still want to consume a lot of inputs to avoid creating only smaller denoms though.
// Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
// Knowing that each CTxIn is at least 148 B big, 400 inputs should take 400 x ~148 B = ~60 kB.
// This still leaves more than enough room for another data of typical MakeCollateralAmounts tx.
std::vector<CompactTallyItem> vecTally;
if (!mixingWallet.SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) {
@ -1394,7 +1394,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
return false;
}
// Start from smallest balances first to consume tiny amounts and cleanup UTXO a bit
// Start from the smallest balances first to consume tiny amounts and cleanup UTXO a bit
std::sort(vecTally.begin(), vecTally.end(), [](const CompactTallyItem& a, const CompactTallyItem& b) {
return a.nAmount < b.nAmount;
});
@ -1546,10 +1546,10 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
scriptChange = GetScriptForDestination(vchPubKey.GetID());
reservekey.KeepKey();
// return change
txCollateral.vout.push_back(CTxOut(txout.nValue - CCoinJoin::GetCollateralAmount(), scriptChange));
txCollateral.vout.emplace_back(txout.nValue - CCoinJoin::GetCollateralAmount(), scriptChange);
} else { // txout.nValue < CCoinJoin::GetCollateralAmount() * 2
// create dummy data output only and pay everything as a fee
txCollateral.vout.push_back(CTxOut(0, CScript() << OP_RETURN));
txCollateral.vout.emplace_back(0, CScript() << OP_RETURN);
}
if (!SignSignature(mixingWallet, txout.scriptPubKey, txCollateral, 0, txout.nValue, SIGHASH_ALL)) {
@ -1568,9 +1568,9 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
LOCK2(cs_main, mempool.cs);
LOCK(mixingWallet.cs_wallet);
// NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
// NOTE: We do not allow txes larger than 100 kB, so we have to limit number of inputs here.
// We still want to consume a lot of inputs to avoid creating only smaller denoms though.
// Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
// Knowing that each CTxIn is at least 148 B big, 400 inputs should take 400 x ~148 B = ~60 kB.
// This still leaves more than enough room for another data of typical CreateDenominated tx.
std::vector<CompactTallyItem> vecTally;
if (!mixingWallet.SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) {
@ -1578,7 +1578,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
return false;
}
// Start from largest balances first to speed things up by creating txes with larger/largest denoms included
// Start from the largest balances first to speed things up by creating txes with larger/largest denoms included
std::sort(vecTally.begin(), vecTally.end(), [](const CompactTallyItem& a, const CompactTallyItem& b) {
return a.nAmount > b.nAmount;
});
@ -1713,10 +1713,10 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
auto countPossibleOutputs = [&](CAmount nAmount) -> int {
std::vector<CAmount> vecOutputs;
while (true) {
// Create an potential output
// Create a potential output
vecOutputs.push_back(nAmount);
if (!txBuilder.CouldAddOutputs(vecOutputs) || txBuilder.CountOutputs() + vecOutputs.size() > COINJOIN_DENOM_OUTPUTS_THRESHOLD) {
// If its not possible to add it due to insufficient amount left or total number of outputs exceeds
// If it's not possible to add it due to insufficient amount left or total number of outputs exceeds
// COINJOIN_DENOM_OUTPUTS_THRESHOLD drop the output again and stop trying.
vecOutputs.pop_back();
break;
@ -1735,7 +1735,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
// accurate approximation by many smaller denoms. This is ok because when we get here we
// should have nCoinJoinDenomsGoal of each smaller denom already. Also, without `+1`
// we can end up in a situation when there is already nCoinJoinDenomsHardCap of smaller
// denoms yet we can't mix the remaining nBalanceToDenominate because it's smaller than
// denoms, yet we can't mix the remaining nBalanceToDenominate because it's smaller than
// nDenomValue (and thus denomsToCreateBal == 0), so the target would never get reached
// even when there is enough funds for that.
int denomsToCreateBal = (nBalanceToDenominate / nDenomValue) + 1;
@ -1790,7 +1790,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
return true;
}
void CCoinJoinClientSession::RelayIn(const CCoinJoinEntry& entry, CConnman& connman)
void CCoinJoinClientSession::RelayIn(const CCoinJoinEntry& entry, CConnman& connman) const
{
if (!mixingMasternode) return;
@ -1877,7 +1877,7 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const
void DoCoinJoinMaintenance(CConnman& connman)
{
coinJoinClientQueueManager.DoMaintenance();
for (auto& pair : coinJoinClientManagers) {
for (const auto& pair : coinJoinClientManagers) {
pair.second->DoMaintenance(connman);
}
}

View File

@ -8,6 +8,8 @@
#include <coinjoin/coinjoin-util.h>
#include <coinjoin/coinjoin.h>
#include <utility>
class CDeterministicMN;
typedef std::shared_ptr<const CDeterministicMN> CDeterministicMNCPtr;
@ -43,15 +45,15 @@ public:
{
}
CPendingDsaRequest(const CService& addr_, const CCoinJoinAccept& dsa_) :
addr(addr_),
dsa(dsa_),
CPendingDsaRequest(CService addr_, CCoinJoinAccept dsa_) :
addr(std::move(addr_)),
dsa(std::move(dsa_)),
nTimeCreated(GetTime())
{
}
CService GetAddr() { return addr; }
CCoinJoinAccept GetDSA() { return dsa; }
CService GetAddr() const { return addr; }
CCoinJoinAccept GetDSA() const { return dsa; }
bool IsExpired() const { return GetTime() - nTimeCreated > TIMEOUT; }
friend bool operator==(const CPendingDsaRequest& a, const CPendingDsaRequest& b)
@ -114,12 +116,12 @@ private:
/// As a client, check and sign the final transaction
bool SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman);
void RelayIn(const CCoinJoinEntry& entry, CConnman& connman);
void RelayIn(const CCoinJoinEntry& entry, CConnman& connman) const;
void SetNull();
public:
CCoinJoinClientSession(CWallet& pwallet) :
explicit CCoinJoinClientSession(CWallet& pwallet) :
vecOutPointLocked(),
strLastMessage(),
strAutoDenomResult(),
@ -137,7 +139,7 @@ public:
void ResetPool();
std::string GetStatus(bool fWaitForBlock);
std::string GetStatus(bool fWaitForBlock) const;
bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
@ -169,10 +171,6 @@ public:
class CCoinJoinClientManager
{
private:
CCoinJoinClientManager() = delete;
CCoinJoinClientManager(CCoinJoinClientManager const&) = delete;
CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete;
// Keep track of the used Masternodes
std::vector<COutPoint> vecMasternodesUsed;
@ -183,7 +181,7 @@ private:
bool fMixing{false};
int nCachedLastSuccessBlock;
int nMinBlocksToWait; // how many blocks to wait after one successful mixing tx in non-multisession mode
int nMinBlocksToWait; // how many blocks to wait for after one successful mixing tx in non-multisession mode
std::string strAutoDenomResult;
CWallet& mixingWallet;
@ -200,7 +198,11 @@ public:
int nCachedNumBlocks; // used for the overview screen
bool fCreateAutoBackups; // builtin support for automatic backups
CCoinJoinClientManager(CWallet& wallet) :
CCoinJoinClientManager() = delete;
CCoinJoinClientManager(CCoinJoinClientManager const&) = delete;
CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete;
explicit CCoinJoinClientManager(CWallet& wallet) :
vecMasternodesUsed(),
deqSessions(),
nCachedLastSuccessBlock(0),

View File

@ -20,8 +20,6 @@
#include <validation.h>
#include <version.h>
#include <llmq/quorums_instantsend.h>
#include <univalue.h>
CCoinJoinServer coinJoinServer;
@ -32,208 +30,228 @@ void CCoinJoinServer::ProcessMessage(CNode* pfrom, const std::string& strCommand
if (!masternodeSync.IsBlockchainSynced()) return;
if (strCommand == NetMsgType::DSACCEPT) {
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
return;
}
if (IsSessionReady()) {
// too many users in this session already, reject new ones
LogPrint(BCLog::COINJOIN, "DSACCEPT -- queue is already full!\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_QUEUE_FULL, connman);
return;
}
CCoinJoinAccept dsa;
vRecv >> dsa;
LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CCoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = WITH_LOCK(activeMasternodeInfoCs, return mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint));
if (!dmn) {
PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
return;
}
if (vecSessionCollaterals.empty()) {
{
TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return;
for (const auto& q : vecCoinJoinQueue) {
if (WITH_LOCK(activeMasternodeInfoCs, return q.masternodeOutpoint == activeMasternodeInfo.outpoint)) {
// refuse to create another queue this often
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq is still in queue, refuse to mix\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
return;
}
}
}
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
if (fLogIPs) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d, addr=%s\n", pfrom->GetId(), pfrom->addr.ToString());
} else {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d\n", pfrom->GetId());
}
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
return;
}
}
PoolMessage nMessageID = MSG_NOERR;
bool fResult = nSessionID == 0 ? CreateNewSession(dsa, nMessageID, connman)
: AddUserToExistingSession(dsa, nMessageID);
if (fResult) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- is compatible, please submit!\n");
PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
return;
} else {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- not compatible with existing transactions!\n");
PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
return;
}
ProcessDSACCEPT(pfrom, strCommand, vRecv, connman, enable_bip61);
return;
} else if (strCommand == NetMsgType::DSQUEUE) {
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
ProcessDSQUEUE(pfrom, strCommand, vRecv, connman, enable_bip61);
return;
} else if (strCommand == NetMsgType::DSVIN) {
ProcessDSVIN(pfrom, strCommand, vRecv, connman, enable_bip61);
return;
} else if (strCommand == NetMsgType::DSSIGNFINALTX) {
ProcessDSSIGNFINALTX(pfrom, strCommand, vRecv, connman, enable_bip61);
}
}
void CCoinJoinServer::ProcessDSACCEPT(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61)
{
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
return;
}
PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
return;
}
CCoinJoinQueue dsq;
vRecv >> dsq;
if (IsSessionReady()) {
// too many users in this session already, reject new ones
LogPrint(BCLog::COINJOIN, "DSACCEPT -- queue is already full!\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_QUEUE_FULL, connman);
return;
}
CCoinJoinAccept dsa;
vRecv >> dsa;
LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CCoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = WITH_LOCK(activeMasternodeInfoCs, return mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint));
if (!dmn) {
PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
return;
}
if (vecSessionCollaterals.empty()) {
{
TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return;
// process every dsq only once
for (const auto& q : vecCoinJoinQueue) {
if (q == dsq) {
return;
}
if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
// no way the same mn can send another dsq with the same readiness this soon
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Peer %s is sending WAY too many dsq messages for a masternode with collateral %s\n", pfrom->GetLogString(), dsq.masternodeOutpoint.ToStringShort());
if (WITH_LOCK(activeMasternodeInfoCs, return q.masternodeOutpoint == activeMasternodeInfo.outpoint)) {
// refuse to create another queue this often
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq is still in queue, refuse to mix\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
return;
}
}
} // cs_vecqueue
}
LogPrint(BCLog::COINJOIN, "DSQUEUE -- %s new\n", dsq.ToString());
if (dsq.IsTimeOutOfBounds()) return;
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
if (!dmn) return;
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 10);
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
if (fLogIPs) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d, addr=%s\n", pfrom->GetId(), pfrom->addr.ToString());
} else {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq too recent, must wait: peer=%d\n", pfrom->GetId());
}
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
return;
}
if (!dsq.fReady) {
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, mmetaman.GetDsqCount());
//don't allow a few nodes to dominate the queuing process
if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->pdmnState->addr.ToString());
return;
}
mmetaman.AllowMixing(dmn->proTxHash);
LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return;
vecCoinJoinQueue.push_back(dsq);
dsq.Relay(connman);
}
} else if (strCommand == NetMsgType::DSVIN) {
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSVIN -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
return;
}
//do we have enough users in the current session?
if (!IsSessionReady()) {
LogPrint(BCLog::COINJOIN, "DSVIN -- session not complete!\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_SESSION, connman);
return;
}
CCoinJoinEntry entry;
vRecv >> entry;
LogPrint(BCLog::COINJOIN, "DSVIN -- txCollateral %s", entry.txCollateral->ToString()); /* Continued */
PoolMessage nMessageID = MSG_NOERR;
entry.addr = pfrom->addr;
if (AddEntry(connman, entry, nMessageID)) {
PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
CheckPool(connman);
RelayStatus(STATUS_ACCEPTED, connman);
} else {
PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
}
} else if (strCommand == NetMsgType::DSSIGNFINALTX) {
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
return;
}
std::vector<CTxIn> vecTxIn;
vRecv >> vecTxIn;
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- vecTxIn.size() %s\n", vecTxIn.size());
int nTxInIndex = 0;
int nTxInsCount = (int)vecTxIn.size();
for (const auto& txin : vecTxIn) {
nTxInIndex++;
if (!AddScriptSig(txin)) {
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID);
RelayStatus(STATUS_REJECTED, connman);
return;
}
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- AddScriptSig() %d/%d success\n", nTxInIndex, nTxInsCount);
}
// all is good
CheckPool(connman);
}
PoolMessage nMessageID = MSG_NOERR;
bool fResult = nSessionID == 0 ? CreateNewSession(dsa, nMessageID, connman)
: AddUserToExistingSession(dsa, nMessageID);
if (fResult) {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- is compatible, please submit!\n");
PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
return;
} else {
LogPrint(BCLog::COINJOIN, "DSACCEPT -- not compatible with existing transactions!\n");
PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
return;
}
}
void CCoinJoinServer::ProcessDSQUEUE(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61)
{
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
return;
}
CCoinJoinQueue dsq;
vRecv >> dsq;
{
TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return;
// process every dsq only once
for (const auto& q : vecCoinJoinQueue) {
if (q == dsq) {
return;
}
if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
// no way the same mn can send another dsq with the same readiness this soon
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Peer %s is sending WAY too many dsq messages for a masternode with collateral %s\n", pfrom->GetLogString(), dsq.masternodeOutpoint.ToStringShort());
return;
}
}
} // cs_vecqueue
LogPrint(BCLog::COINJOIN, "DSQUEUE -- %s new\n", dsq.ToString());
if (dsq.IsTimeOutOfBounds()) return;
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
if (!dmn) return;
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
LOCK(cs_main);
Misbehaving(pfrom->GetId(), 10);
return;
}
if (!dsq.fReady) {
int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
LogPrint(BCLog::COINJOIN, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, mmetaman.GetDsqCount());
//don't allow a few nodes to dominate the queuing process
if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->pdmnState->addr.ToString());
return;
}
mmetaman.AllowMixing(dmn->proTxHash);
LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
TRY_LOCK(cs_vecqueue, lockRecv);
if (!lockRecv) return;
vecCoinJoinQueue.push_back(dsq);
dsq.Relay(connman);
}
}
void CCoinJoinServer::ProcessDSVIN(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61)
{
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSVIN -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
return;
}
//do we have enough users in the current session?
if (!IsSessionReady()) {
LogPrint(BCLog::COINJOIN, "DSVIN -- session not complete!\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_SESSION, connman);
return;
}
CCoinJoinEntry entry;
vRecv >> entry;
LogPrint(BCLog::COINJOIN, "DSVIN -- txCollateral %s", entry.txCollateral->ToString()); /* Continued */
PoolMessage nMessageID = MSG_NOERR;
entry.addr = pfrom->addr;
if (AddEntry(connman, entry, nMessageID)) {
PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
CheckPool(connman);
RelayStatus(STATUS_ACCEPTED, connman);
} else {
PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
}
}
void CCoinJoinServer::ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61)
{
if (pfrom->nVersion < MIN_COINJOIN_PEER_PROTO_VERSION) {
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
if (enable_bip61) {
connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
REJECT_OBSOLETE, strprintf(
"Version must be %d or greater", MIN_COINJOIN_PEER_PROTO_VERSION)));
}
return;
}
std::vector<CTxIn> vecTxIn;
vRecv >> vecTxIn;
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- vecTxIn.size() %s\n", vecTxIn.size());
int nTxInIndex = 0;
int nTxInsCount = (int)vecTxIn.size();
for (const auto& txin : vecTxIn) {
nTxInIndex++;
if (!AddScriptSig(txin)) {
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID);
RelayStatus(STATUS_REJECTED, connman);
return;
}
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- AddScriptSig() %d/%d success\n", nTxInIndex, nTxInsCount);
}
// all is good
CheckPool(connman);
}
void CCoinJoinServer::SetNull()
@ -272,7 +290,7 @@ void CCoinJoinServer::CheckPool(CConnman& connman)
return;
}
// If we have all of the signatures, try to compile the transaction
// If we have all the signatures, try to compile the transaction
if (nState == POOL_STATE_SIGNING && IsSignaturesComplete()) {
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckPool -- SIGNING\n");
CommitFinalTransaction(connman);
@ -360,14 +378,14 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
//
// Why bother? CoinJoin uses collateral to ensure abuse to the process is kept to a minimum.
// The submission and signing stages are completely separate. In the cases where
// a client submits a transaction then refused to sign, there must be a cost. Otherwise they
// a client submits a transaction then refused to sign, there must be a cost. Otherwise, they
// would be able to do this over and over again and bring the mixing to a halt.
//
// How does this work? Messages to Masternodes come in via NetMsgType::DSVIN, these require a valid collateral
// transaction for the client to be able to enter the pool. This transaction is kept by the Masternode
// until the transaction is either complete or fails.
//
void CCoinJoinServer::ChargeFees(CConnman& connman)
void CCoinJoinServer::ChargeFees(CConnman& connman) const
{
if (!fMasternodeMode) return;
@ -432,12 +450,12 @@ void CCoinJoinServer::ChargeFees(CConnman& connman)
Collateral Fee Charges:
Being that mixing has "no fees" we need to have some kind of cost associated
with using it to stop abuse. Otherwise it could serve as an attack vector and
with using it to stop abuse. Otherwise, it could serve as an attack vector and
allow endless transaction that would bloat Dash and make it unusable. To
stop these kinds of attacks 1 in 10 successful transactions are charged. This
adds up to a cost of 0.001DRK per transaction on average.
*/
void CCoinJoinServer::ChargeRandomFees(CConnman& connman)
void CCoinJoinServer::ChargeRandomFees(CConnman& connman) const
{
if (!fMasternodeMode) return;
@ -448,7 +466,7 @@ void CCoinJoinServer::ChargeRandomFees(CConnman& connman)
}
}
void CCoinJoinServer::ConsumeCollateral(CConnman& connman, const CTransactionRef& txref)
void CCoinJoinServer::ConsumeCollateral(CConnman& connman, const CTransactionRef& txref) const
{
LOCK(cs_main);
CValidationState validationState;
@ -460,7 +478,7 @@ void CCoinJoinServer::ConsumeCollateral(CConnman& connman, const CTransactionRef
}
}
bool CCoinJoinServer::HasTimedOut()
bool CCoinJoinServer::HasTimedOut() const
{
if (!fMasternodeMode) return false;
@ -510,7 +528,7 @@ void CCoinJoinServer::CheckForCompleteQueue(CConnman& connman)
}
// Check to make sure a given input matches an input in the pool and its scriptSig is valid
bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin)
bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin) const
{
CMutableTransaction txNew;
txNew.vin.clear();
@ -652,7 +670,7 @@ bool CCoinJoinServer::AddScriptSig(const CTxIn& txinNew)
}
// Check to make sure everything is signed
bool CCoinJoinServer::IsSignaturesComplete()
bool CCoinJoinServer::IsSignaturesComplete() const
{
for (const auto& entry : vecEntries) {
for (const auto& txdsin : entry.vecTxDSIn) {
@ -663,7 +681,7 @@ bool CCoinJoinServer::IsSignaturesComplete()
return true;
}
bool CCoinJoinServer::IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet)
bool CCoinJoinServer::IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) const
{
if (!fMasternodeMode) return false;
@ -756,7 +774,7 @@ bool CCoinJoinServer::AddUserToExistingSession(const CCoinJoinAccept& dsa, PoolM
}
// Returns true if either max size has been reached or if the mix timed out and min size was reached
bool CCoinJoinServer::IsSessionReady()
bool CCoinJoinServer::IsSessionReady() const
{
if (nState == POOL_STATE_QUEUE) {
if ((int)vecSessionCollaterals.size() >= CCoinJoin::GetMaxPoolParticipants()) {
@ -792,7 +810,7 @@ void CCoinJoinServer::RelayFinalTransaction(const CTransaction& txFinal, CConnma
}
}
void CCoinJoinServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman)
void CCoinJoinServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman) const
{
if (!pnode) return;
CCoinJoinStatusUpdate psssup(nSessionID, nState, 0, nStatusUpdate, nMessageID);
@ -869,7 +887,7 @@ void CCoinJoinServer::SetState(PoolState nStateNew)
nState = nStateNew;
}
void CCoinJoinServer::DoMaintenance(CConnman& connman)
void CCoinJoinServer::DoMaintenance(CConnman& connman) const
{
if (!fMasternodeMode) return; // only run on masternodes

View File

@ -31,11 +31,11 @@ private:
bool AddScriptSig(const CTxIn& txin);
/// Charge fees to bad actors (Charge clients a fee if they're abusive)
void ChargeFees(CConnman& connman);
void ChargeFees(CConnman& connman) const;
/// Rarely charge fees to pay miners
void ChargeRandomFees(CConnman& connman);
void ChargeRandomFees(CConnman& connman) const;
/// Consume collateral in cases when peer misbehaved
void ConsumeCollateral(CConnman& connman, const CTransactionRef& txref);
void ConsumeCollateral(CConnman& connman, const CTransactionRef& txref) const;
/// Check for process
void CheckPool(CConnman& connman);
@ -44,26 +44,31 @@ private:
void CommitFinalTransaction(CConnman& connman);
/// Is this nDenom and txCollateral acceptable?
bool IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet);
bool IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) const;
bool CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet, CConnman& connman);
bool AddUserToExistingSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet);
/// Do we have enough users to take entries?
bool IsSessionReady();
bool IsSessionReady() const;
/// Check that all inputs are signed. (Are all inputs signed?)
bool IsSignaturesComplete();
bool IsSignaturesComplete() const;
/// Check to make sure a given input matches an input in the pool and its scriptSig is valid
bool IsInputScriptSigValid(const CTxIn& txin);
bool IsInputScriptSigValid(const CTxIn& txin) const;
// Set the 'state' value, with some logging and capturing when the state changed
void SetState(PoolState nStateNew);
/// Relay mixing Messages
void RelayFinalTransaction(const CTransaction& txFinal, CConnman& connman);
void PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman);
void PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman) const;
void RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID = MSG_NOERR);
void RelayCompletedTransaction(PoolMessage nMessageID, CConnman& connman);
void ProcessDSACCEPT(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
void ProcessDSQUEUE(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
void ProcessDSVIN(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
void ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
void SetNull();
public:
@ -73,11 +78,11 @@ public:
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
bool HasTimedOut();
bool HasTimedOut() const;
void CheckTimeout(CConnman& connman);
void CheckForCompleteQueue(CConnman& connman);
void DoMaintenance(CConnman& connman);
void DoMaintenance(CConnman& connman) const;
void GetJsonInfo(UniValue& obj) const;
};

View File

@ -9,7 +9,6 @@
#include <chain.h>
#include <messagesigner.h>
#include <netmessagemaker.h>
#include <script/sign.h>
#include <txmempool.h>
#include <util/system.h>
#include <util/moneystr.h>
@ -119,7 +118,7 @@ bool CCoinJoinBroadcastTx::IsExpired(const CBlockIndex* pindex) const
{
// expire confirmed DSTXes after ~1h since confirmation or chainlocked confirmation
if (nConfirmedHeight == -1 || pindex->nHeight < nConfirmedHeight) return false; // not mined yet
if (pindex->nHeight - nConfirmedHeight > 24) return true; // mined more then an hour ago
if (pindex->nHeight - nConfirmedHeight > 24) return true; // mined more than an hour ago
return llmq::chainLocksHandler->HasChainLock(pindex->nHeight, *pindex->phashBlock);
}
@ -251,7 +250,7 @@ bool CCoinJoinBaseSession::IsValidInOuts(const std::vector<CTxIn>& vin, const st
return false;
}
// IsPayToPublicKeyHash() above already checks for scriptPubKey size,
// no need to double check, hence no usage of ERR_NON_STANDARD_PUBKEY
// no need to double-check, hence no usage of ERR_NON_STANDARD_PUBKEY
return true;
};
@ -292,7 +291,7 @@ bool CCoinJoinBaseSession::IsValidInOuts(const std::vector<CTxIn>& vin, const st
}
// The same size and denom for inputs and outputs ensures their total value is also the same,
// no need to double check. If not, we are doing something wrong, bail out.
// no need to double-check. If not, we are doing something wrong, bail out.
if (nFees != 0) {
LogPrint(BCLog::COINJOIN, "CCoinJoinBaseSession::%s -- ERROR: non-zero fees! fees: %lld\n", __func__, nFees);
nMessageIDRet = ERR_FEES;

View File

@ -11,6 +11,8 @@
#include <timedata.h>
#include <tinyformat.h>
#include <utility>
class CCoinJoin;
class CConnman;
class CBLSPublicKey;
@ -116,9 +118,9 @@ public:
bool fHasSig; // flag to indicate if signed
int nRounds;
CTxDSIn(const CTxIn& txin, const CScript& script, int nRounds) :
CTxDSIn(const CTxIn& txin, CScript script, int nRounds) :
CTxIn(txin),
prevPubKey(script),
prevPubKey(std::move(script)),
fHasSig(false),
nRounds(nRounds)
{
@ -143,9 +145,9 @@ public:
nDenom(0),
txCollateral(CMutableTransaction()){};
CCoinJoinAccept(int nDenom, const CMutableTransaction& txCollateral) :
CCoinJoinAccept(int nDenom, CMutableTransaction txCollateral) :
nDenom(nDenom),
txCollateral(txCollateral){};
txCollateral(std::move(txCollateral)){};
SERIALIZE_METHODS(CCoinJoinAccept, obj)
{
@ -176,9 +178,9 @@ public:
{
}
CCoinJoinEntry(const std::vector<CTxDSIn>& vecTxDSIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral) :
vecTxDSIn(vecTxDSIn),
vecTxOut(vecTxOut),
CCoinJoinEntry(std::vector<CTxDSIn> vecTxDSIn, std::vector<CTxOut> vecTxOut, const CTransaction& txCollateral) :
vecTxDSIn(std::move(vecTxDSIn)),
vecTxOut(std::move(vecTxOut)),
txCollateral(MakeTransactionRef(txCollateral)),
addr(CService())
{
@ -217,7 +219,7 @@ public:
{
}
CCoinJoinQueue(int nDenom, COutPoint outpoint, int64_t nTime, bool fReady) :
CCoinJoinQueue(int nDenom, const COutPoint& outpoint, int64_t nTime, bool fReady) :
nDenom(nDenom),
masternodeOutpoint(outpoint),
nTime(nTime),
@ -288,9 +290,9 @@ public:
{
}
CCoinJoinBroadcastTx(const CTransactionRef& _tx, COutPoint _outpoint, int64_t _sigTime) :
CCoinJoinBroadcastTx(CTransactionRef _tx, const COutPoint& _outpoint, int64_t _sigTime) :
nConfirmedHeight(-1),
tx(_tx),
tx(std::move(_tx)),
masternodeOutpoint(_outpoint),
vchSig(),
sigTime(_sigTime)