privatesend: Implement multiwallet support

With the introduction of better mutliwallet support, privatesend only worked for your first wallet. This commit implements multiwallet for privatesend such that the wallet you start the mixing from is the wallet mixing will occur in.

Signed-off-by: pasta <pasta@dashboost.org>
This commit is contained in:
pasta 2020-07-12 00:52:25 -05:00
parent c240e70e38
commit 8acba46205
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
7 changed files with 135 additions and 88 deletions

View File

@ -32,7 +32,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string&
if (!CheckDiskSpace()) {
ResetPool();
fPrivateSendRunning = false;
StopMixing();
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n");
return;
}
@ -225,6 +225,24 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string&
}
}
bool CPrivateSendClientManager::StartMixing(CWallet* pwallet) {
if (IsMixing()) {
return false;
}
assert(pwallet != nullptr);
mixingWallet = pwallet;
return true;
}
void CPrivateSendClientManager::StopMixing() {
mixingWallet = nullptr;
}
bool CPrivateSendClientManager::IsMixing() const
{
return mixingWallet != nullptr;
}
void CPrivateSendClientSession::ResetPool()
{
txMyCollateral = CMutableTransaction();
@ -261,13 +279,13 @@ void CPrivateSendClientSession::UnlockCoins()
if (!privateSendClient.fEnablePrivateSend) return;
while (true) {
TRY_LOCK(GetWallets()[0]->cs_wallet, lockWallet);
TRY_LOCK(GetMixingWallet()->cs_wallet, lockWallet);
if (!lockWallet) {
MilliSleep(50);
continue;
}
for (const auto& outpoint : vecOutPointLocked)
GetWallets()[0]->UnlockCoin(outpoint);
GetMixingWallet()->UnlockCoin(outpoint);
break;
}
@ -355,6 +373,17 @@ bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector<CDeterminis
return !vecDmnsRet.empty();
}
CWallet* CPrivateSendClientSession::GetMixingWallet() const
{
return privateSendClient.GetMixingWallet();
}
CWallet* CPrivateSendClientManager::GetMixingWallet() const
{
assert(mixingWallet != nullptr);
return mixingWallet;
}
//
// Check session timeouts
//
@ -400,7 +429,7 @@ void CPrivateSendClientManager::CheckTimeout()
CheckQueue();
if (!fEnablePrivateSend || !fPrivateSendRunning) return;
if (!fEnablePrivateSend || !IsMixing()) return;
LOCK(cs_deqsessions);
for (auto& session : deqSessions) {
@ -524,7 +553,7 @@ void CPrivateSendClientSession::ProcessPoolStateUpdate(CPrivateSendStatusUpdate
//
bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
if (fMasternodeMode || pnode == nullptr) return false;
if (!mixingMasternode) return false;
@ -604,7 +633,7 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr
return false;
}
const CKeyStore& keystore = *GetWallets()[0];
const CKeyStore& keystore = *GetMixingWallet();
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Signing my input %i\n", __func__, nMyInputIndex);
// 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)
@ -673,14 +702,14 @@ bool CPrivateSendClientManager::WaitForAnotherBlock()
bool CPrivateSendClientManager::CheckAutomaticBackup()
{
if (!fEnablePrivateSend || !fPrivateSendRunning) return false;
if (!fEnablePrivateSend || !IsMixing()) return false;
switch (nWalletBackups) {
case 0:
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Automatic backups disabled, no mixing available.\n");
strAutoDenomResult = _("Automatic backups disabled") + ", " + _("no mixing available.");
fPrivateSendRunning = false; // stop mixing
GetWallets()[0]->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup"
StopMixing();
GetMixingWallet()->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup"
return false;
case -1:
// Automatic backup failed, nothing else we can do until user fixes the issue manually.
@ -698,24 +727,24 @@ bool CPrivateSendClientManager::CheckAutomaticBackup()
return false;
}
if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) {
if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) {
// We should never get here via mixing itself but probably something else is still actively using keypool
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetWallets()[0]->nKeysLeftSinceAutoBackup);
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetMixingWallet()->nKeysLeftSinceAutoBackup);
strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetMixingWallet()->nKeysLeftSinceAutoBackup);
// It's getting really dangerous, stop mixing
fPrivateSendRunning = false;
StopMixing();
return false;
} else if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
} else if (GetMixingWallet()->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
// Low number of keys left but it's still more or less safe to continue
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetWallets()[0]->nKeysLeftSinceAutoBackup);
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup);
strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetMixingWallet()->nKeysLeftSinceAutoBackup);
if (fCreateAutoBackups) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Trying to create new backup.\n");
std::string warningString;
std::string errorString;
if (!GetWallets()[0]->AutoBackupWallet("", warningString, errorString)) {
if (!GetMixingWallet()->AutoBackupWallet("", warningString, errorString)) {
if (!warningString.empty()) {
// There were some issues saving backup but yet more or less safe to continue
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", warningString);
@ -733,7 +762,7 @@ bool CPrivateSendClientManager::CheckAutomaticBackup()
}
}
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetMixingWallet()->nKeysLeftSinceAutoBackup);
return true;
}
@ -751,15 +780,15 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
return false;
}
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
CAmount nBalanceNeedsAnonymized;
{
LOCK2(cs_main, mempool.cs);
LOCK(GetWallets()[0]->cs_wallet);
LOCK(GetMixingWallet()->cs_wallet);
if (!fDryRun && GetWallets()[0]->IsLocked(true)) {
if (!fDryRun && GetMixingWallet()->IsLocked(true)) {
strAutoDenomResult = _("Wallet is locked.");
return false;
}
@ -783,7 +812,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
}
// check if there is anything left to do
CAmount nBalanceAnonymized = GetWallets()[0]->GetAnonymizedBalance();
CAmount nBalanceAnonymized = GetMixingWallet()->GetAnonymizedBalance();
nBalanceNeedsAnonymized = privateSendClient.nPrivateSendAmount*COIN - nBalanceAnonymized;
if (nBalanceNeedsAnonymized < 0) {
@ -795,13 +824,13 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
CAmount nValueMin = CPrivateSend::GetSmallestDenomination();
// if there are no confirmed DS collateral inputs yet
if (!GetWallets()[0]->HasCollateralInputs()) {
if (!GetMixingWallet()->HasCollateralInputs()) {
// should have some additional amount for them
nValueMin += CPrivateSend::GetMaxCollateralAmount();
}
// including denoms but applying some restrictions
CAmount nBalanceAnonymizable = GetWallets()[0]->GetAnonymizableBalance();
CAmount nBalanceAnonymizable = GetMixingWallet()->GetAnonymizableBalance();
// mixable balance is way too small
if (nBalanceAnonymizable < nValueMin) {
@ -811,10 +840,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
}
// excluding denoms
CAmount nBalanceAnonimizableNonDenom = GetWallets()[0]->GetAnonymizableBalance(true);
CAmount nBalanceAnonimizableNonDenom = GetMixingWallet()->GetAnonymizableBalance(true);
// denoms
CAmount nBalanceDenominatedConf = GetWallets()[0]->GetDenominatedBalance();
CAmount nBalanceDenominatedUnconf = GetWallets()[0]->GetDenominatedBalance(true);
CAmount nBalanceDenominatedConf = GetMixingWallet()->GetDenominatedBalance();
CAmount nBalanceDenominatedUnconf = GetMixingWallet()->GetDenominatedBalance(true);
CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf;
CAmount nBalanceToDenominate = privateSendClient.nPrivateSendAmount * COIN - nBalanceDenominated;
@ -863,8 +892,8 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
}
//check if we have the collateral sized inputs
if (!GetWallets()[0]->HasCollateralInputs()) {
return !GetWallets()[0]->HasCollateralInputs(false) && MakeCollateralAmounts(connman);
if (!GetMixingWallet()->HasCollateralInputs()) {
return !GetMixingWallet()->HasCollateralInputs(false) && MakeCollateralAmounts(connman);
}
if (nSessionID) {
@ -888,14 +917,14 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
//check our collateral and create new if needed
std::string strReason;
if (txMyCollateral == CMutableTransaction()) {
if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) {
if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error:%s\n", strReason);
return false;
}
} else {
if (!CPrivateSend::IsCollateralValid(txMyCollateral)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- invalid collateral, recreating...\n");
if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) {
if (!GetMixingWallet()->CreateCollateralTransaction(txMyCollateral, strReason)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error: %s\n", strReason);
return false;
}
@ -903,10 +932,10 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
}
// lock the funds we're going to use for our collateral
for (const auto& txin : txMyCollateral.vin) {
GetWallets()[0]->LockCoin(txin.prevout);
GetMixingWallet()->LockCoin(txin.prevout);
vecOutPointLocked.push_back(txin.prevout);
}
} // LOCK2(cs_main, GetWallets()[0]->cs_wallet);
} // LOCK2(cs_main, GetMixingWallet()->cs_wallet);
// Always attempt to join an existing queue
if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) {
@ -923,14 +952,14 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool
bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool fDryRun)
{
if (fMasternodeMode) return false; // no client-side mixing on masternodes
if (!fEnablePrivateSend || !fPrivateSendRunning) return false;
if (!fEnablePrivateSend || !IsMixing()) return false;
if (!masternodeSync.IsBlockchainSynced()) {
strAutoDenomResult = _("Can't mix while sync in progress.");
return false;
}
if (!fDryRun && GetWallets()[0]->IsLocked(true)) {
if (!fDryRun && GetMixingWallet()->IsLocked(true)) {
strAutoDenomResult = _("Wallet is locked.");
return false;
}
@ -1013,7 +1042,7 @@ CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode()
bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
auto mnList = deterministicMNManager->GetListAtChainTip();
@ -1042,7 +1071,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize
std::vector<std::pair<CTxDSIn, CTxOut> > vecPSInOutPairsTmp;
// Try to match their denominations if possible, select exact number of denominations
if (!GetWallets()[0]->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) {
if (!GetMixingWallet()->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CPrivateSend::DenominationToString(dsq.nDenom));
continue;
}
@ -1072,7 +1101,7 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize
bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
if (nBalanceNeedsAnonymized <= 0) return false;
int nTries = 0;
@ -1081,7 +1110,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, C
// find available denominated amounts
std::set<CAmount> setAmounts;
if (!GetWallets()[0]->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) {
if (!GetMixingWallet()->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) {
// this should never happen
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't mix: no compatible inputs found!\n");
strAutoDenomResult = _("Can't mix: no compatible inputs found!");
@ -1187,7 +1216,7 @@ void CPrivateSendClientManager::ProcessPendingDsaRequest(CConnman& connman)
bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman)
{
LOCK2(cs_main, mempool.cs);
LOCK(GetWallets()[0]->cs_wallet);
LOCK(GetMixingWallet()->cs_wallet);
std::string strError;
std::vector<std::pair<CTxDSIn, CTxOut> > vecPSInOutPairs, vecPSInOutPairsTmp;
@ -1238,9 +1267,9 @@ bool CPrivateSendClientSession::SubmitDenominate(CConnman& connman)
bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
if (GetWallets()[0]->IsLocked(true)) {
if (GetMixingWallet()->IsLocked(true)) {
strErrorRet = "Wallet locked, unable to create transaction!";
return false;
}
@ -1252,7 +1281,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::
vecPSInOutPairsRet.clear();
bool fSelected = GetWallets()[0]->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet);
bool fSelected = GetMixingWallet()->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet);
if (!fSelected) {
strErrorRet = "Can't select current denominated inputs";
return false;
@ -1264,7 +1293,7 @@ bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::
bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet, bool fDryRun)
{
AssertLockHeld(cs_main);
AssertLockHeld(GetWallets()[0]->cs_wallet);
AssertLockHeld(GetMixingWallet()->cs_wallet);
if (!CPrivateSend::IsValidDenomination(nSessionDenom)) {
strErrorRet = "Incorrect session denom";
@ -1295,7 +1324,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds
++nSteps;
continue;
}
scriptDenom = keyHolderStorage.AddKey(GetWallets()[0]);
scriptDenom = keyHolderStorage.AddKey(GetMixingWallet());
}
vecPSInOutPairsRet.emplace_back(pair.first, CTxOut(nDenomAmount, scriptDenom));
// step is complete
@ -1313,7 +1342,7 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds
}
for (const auto& pair : vecPSInOutPairsRet) {
GetWallets()[0]->LockCoin(pair.first.prevout);
GetMixingWallet()->LockCoin(pair.first.prevout);
vecOutPointLocked.push_back(pair.first.prevout);
}
@ -1323,17 +1352,17 @@ bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds
// Create collaterals by looping through inputs grouped by addresses
bool CPrivateSendClientSession::MakeCollateralAmounts(CConnman& connman)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
LOCK2(cs_main, mempool.cs);
LOCK(GetWallets()[0]->cs_wallet);
LOCK(GetMixingWallet()->cs_wallet);
// NOTE: We do not allow txes larger than 100kB, 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.
// This still leaves more than enough room for another data of typical MakeCollateralAmounts tx.
std::vector<CompactTallyItem> vecTally;
if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) {
if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
return false;
}
@ -1365,9 +1394,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
{
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
AssertLockHeld(GetWallets()[0]->cs_wallet);
AssertLockHeld(GetMixingWallet()->cs_wallet);
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
// Skip way too tiny amounts
if (tallyItem.nAmount < CPrivateSend::GetCollateralAmount()) {
@ -1391,9 +1420,9 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
std::vector<CRecipient> vecSend;
// make our collateral address
CReserveKey reservekeyCollateral(GetWallets()[0]);
CReserveKey reservekeyCollateral(GetMixingWallet());
// make our change address
CReserveKey reservekeyChange(GetWallets()[0]);
CReserveKey reservekeyChange(GetMixingWallet());
CScript scriptCollateral;
CPubKey vchPubKey;
@ -1422,7 +1451,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
coinControl.Select(outpoint);
}
bool fSuccess = GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange,
bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange,
nFeeRet, nChangePosRet, strFail, coinControl);
if (!fSuccess) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ONLY_NONDENOMINATED: %s\n", strFail);
@ -1430,7 +1459,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
if (fTryDenominated) {
// Try to also use denominated coins (we can't mix denominated without collaterals anyway).
coinControl.nCoinType = CoinType::ALL_COINS;
if (!GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange,
if (!GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange,
nFeeRet, nChangePosRet, strFail, coinControl)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ALL_COINS Error: %s\n", strFail);
reservekeyCollateral.ReturnKey();
@ -1449,7 +1478,7 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
// use the same nCachedLastSuccessBlock as for DS mixing to prevent race
CValidationState state;
if (!GetWallets()[0]->CommitTransaction(wtx, reservekeyChange, &connman, state)) {
if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason());
return false;
}
@ -1462,17 +1491,17 @@ bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& ta
// Create denominations by looping through inputs grouped by addresses
bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, CConnman& connman)
{
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
LOCK2(cs_main, mempool.cs);
LOCK(GetWallets()[0]->cs_wallet);
LOCK(GetMixingWallet()->cs_wallet);
// NOTE: We do not allow txes larger than 100kB, 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.
// This still leaves more than enough room for another data of typical CreateDenominated tx.
std::vector<CompactTallyItem> vecTally;
if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) {
if (!GetMixingWallet()->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
return false;
}
@ -1482,7 +1511,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
return a.nAmount > b.nAmount;
});
bool fCreateMixingCollaterals = !GetWallets()[0]->HasCollateralInputs();
bool fCreateMixingCollaterals = !GetMixingWallet()->HasCollateralInputs();
for (const auto& item : vecTally) {
if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals, connman)) continue;
@ -1498,9 +1527,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
{
AssertLockHeld(cs_main);
AssertLockHeld(mempool.cs);
AssertLockHeld(GetWallets()[0]->cs_wallet);
AssertLockHeld(GetMixingWallet()->cs_wallet);
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.fPrivateSendRunning) return false;
if (!privateSendClient.fEnablePrivateSend || !privateSendClient.IsMixing()) return false;
std::vector<CRecipient> vecSend;
CKeyHolderStorage keyHolderStorageDenom;
@ -1520,7 +1549,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
// ****** Add an output for mixing collaterals ************ /
if (fCreateMixingCollaterals) {
CScript scriptCollateral = keyHolderStorageDenom.AddKey(GetWallets()[0]);
CScript scriptCollateral = keyHolderStorageDenom.AddKey(GetMixingWallet());
vecSend.push_back((CRecipient){scriptCollateral, CPrivateSend::GetMaxCollateralAmount(), false});
nValueLeft -= CPrivateSend::GetMaxCollateralAmount() + nOutputFee;
}
@ -1533,7 +1562,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
std::map<CAmount, int> mapDenomCount;
for (auto nDenomValue : vecStandardDenoms) {
mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, GetWallets()[0]->CountInputsWithAmount(nDenomValue)));
mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, GetMixingWallet()->CountInputsWithAmount(nDenomValue)));
}
// Will generate outputs for the createdenoms up to privatesendmaxdenoms per denom
@ -1571,7 +1600,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
// add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal
while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClient.nPrivateSendDenomsGoal) {
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]);
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet());
vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false});
@ -1635,7 +1664,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
// Never go above the cap unless it's the largest denom
if (nDenomValue != nLargestDenomValue && it->second >= privateSendClient.nPrivateSendDenomsHardCap) break;
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetWallets()[0]);
CScript scriptDenom = keyHolderStorageDenom.AddKey(GetMixingWallet());
vecSend.push_back((CRecipient) {scriptDenom, nDenomValue, false});
// increment outputs and subtract denomination amount
@ -1681,9 +1710,9 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
int nChangePosRet = -1;
std::string strFail = "";
// make our change address
CReserveKey reservekeyChange(GetWallets()[0]);
CReserveKey reservekeyChange(GetMixingWallet());
bool fSuccess = GetWallets()[0]->CreateTransaction(vecSend, wtx, reservekeyChange,
bool fSuccess = GetMixingWallet()->CreateTransaction(vecSend, wtx, reservekeyChange,
nFeeRet, nChangePosRet, strFail, coinControl);
if (!fSuccess) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- Error: %s\n", strFail);
@ -1694,7 +1723,7 @@ bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate,
keyHolderStorageDenom.KeepAll();
CValidationState state;
if (!GetWallets()[0]->CommitTransaction(wtx, reservekeyChange, &connman, state)) {
if (!GetMixingWallet()->CommitTransaction(wtx, reservekeyChange, &connman, state)) {
LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- CommitTransaction failed! Reason given: %s\n", state.GetRejectReason());
return false;
}
@ -1770,7 +1799,7 @@ void CPrivateSendClientManager::GetJsonInfo(UniValue& obj) const
obj.clear();
obj.setObject();
obj.pushKV("enabled", fEnablePrivateSend);
obj.pushKV("running", fPrivateSendRunning);
obj.pushKV("running", IsMixing());
obj.pushKV("multisession", fPrivateSendMultiSession);
obj.pushKV("max_sessions", nPrivateSendSessions);
obj.pushKV("max_rounds", nPrivateSendRounds);

View File

@ -163,6 +163,7 @@ public:
std::string GetStatus(bool fWaitForBlock);
bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
CWallet* GetMixingWallet() const;
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);
@ -193,6 +194,8 @@ private:
int nMinBlocksToWait; // how many blocks to wait after one successful mixing tx in non-multisession mode
std::string strAutoDenomResult;
CWallet* mixingWallet;
// Keep track of current block height
int nCachedBlockHeight;
@ -208,7 +211,6 @@ public:
int nPrivateSendDenomsGoal;
int nPrivateSendDenomsHardCap;
bool fEnablePrivateSend;
bool fPrivateSendRunning;
bool fPrivateSendMultiSession;
int nCachedNumBlocks; //used for the overview screen
@ -226,15 +228,20 @@ public:
nPrivateSendDenomsGoal(DEFAULT_PRIVATESEND_DENOMS_GOAL),
nPrivateSendDenomsHardCap(DEFAULT_PRIVATESEND_DENOMS_HARDCAP),
fEnablePrivateSend(false),
fPrivateSendRunning(false),
fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION),
nCachedNumBlocks(std::numeric_limits<int>::max()),
fCreateAutoBackups(true)
fCreateAutoBackups(true),
mixingWallet(nullptr)
{
}
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
bool StartMixing(CWallet* pwallet);
void StopMixing();
bool IsMixing() const;
void ResetPool();
std::string GetStatuses();
@ -242,6 +249,8 @@ public:
bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const;
CWallet* GetMixingWallet() const;
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);

View File

@ -1049,7 +1049,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVer
// Disabling macOS App Nap on initial sync, disk, reindex operations and mixing.
bool disableAppNap = !masternodeSync.IsSynced();
#ifdef ENABLE_WALLET
disableAppNap |= privateSendClient.fPrivateSendRunning;
disableAppNap |= privateSendClient.IsMixing();
#endif // ENABLE_WALLET
if (disableAppNap) {
m_app_nap_inhibitor->disableAppNap();

View File

@ -181,7 +181,7 @@ OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent)
ui->labelPrivateSendEnabled->setToolTip(tr("Automatic backups are disabled, no mixing available!"));
}
} else {
if(!privateSendClient.fPrivateSendRunning){
if(!privateSendClient.IsMixing()){
ui->togglePrivateSend->setText(tr("Start Mixing"));
} else {
ui->togglePrivateSend->setText(tr("Stop Mixing"));
@ -500,7 +500,7 @@ void OverviewPage::privateSendStatus(bool fForce)
}
ui->labelPrivateSendEnabled->setToolTip(strKeysLeftText);
if (!privateSendClient.fPrivateSendRunning) {
if (!privateSendClient.IsMixing()) {
if (nBestHeight != privateSendClient.nCachedNumBlocks) {
privateSendClient.nCachedNumBlocks = nBestHeight;
updatePrivateSendProgress();
@ -557,7 +557,7 @@ void OverviewPage::privateSendStatus(bool fForce)
}
}
QString strEnabled = privateSendClient.fPrivateSendRunning ? tr("Enabled") : tr("Disabled");
QString strEnabled = privateSendClient.IsMixing() ? tr("Enabled") : tr("Disabled");
// Show how many keys left in advanced PS UI mode only
if(fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText;
ui->labelPrivateSendEnabled->setText(strEnabled);
@ -600,7 +600,7 @@ void OverviewPage::togglePrivateSend(){
QMessageBox::Ok, QMessageBox::Ok);
settings.setValue("hasMixed", "hasMixed");
}
if(!privateSendClient.fPrivateSendRunning){
if(!privateSendClient.IsMixing()){
const CAmount nMinAmount = CPrivateSend::GetSmallestDenomination() + CPrivateSend::GetMaxCollateralAmount();
if(currentBalance < nMinAmount){
QString strMinAmount(BitcoinUnits::formatWithUnit(nDisplayUnit, nMinAmount));
@ -628,14 +628,15 @@ void OverviewPage::togglePrivateSend(){
}
privateSendClient.fPrivateSendRunning = !privateSendClient.fPrivateSendRunning;
privateSendClient.nCachedNumBlocks = std::numeric_limits<int>::max();
if(!privateSendClient.fPrivateSendRunning){
if (privateSendClient.IsMixing()) {
ui->togglePrivateSend->setText(tr("Start Mixing"));
privateSendClient.ResetPool();
privateSendClient.StopMixing();
} else {
ui->togglePrivateSend->setText(tr("Stop Mixing"));
privateSendClient.StartMixing(walletModel->getWallet());
}
}
@ -663,5 +664,5 @@ void OverviewPage::DisablePrivateSendCompletely() {
if (nWalletBackups <= 0) {
ui->labelPrivateSendEnabled->setText("<span style='" + GUIUtil::getThemedStyleQString(GUIUtil::ThemedStyle::TS_ERROR) + "'>(" + tr("Disabled") + ")</span>");
}
privateSendClient.fPrivateSendRunning = false;
privateSendClient.StopMixing();
}

View File

@ -50,13 +50,16 @@ UniValue privatesend(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please unlock wallet for mixing with walletpassphrase first.");
}
privateSendClient.fPrivateSendRunning = true;
if (!privateSendClient.StartMixing(pwallet)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Mixing has been started already.");
}
bool result = privateSendClient.DoAutomaticDenominating(*g_connman);
return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatuses() + ", will retry"));
}
if (request.params[0].get_str() == "stop") {
privateSendClient.fPrivateSendRunning = false;
privateSendClient.StopMixing();
return "Mixing was stopped";
}

View File

@ -374,8 +374,8 @@ void WalletInit::Flush()
{
if (privateSendClient.fEnablePrivateSend) {
// Stop PrivateSend, release keys
privateSendClient.fPrivateSendRunning = false;
privateSendClient.ResetPool();
privateSendClient.StopMixing();
}
for (CWallet* pwallet : GetWallets()) {
pwallet->Flush(false);
@ -408,10 +408,15 @@ void WalletInit::AutoLockMasternodeCollaterals()
void WalletInit::InitPrivateSendSettings()
{
if (!HasWallets()) {
privateSendClient.fEnablePrivateSend = privateSendClient.fPrivateSendRunning = false;
privateSendClient.fEnablePrivateSend = false;
privateSendClient.StopMixing();
} else {
privateSendClient.fEnablePrivateSend = gArgs.GetBoolArg("-enableprivatesend", true);
privateSendClient.fPrivateSendRunning = GetWallets()[0]->IsLocked() ? false : gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART);
if (GetWallets()[0]->IsLocked()) {
privateSendClient.StopMixing();
} else if (gArgs.GetBoolArg("-privatesendautostart", DEFAULT_PRIVATESEND_AUTOSTART)) {
privateSendClient.StartMixing(GetWallets()[0]);
}
}
privateSendClient.fPrivateSendMultiSession = gArgs.GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION);
privateSendClient.nPrivateSendSessions = std::min(std::max((int)gArgs.GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS);
@ -423,7 +428,7 @@ void WalletInit::InitPrivateSendSettings()
if (privateSendClient.fEnablePrivateSend) {
LogPrintf("PrivateSend: autostart=%d, multisession=%d," /* Continued */
"sessions=%d, rounds=%d, amount=%d, denoms_goal=%d, denoms_hardcap=%d\n",
privateSendClient.fPrivateSendRunning, privateSendClient.fPrivateSendMultiSession,
privateSendClient.IsMixing(), privateSendClient.fPrivateSendMultiSession,
privateSendClient.nPrivateSendSessions, privateSendClient.nPrivateSendRounds,
privateSendClient.nPrivateSendAmount,
privateSendClient.nPrivateSendDenomsGoal, privateSendClient.nPrivateSendDenomsHardCap);

View File

@ -4342,7 +4342,7 @@ bool CWallet::NewKeyPool()
batch.ErasePool(nIndex);
}
setExternalKeyPool.clear();
privateSendClient.fPrivateSendRunning = false;
privateSendClient.StopMixing();
nKeysLeftSinceAutoBackup = 0;
m_pool_key_to_index.clear();