Merge #6441: fix: hold wallet shared pointer in CJ Manager/Sessions to prevent concurrent unload

2d7c7f81b8 fix: do not transfer wallet ownership to CTransactionBuilder{Output} (UdjinM6)
0aeeb8583a fix: add missing `AddWallet` call in `TestLoadWallet` (UdjinM6)
e800d9d09c fix: hold wallet shared pointer in CJ Manager/Sessions to prevent concurrent unload (UdjinM6)

Pull request description:

  ## Issue being fixed or feature implemented
  https://github.com/dashpay/dash/pull/6440#discussion_r1865042366

  ## What was done?

  ## How Has This Been Tested?

  ## Breaking Changes

  ## Checklist:
  - [ ] I have performed a self-review of my own code
  - [ ] I have commented my code, particularly in hard-to-understand areas
  - [ ] I have added or updated relevant unit/integration/functional/e2e tests
  - [ ] I have made corresponding changes to the documentation
  - [ ] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  PastaPastaPasta:
    utACK 2d7c7f81b8

Tree-SHA512: 308e3bed077baa2167b7f9d81b87e5a61a113e4d465706548f303dfc499bc072d4e823e85772e591a879986b0fb0413d5afe0e3995e1f939fa772b29adc0300d
This commit is contained in:
pasta 2024-12-03 08:35:56 -06:00
commit 02948b2695
No known key found for this signature in database
GPG Key ID: E2F3D7916E722D38
9 changed files with 121 additions and 127 deletions

View File

@ -160,7 +160,7 @@ void CCoinJoinClientManager::ProcessMessage(CNode& peer, CChainState& active_cha
} }
} }
CCoinJoinClientSession::CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, CCoinJoinClientSession::CCoinJoinClientSession(const std::shared_ptr<CWallet>& wallet, CoinJoinWalletManager& walletman,
CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman,
CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync,
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman, const std::unique_ptr<CCoinJoinClientQueueManager>& queueman,
@ -258,7 +258,7 @@ void CCoinJoinClientSession::ResetPool()
{ {
txMyCollateral = CMutableTransaction(); txMyCollateral = CMutableTransaction();
UnlockCoins(); UnlockCoins();
WITH_LOCK(m_wallet.cs_wallet, keyHolderStorage.ReturnAll()); WITH_LOCK(m_wallet->cs_wallet, keyHolderStorage.ReturnAll());
WITH_LOCK(cs_coinjoin, SetNull()); WITH_LOCK(cs_coinjoin, SetNull());
} }
@ -292,13 +292,13 @@ void CCoinJoinClientSession::UnlockCoins()
if (!CCoinJoinClientOptions::IsEnabled()) return; if (!CCoinJoinClientOptions::IsEnabled()) return;
while (true) { while (true) {
TRY_LOCK(m_wallet.cs_wallet, lockWallet); TRY_LOCK(m_wallet->cs_wallet, lockWallet);
if (!lockWallet) { if (!lockWallet) {
UninterruptibleSleep(std::chrono::milliseconds{50}); UninterruptibleSleep(std::chrono::milliseconds{50});
continue; continue;
} }
for (const auto& outpoint : vecOutPointLocked) for (const auto& outpoint : vecOutPointLocked)
m_wallet.UnlockCoin(outpoint); m_wallet->UnlockCoin(outpoint);
break; break;
} }
@ -419,7 +419,7 @@ bool CCoinJoinClientSession::CheckTimeout()
SetState(POOL_STATE_ERROR); SetState(POOL_STATE_ERROR);
UnlockCoins(); UnlockCoins();
WITH_LOCK(m_wallet.cs_wallet, keyHolderStorage.ReturnAll()); WITH_LOCK(m_wallet->cs_wallet, keyHolderStorage.ReturnAll());
nTimeLastSuccessfulStep = GetTime(); nTimeLastSuccessfulStep = GetTime();
strLastMessage = CoinJoin::GetMessageByID(ERR_SESSION); strLastMessage = CoinJoin::GetMessageByID(ERR_SESSION);
@ -530,7 +530,7 @@ void CCoinJoinClientSession::ProcessPoolStateUpdate(CCoinJoinStatusUpdate psssup
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- rejected by Masternode: %s\n", __func__, strMessageTmp.translated); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- rejected by Masternode: %s\n", __func__, strMessageTmp.translated);
SetState(POOL_STATE_ERROR); SetState(POOL_STATE_ERROR);
UnlockCoins(); UnlockCoins();
WITH_LOCK(m_wallet.cs_wallet, keyHolderStorage.ReturnAll()); WITH_LOCK(m_wallet->cs_wallet, keyHolderStorage.ReturnAll());
nTimeLastSuccessfulStep = GetTime(); nTimeLastSuccessfulStep = GetTime();
strLastMessage = strMessageTmp; strLastMessage = strMessageTmp;
break; break;
@ -564,7 +564,7 @@ bool CCoinJoinClientSession::SignFinalTransaction(CNode& peer, CChainState& acti
if (m_is_masternode) return false; if (m_is_masternode) return false;
if (!mixingMasternode) return false; if (!mixingMasternode) return false;
LOCK(m_wallet.cs_wallet); LOCK(m_wallet->cs_wallet);
LOCK(cs_coinjoin); LOCK(cs_coinjoin);
finalMutableTransaction = CMutableTransaction{finalTransactionNew}; finalMutableTransaction = CMutableTransaction{finalTransactionNew};
@ -646,9 +646,9 @@ bool CCoinJoinClientSession::SignFinalTransaction(CNode& peer, CChainState& acti
} }
// fill values for found outpoints // fill values for found outpoints
m_wallet.chain().findCoins(coins); m_wallet->chain().findCoins(coins);
std::map<int, bilingual_str> signing_errors; std::map<int, bilingual_str> signing_errors;
m_wallet.SignTransaction(finalMutableTransaction, coins, SIGHASH_ALL | SIGHASH_ANYONECANPAY, signing_errors); m_wallet->SignTransaction(finalMutableTransaction, coins, SIGHASH_ALL | SIGHASH_ANYONECANPAY, signing_errors);
for (const auto& [input_index, error_string] : signing_errors) { for (const auto& [input_index, error_string] : signing_errors) {
// NOTE: this is a partial signing so it's expected for SignTransaction to return // NOTE: this is a partial signing so it's expected for SignTransaction to return
@ -697,7 +697,7 @@ void CCoinJoinClientSession::CompletedTransaction(PoolMessage nMessageID)
keyHolderStorage.KeepAll(); keyHolderStorage.KeepAll();
WalletCJLogPrint(m_wallet, "CompletedTransaction -- success\n"); WalletCJLogPrint(m_wallet, "CompletedTransaction -- success\n");
} else { } else {
WITH_LOCK(m_wallet.cs_wallet, keyHolderStorage.ReturnAll()); WITH_LOCK(m_wallet->cs_wallet, keyHolderStorage.ReturnAll());
WalletCJLogPrint(m_wallet, "CompletedTransaction -- error\n"); WalletCJLogPrint(m_wallet, "CompletedTransaction -- error\n");
} }
UnlockCoins(); UnlockCoins();
@ -725,14 +725,14 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false; if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return false;
// We don't need auto-backups for descriptor wallets // We don't need auto-backups for descriptor wallets
if (!m_wallet.IsLegacy()) return true; if (!m_wallet->IsLegacy()) return true;
switch (nWalletBackups) { switch (nWalletBackups) {
case 0: case 0:
strAutoDenomResult = _("Automatic backups disabled") + Untranslated(", ") + _("no mixing available."); strAutoDenomResult = _("Automatic backups disabled") + Untranslated(", ") + _("no mixing available.");
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original); WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original);
StopMixing(); StopMixing();
m_wallet.nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup" m_wallet->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup"
return false; return false;
case -1: case -1:
// Automatic backup failed, nothing else we can do until user fixes the issue manually. // Automatic backup failed, nothing else we can do until user fixes the issue manually.
@ -750,16 +750,18 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
return false; return false;
} }
if (m_wallet.nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_STOP) { if (m_wallet->nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_STOP) {
// We should never get here via mixing itself but probably something else is still actively using keypool // We should never get here via mixing itself but probably something else is still actively using keypool
strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + Untranslated(", ") + _("no mixing available."), m_wallet.nKeysLeftSinceAutoBackup); strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + Untranslated(", ") +
_("no mixing available."),
m_wallet->nKeysLeftSinceAutoBackup);
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original); WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original);
// It's getting really dangerous, stop mixing // It's getting really dangerous, stop mixing
StopMixing(); StopMixing();
return false; return false;
} else if (m_wallet.nKeysLeftSinceAutoBackup < COINJOIN_KEYS_THRESHOLD_WARNING) { } else if (m_wallet->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
strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), m_wallet.nKeysLeftSinceAutoBackup); strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), m_wallet->nKeysLeftSinceAutoBackup);
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original); WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- %s\n", strAutoDenomResult.original);
if (fCreateAutoBackups) { if (fCreateAutoBackups) {
@ -767,7 +769,7 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
bilingual_str errorString; bilingual_str errorString;
std::vector<bilingual_str> warnings; std::vector<bilingual_str> warnings;
if (!m_wallet.AutoBackupWallet("", errorString, warnings)) { if (!m_wallet->AutoBackupWallet("", errorString, warnings)) {
if (!warnings.empty()) { if (!warnings.empty()) {
// There were some issues saving backup but yet more or less safe to continue // There were some issues saving backup but yet more or less safe to continue
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", Join(warnings, Untranslated("\n")).translated); WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", Join(warnings, Untranslated("\n")).translated);
@ -785,7 +787,8 @@ bool CCoinJoinClientManager::CheckAutomaticBackup()
} }
} }
WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", m_wallet.nKeysLeftSinceAutoBackup); WalletCJLogPrint(m_wallet, "CCoinJoinClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n",
m_wallet->nKeysLeftSinceAutoBackup);
return true; return true;
} }
@ -809,9 +812,9 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
CAmount nBalanceNeedsAnonymized; CAmount nBalanceNeedsAnonymized;
{ {
LOCK(m_wallet.cs_wallet); LOCK(m_wallet->cs_wallet);
if (!fDryRun && m_wallet.IsLocked(true)) { if (!fDryRun && m_wallet->IsLocked(true)) {
strAutoDenomResult = _("Wallet is locked."); strAutoDenomResult = _("Wallet is locked.");
return false; return false;
} }
@ -834,7 +837,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
return false; return false;
} }
const auto bal = m_wallet.GetBalance(); const auto bal = m_wallet->GetBalance();
// check if there is anything left to do // check if there is anything left to do
CAmount nBalanceAnonymized = bal.m_anonymized; CAmount nBalanceAnonymized = bal.m_anonymized;
@ -849,13 +852,13 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
CAmount nValueMin = CoinJoin::GetSmallestDenomination(); CAmount nValueMin = CoinJoin::GetSmallestDenomination();
// if there are no confirmed DS collateral inputs yet // if there are no confirmed DS collateral inputs yet
if (!m_wallet.HasCollateralInputs()) { if (!m_wallet->HasCollateralInputs()) {
// should have some additional amount for them // should have some additional amount for them
nValueMin += CoinJoin::GetMaxCollateralAmount(); nValueMin += CoinJoin::GetMaxCollateralAmount();
} }
// including denoms but applying some restrictions // including denoms but applying some restrictions
CAmount nBalanceAnonymizable = m_wallet.GetAnonymizableBalance(); CAmount nBalanceAnonymizable = m_wallet->GetAnonymizableBalance();
// mixable balance is way too small // mixable balance is way too small
if (nBalanceAnonymizable < nValueMin) { if (nBalanceAnonymizable < nValueMin) {
@ -865,7 +868,7 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
} }
// excluding denoms // excluding denoms
CAmount nBalanceAnonimizableNonDenom = m_wallet.GetAnonymizableBalance(true); CAmount nBalanceAnonimizableNonDenom = m_wallet->GetAnonymizableBalance(true);
// denoms // denoms
CAmount nBalanceDenominatedConf = bal.m_denominated_trusted; CAmount nBalanceDenominatedConf = bal.m_denominated_trusted;
CAmount nBalanceDenominatedUnconf = bal.m_denominated_untrusted_pending; CAmount nBalanceDenominatedUnconf = bal.m_denominated_untrusted_pending;
@ -917,8 +920,8 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
} }
//check if we have the collateral sized inputs //check if we have the collateral sized inputs
if (!m_wallet.HasCollateralInputs()) { if (!m_wallet->HasCollateralInputs()) {
return !m_wallet.HasCollateralInputs(false) && MakeCollateralAmounts(); return !m_wallet->HasCollateralInputs(false) && MakeCollateralAmounts();
} }
if (nSessionID) { if (nSessionID) {
@ -957,10 +960,10 @@ bool CCoinJoinClientSession::DoAutomaticDenominating(ChainstateManager& chainman
} }
// lock the funds we're going to use for our collateral // lock the funds we're going to use for our collateral
for (const auto& txin : txMyCollateral.vin) { for (const auto& txin : txMyCollateral.vin) {
m_wallet.LockCoin(txin.prevout); m_wallet->LockCoin(txin.prevout);
vecOutPointLocked.push_back(txin.prevout); vecOutPointLocked.push_back(txin.prevout);
} }
} // LOCK(m_wallet.cs_wallet); } // LOCK(m_wallet->cs_wallet);
// Always attempt to join an existing queue // Always attempt to join an existing queue
if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) { if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) {
@ -985,7 +988,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman
return false; return false;
} }
if (!fDryRun && m_wallet.IsLocked(true)) { if (!fDryRun && m_wallet->IsLocked(true)) {
strAutoDenomResult = _("Wallet is locked."); strAutoDenomResult = _("Wallet is locked.");
return false; return false;
} }
@ -1107,7 +1110,7 @@ bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized,
std::vector<CTxDSIn> vecTxDSInTmp; std::vector<CTxDSIn> vecTxDSInTmp;
// Try to match their denominations if possible, select exact number of denominations // Try to match their denominations if possible, select exact number of denominations
if (!m_wallet.SelectTxDSInsByDenomination(dsq.nDenom, nBalanceNeedsAnonymized, vecTxDSInTmp)) { if (!m_wallet->SelectTxDSInsByDenomination(dsq.nDenom, nBalanceNeedsAnonymized, vecTxDSInTmp)) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CoinJoin::DenominationToString(dsq.nDenom)); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CoinJoin::DenominationToString(dsq.nDenom));
continue; continue;
} }
@ -1153,7 +1156,7 @@ bool CCoinJoinClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CCon
// find available denominated amounts // find available denominated amounts
std::set<CAmount> setAmounts; std::set<CAmount> setAmounts;
if (!m_wallet.SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) { if (!m_wallet->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) {
// this should never happen // this should never happen
strAutoDenomResult = _("Can't mix: no compatible inputs found!"); strAutoDenomResult = _("Can't mix: no compatible inputs found!");
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- %s\n", strAutoDenomResult.original); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::StartNewQueue -- %s\n", strAutoDenomResult.original);
@ -1288,7 +1291,7 @@ bool CCoinJoinClientManager::MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq)
bool CCoinJoinClientSession::SubmitDenominate(CConnman& connman) bool CCoinJoinClientSession::SubmitDenominate(CConnman& connman)
{ {
LOCK(m_wallet.cs_wallet); LOCK(m_wallet->cs_wallet);
std::string strError; std::string strError;
std::vector<CTxDSIn> vecTxDSIn; std::vector<CTxDSIn> vecTxDSIn;
@ -1342,7 +1345,7 @@ bool CCoinJoinClientSession::SelectDenominate(std::string& strErrorRet, std::vec
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
if (m_wallet.IsLocked(true)) { if (m_wallet->IsLocked(true)) {
strErrorRet = "Wallet locked, unable to create transaction!"; strErrorRet = "Wallet locked, unable to create transaction!";
return false; return false;
} }
@ -1354,7 +1357,7 @@ bool CCoinJoinClientSession::SelectDenominate(std::string& strErrorRet, std::vec
vecTxDSInRet.clear(); vecTxDSInRet.clear();
bool fSelected = m_wallet.SelectTxDSInsByDenomination(nSessionDenom, CoinJoin::GetMaxPoolAmount(), vecTxDSInRet); bool fSelected = m_wallet->SelectTxDSInsByDenomination(nSessionDenom, CoinJoin::GetMaxPoolAmount(), vecTxDSInRet);
if (!fSelected) { if (!fSelected) {
strErrorRet = "Can't select current denominated inputs"; strErrorRet = "Can't select current denominated inputs";
return false; return false;
@ -1365,7 +1368,7 @@ bool CCoinJoinClientSession::SelectDenominate(std::string& strErrorRet, std::vec
bool CCoinJoinClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet, bool fDryRun) bool CCoinJoinClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet, bool fDryRun)
{ {
AssertLockHeld(m_wallet.cs_wallet); AssertLockHeld(m_wallet->cs_wallet);
if (!CoinJoin::IsValidDenomination(nSessionDenom)) { if (!CoinJoin::IsValidDenomination(nSessionDenom)) {
strErrorRet = "Incorrect session denom"; strErrorRet = "Incorrect session denom";
@ -1395,12 +1398,7 @@ bool CCoinJoinClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, s
++nSteps; ++nSteps;
continue; continue;
} }
const auto pwallet = GetWallet(m_wallet.GetName()); scriptDenom = keyHolderStorage.AddKey(m_wallet.get());
if (!pwallet) {
strErrorRet ="Couldn't get wallet pointer";
return false;
}
scriptDenom = keyHolderStorage.AddKey(pwallet.get());
} }
vecPSInOutPairsRet.emplace_back(entry, CTxOut(nDenomAmount, scriptDenom)); vecPSInOutPairsRet.emplace_back(entry, CTxOut(nDenomAmount, scriptDenom));
// step is complete // step is complete
@ -1418,7 +1416,7 @@ bool CCoinJoinClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, s
} }
for (const auto& [txDsIn, txDsOut] : vecPSInOutPairsRet) { for (const auto& [txDsIn, txDsOut] : vecPSInOutPairsRet) {
m_wallet.LockCoin(txDsIn.prevout); m_wallet->LockCoin(txDsIn.prevout);
vecOutPointLocked.push_back(txDsIn.prevout); vecOutPointLocked.push_back(txDsIn.prevout);
} }
@ -1430,13 +1428,13 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
LOCK(m_wallet.cs_wallet); LOCK(m_wallet->cs_wallet);
// NOTE: We do not allow txes larger than 100 kB, 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. // We still want to consume a lot of inputs to avoid creating only smaller denoms though.
// Knowing that each CTxIn is at least 148 B big, 400 inputs should take 400 x ~148 B = ~60 kB. // 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. // This still leaves more than enough room for another data of typical MakeCollateralAmounts tx.
std::vector<CompactTallyItem> vecTally = m_wallet.SelectCoinsGroupedByAddresses(false, false, true, 400); std::vector<CompactTallyItem> vecTally = m_wallet->SelectCoinsGroupedByAddresses(false, false, true, 400);
if (vecTally.empty()) { if (vecTally.empty()) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
return false; return false;
@ -1448,14 +1446,14 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
}); });
// First try to use only non-denominated funds // First try to use only non-denominated funds
if (ranges::any_of(vecTally, [&](const auto& item) EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet) { if (ranges::any_of(vecTally, [&](const auto& item) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
return MakeCollateralAmounts(item, false); return MakeCollateralAmounts(item, false);
})) { })) {
return true; return true;
} }
// There should be at least some denominated funds we should be able to break in pieces to continue mixing // There should be at least some denominated funds we should be able to break in pieces to continue mixing
if (ranges::any_of(vecTally, [&](const auto& item) EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet) { if (ranges::any_of(vecTally, [&](const auto& item) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
return MakeCollateralAmounts(item, true); return MakeCollateralAmounts(item, true);
})) { })) {
return true; return true;
@ -1470,7 +1468,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts()
bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated) bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated)
{ {
// TODO: consider refactoring to remove duplicated code with CCoinJoinClientSession::CreateDenominated // TODO: consider refactoring to remove duplicated code with CCoinJoinClientSession::CreateDenominated
AssertLockHeld(m_wallet.cs_wallet); AssertLockHeld(m_wallet->cs_wallet);
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
@ -1484,14 +1482,7 @@ bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tally
return false; return false;
} }
const auto pwallet = GetWallet(m_wallet.GetName()); CTransactionBuilder txBuilder(m_wallet, tallyItem);
if (!pwallet) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Couldn't get wallet pointer\n", __func__);
return false;
}
CTransactionBuilder txBuilder(pwallet, tallyItem);
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString()); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
@ -1562,13 +1553,13 @@ bool CCoinJoinClientSession::MakeCollateralAmounts(const CompactTallyItem& tally
bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason)
{ {
AssertLockHeld(m_wallet.cs_wallet); AssertLockHeld(m_wallet->cs_wallet);
std::vector<COutput> vCoins; std::vector<COutput> vCoins;
CCoinControl coin_control; CCoinControl coin_control;
coin_control.nCoinType = CoinType::ONLY_COINJOIN_COLLATERAL; coin_control.nCoinType = CoinType::ONLY_COINJOIN_COLLATERAL;
m_wallet.AvailableCoins(vCoins, &coin_control); m_wallet->AvailableCoins(vCoins, &coin_control);
if (vCoins.empty()) { if (vCoins.empty()) {
strReason = strprintf("%s requires a collateral transaction and could not locate an acceptable input!", gCoinJoinName); strReason = strprintf("%s requires a collateral transaction and could not locate an acceptable input!", gCoinJoinName);
@ -1589,7 +1580,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
// make our change address // make our change address
CScript scriptChange; CScript scriptChange;
CTxDestination dest; CTxDestination dest;
ReserveDestination reserveDest(&m_wallet); ReserveDestination reserveDest(m_wallet.get());
bool success = reserveDest.GetReservedDestination(dest, true); bool success = reserveDest.GetReservedDestination(dest, true);
assert(success); // should never fail, as we just unlocked assert(success); // should never fail, as we just unlocked
scriptChange = GetScriptForDestination(dest); scriptChange = GetScriptForDestination(dest);
@ -1601,7 +1592,7 @@ bool CCoinJoinClientSession::CreateCollateralTransaction(CMutableTransaction& tx
txCollateral.vout.emplace_back(0, CScript() << OP_RETURN); txCollateral.vout.emplace_back(0, CScript() << OP_RETURN);
} }
if (!m_wallet.SignTransaction(txCollateral)) { if (!m_wallet->SignTransaction(txCollateral)) {
strReason = "Unable to sign collateral transaction!"; strReason = "Unable to sign collateral transaction!";
return false; return false;
} }
@ -1614,13 +1605,13 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
{ {
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
LOCK(m_wallet.cs_wallet); LOCK(m_wallet->cs_wallet);
// NOTE: We do not allow txes larger than 100 kB, 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. // We still want to consume a lot of inputs to avoid creating only smaller denoms though.
// Knowing that each CTxIn is at least 148 B big, 400 inputs should take 400 x ~148 B = ~60 kB. // 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. // This still leaves more than enough room for another data of typical CreateDenominated tx.
std::vector<CompactTallyItem> vecTally = m_wallet.SelectCoinsGroupedByAddresses(true, true, true, 400); std::vector<CompactTallyItem> vecTally = m_wallet->SelectCoinsGroupedByAddresses(true, true, true, 400);
if (vecTally.empty()) { if (vecTally.empty()) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n"); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
return false; return false;
@ -1631,7 +1622,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
return a.nAmount > b.nAmount; return a.nAmount > b.nAmount;
}); });
bool fCreateMixingCollaterals = !m_wallet.HasCollateralInputs(); bool fCreateMixingCollaterals = !m_wallet->HasCollateralInputs();
for (const auto& item : vecTally) { for (const auto& item : vecTally) {
if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals)) continue; if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals)) continue;
@ -1645,7 +1636,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate)
// Create denominations // Create denominations
bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals) bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
{ {
AssertLockHeld(m_wallet.cs_wallet); AssertLockHeld(m_wallet->cs_wallet);
if (!CCoinJoinClientOptions::IsEnabled()) return false; if (!CCoinJoinClientOptions::IsEnabled()) return false;
@ -1654,14 +1645,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
return false; return false;
} }
const auto pwallet = GetWallet(m_wallet.GetName()); CTransactionBuilder txBuilder(m_wallet, tallyItem);
if (!pwallet) {
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Couldn't get wallet pointer\n", __func__);
return false;
}
CTransactionBuilder txBuilder(pwallet, tallyItem);
WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString()); WalletCJLogPrint(m_wallet, "CCoinJoinClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
@ -1679,7 +1663,7 @@ bool CCoinJoinClientSession::CreateDenominated(CAmount nBalanceToDenominate, con
std::map<CAmount, int> mapDenomCount; std::map<CAmount, int> mapDenomCount;
for (auto nDenomValue : denoms) { for (auto nDenomValue : denoms) {
mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, m_wallet.CountInputsWithAmount(nDenomValue))); mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, m_wallet->CountInputsWithAmount(nDenomValue)));
} }
// Will generate outputs for the createdenoms up to coinjoinmaxdenoms per denom // Will generate outputs for the createdenoms up to coinjoinmaxdenoms per denom
@ -1922,11 +1906,11 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const
obj.pushKV("sessions", arrSessions); obj.pushKV("sessions", arrSessions);
} }
void CoinJoinWalletManager::Add(CWallet& wallet) void CoinJoinWalletManager::Add(const std::shared_ptr<CWallet>& wallet)
{ {
{ {
LOCK(cs_wallet_manager_map); LOCK(cs_wallet_manager_map);
m_wallet_manager_map.try_emplace(wallet.GetName(), m_wallet_manager_map.try_emplace(wallet->GetName(),
std::make_unique<CCoinJoinClientManager>(wallet, *this, m_dmnman, m_mn_metaman, std::make_unique<CCoinJoinClientManager>(wallet, *this, m_dmnman, m_mn_metaman,
m_mn_sync, m_queueman, m_is_masternode)); m_mn_sync, m_queueman, m_is_masternode));
} }

View File

@ -96,7 +96,7 @@ public:
} }
} }
void Add(CWallet& wallet); void Add(const std::shared_ptr<CWallet>& wallet);
void DoMaintenance(); void DoMaintenance();
void Remove(const std::string& name); void Remove(const std::string& name);
@ -138,7 +138,7 @@ private:
class CCoinJoinClientSession : public CCoinJoinBaseSession class CCoinJoinClientSession : public CCoinJoinBaseSession
{ {
private: private:
CWallet& m_wallet; const std::shared_ptr<CWallet> m_wallet;
CoinJoinWalletManager& m_walletman; CoinJoinWalletManager& m_walletman;
CCoinJoinClientManager& m_clientman; CCoinJoinClientManager& m_clientman;
CDeterministicMNManager& m_dmnman; CDeterministicMNManager& m_dmnman;
@ -163,15 +163,15 @@ private:
/// Create denominations /// Create denominations
bool CreateDenominated(CAmount nBalanceToDenominate); bool CreateDenominated(CAmount nBalanceToDenominate);
bool CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals) bool CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet); EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
/// Split up large inputs or make fee sized inputs /// Split up large inputs or make fee sized inputs
bool MakeCollateralAmounts(); bool MakeCollateralAmounts();
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated) bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated)
EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet); EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason)
EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet); EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman); bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
bool StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman); bool StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
@ -181,7 +181,7 @@ private:
/// step 1: prepare denominated inputs and outputs /// step 1: prepare denominated inputs and outputs
bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn, bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn,
std::vector<std::pair<CTxDSIn, CTxOut>>& vecPSInOutPairsRet, bool fDryRun = false) std::vector<std::pair<CTxDSIn, CTxOut>>& vecPSInOutPairsRet, bool fDryRun = false)
EXCLUSIVE_LOCKS_REQUIRED(m_wallet.cs_wallet); EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
/// step 2: send denominated inputs and outputs prepared in step 1 /// step 2: send denominated inputs and outputs prepared in step 1
bool SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin); bool SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin);
@ -200,7 +200,7 @@ private:
void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin); void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
public: public:
explicit CCoinJoinClientSession(CWallet& wallet, CoinJoinWalletManager& walletman, explicit CCoinJoinClientSession(const std::shared_ptr<CWallet>& wallet, CoinJoinWalletManager& walletman,
CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman, CCoinJoinClientManager& clientman, CDeterministicMNManager& dmnman,
CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync,
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman, bool is_masternode); const std::unique_ptr<CCoinJoinClientQueueManager>& queueman, bool is_masternode);
@ -267,7 +267,7 @@ public:
class CCoinJoinClientManager class CCoinJoinClientManager
{ {
private: private:
CWallet& m_wallet; const std::shared_ptr<CWallet> m_wallet;
CoinJoinWalletManager& m_walletman; CoinJoinWalletManager& m_walletman;
CDeterministicMNManager& m_dmnman; CDeterministicMNManager& m_dmnman;
CMasternodeMetaMan& m_mn_metaman; CMasternodeMetaMan& m_mn_metaman;
@ -306,11 +306,19 @@ public:
CCoinJoinClientManager(CCoinJoinClientManager const&) = delete; CCoinJoinClientManager(CCoinJoinClientManager const&) = delete;
CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete; CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete;
explicit CCoinJoinClientManager(CWallet& wallet, CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman, explicit CCoinJoinClientManager(const std::shared_ptr<CWallet>& wallet, CoinJoinWalletManager& walletman,
CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
const CMasternodeSync& mn_sync,
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman, bool is_masternode) : const std::unique_ptr<CCoinJoinClientQueueManager>& queueman, bool is_masternode) :
m_wallet(wallet), m_walletman(walletman), m_dmnman(dmnman), m_mn_metaman(mn_metaman), m_mn_sync(mn_sync), m_queueman(queueman), m_wallet(wallet),
m_is_masternode{is_masternode} {} m_walletman(walletman),
m_dmnman(dmnman),
m_mn_metaman(mn_metaman),
m_mn_sync(mn_sync),
m_queueman(queueman),
m_is_masternode{is_masternode}
{
}
void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions); void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);

View File

@ -67,10 +67,7 @@ public:
explicit CoinJoinLoaderImpl(CoinJoinWalletManager& walletman) explicit CoinJoinLoaderImpl(CoinJoinWalletManager& walletman)
: m_walletman(walletman) {} : m_walletman(walletman) {}
void AddWallet(CWallet& wallet) override void AddWallet(const std::shared_ptr<CWallet>& wallet) override { m_walletman.Add(wallet); }
{
m_walletman.Add(wallet);
}
void RemoveWallet(const std::string& name) override void RemoveWallet(const std::string& name) override
{ {
m_walletman.Remove(name); m_walletman.Remove(name);

View File

@ -87,14 +87,15 @@ void CKeyHolderStorage::ReturnAll()
} }
} }
CTransactionBuilderOutput::CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn, std::shared_ptr<CWallet> pwalletIn, CAmount nAmountIn) : CTransactionBuilderOutput::CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn,
const std::shared_ptr<CWallet>& wallet, CAmount nAmountIn) :
pTxBuilder(pTxBuilderIn), pTxBuilder(pTxBuilderIn),
dest(pwalletIn.get()), dest(wallet.get()),
nAmount(nAmountIn) nAmount(nAmountIn)
{ {
assert(pTxBuilder); assert(pTxBuilder);
CTxDestination txdest; CTxDestination txdest;
LOCK(pwalletIn->cs_wallet); LOCK(wallet->cs_wallet);
dest.GetReservedDestination(txdest, false); dest.GetReservedDestination(txdest, false);
script = ::GetScriptForDestination(txdest); script = ::GetScriptForDestination(txdest);
} }
@ -108,15 +109,15 @@ bool CTransactionBuilderOutput::UpdateAmount(const CAmount nNewAmount)
return true; return true;
} }
CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn) : CTransactionBuilder::CTransactionBuilder(const std::shared_ptr<CWallet>& wallet, const CompactTallyItem& tallyItemIn) :
pwallet(pwalletIn), m_wallet(wallet),
dummyReserveDestination(pwalletIn.get()), dummyReserveDestination(wallet.get()),
tallyItem(tallyItemIn) tallyItem(tallyItemIn)
{ {
// Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not // Generate a feerate which will be used to consider if the remainder is dust and will go into fees or not
coinControl.m_discard_feerate = ::GetDiscardRate(*pwallet); coinControl.m_discard_feerate = ::GetDiscardRate(*m_wallet);
// Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction // Generate a feerate which will be used by calculations of this class and also by CWallet::CreateTransaction
coinControl.m_feerate = std::max(GetRequiredFeeRate(*pwallet), pwallet->m_pay_tx_fee); coinControl.m_feerate = std::max(GetRequiredFeeRate(*m_wallet), m_wallet->m_pay_tx_fee);
// Change always goes back to origin // Change always goes back to origin
coinControl.destChange = tallyItemIn.txdest; coinControl.destChange = tallyItemIn.txdest;
// Only allow tallyItems inputs for tx creation // Only allow tallyItems inputs for tx creation
@ -131,16 +132,16 @@ CTransactionBuilder::CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, con
// Get a comparable dummy scriptPubKey, avoid writing/flushing to the actual wallet db // Get a comparable dummy scriptPubKey, avoid writing/flushing to the actual wallet db
CScript dummyScript; CScript dummyScript;
{ {
LOCK(pwallet->cs_wallet); LOCK(m_wallet->cs_wallet);
WalletBatch dummyBatch(pwallet->GetDatabase(), false); WalletBatch dummyBatch(m_wallet->GetDatabase(), false);
dummyBatch.TxnBegin(); dummyBatch.TxnBegin();
CKey secret; CKey secret;
secret.MakeNewKey(pwallet->CanSupportFeature(FEATURE_COMPRPUBKEY)); secret.MakeNewKey(m_wallet->CanSupportFeature(FEATURE_COMPRPUBKEY));
CPubKey dummyPubkey = secret.GetPubKey(); CPubKey dummyPubkey = secret.GetPubKey();
dummyBatch.TxnAbort(); dummyBatch.TxnAbort();
dummyScript = ::GetScriptForDestination(PKHash(dummyPubkey)); dummyScript = ::GetScriptForDestination(PKHash(dummyPubkey));
// Calculate required bytes for the dummy signed tx with tallyItem's inputs only // Calculate required bytes for the dummy signed tx with tallyItem's inputs only
nBytesBase = CalculateMaximumSignedTxSize(CTransaction(dummyTx), pwallet.get(), false); nBytesBase = CalculateMaximumSignedTxSize(CTransaction(dummyTx), m_wallet.get(), false);
} }
// Calculate the output size // Calculate the output size
nBytesOutput = ::GetSerializeSize(CTxOut(0, dummyScript), PROTOCOL_VERSION); nBytesOutput = ::GetSerializeSize(CTxOut(0, dummyScript), PROTOCOL_VERSION);
@ -204,7 +205,7 @@ CTransactionBuilderOutput* CTransactionBuilder::AddOutput(CAmount nAmountOutput)
{ {
if (CouldAddOutput(nAmountOutput)) { if (CouldAddOutput(nAmountOutput)) {
LOCK(cs_outputs); LOCK(cs_outputs);
vecOutputs.push_back(std::make_unique<CTransactionBuilderOutput>(this, pwallet, nAmountOutput)); vecOutputs.push_back(std::make_unique<CTransactionBuilderOutput>(this, m_wallet, nAmountOutput));
return vecOutputs.back().get(); return vecOutputs.back().get();
} }
return nullptr; return nullptr;
@ -233,12 +234,12 @@ CAmount CTransactionBuilder::GetAmountUsed() const
CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const CAmount CTransactionBuilder::GetFee(unsigned int nBytes) const
{ {
CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes); CAmount nFeeCalc = coinControl.m_feerate->GetFee(nBytes);
CAmount nRequiredFee = GetRequiredFee(*pwallet, nBytes); CAmount nRequiredFee = GetRequiredFee(*m_wallet, nBytes);
if (nRequiredFee > nFeeCalc) { if (nRequiredFee > nFeeCalc) {
nFeeCalc = nRequiredFee; nFeeCalc = nRequiredFee;
} }
if (nFeeCalc > pwallet->m_default_max_tx_fee) { if (nFeeCalc > m_wallet->m_default_max_tx_fee) {
nFeeCalc = pwallet->m_default_max_tx_fee; nFeeCalc = m_wallet->m_default_max_tx_fee;
} }
return nFeeCalc; return nFeeCalc;
} }
@ -273,9 +274,9 @@ bool CTransactionBuilder::Commit(bilingual_str& strResult)
CTransactionRef tx; CTransactionRef tx;
{ {
LOCK2(pwallet->cs_wallet, cs_main); LOCK2(m_wallet->cs_wallet, cs_main);
FeeCalculation fee_calc_out; FeeCalculation fee_calc_out;
if (!pwallet->CreateTransaction(vecSend, tx, nFeeRet, nChangePosRet, strResult, coinControl, fee_calc_out)) { if (!m_wallet->CreateTransaction(vecSend, tx, nFeeRet, nChangePosRet, strResult, coinControl, fee_calc_out)) {
return false; return false;
} }
} }
@ -312,8 +313,8 @@ bool CTransactionBuilder::Commit(bilingual_str& strResult)
} }
{ {
LOCK2(pwallet->cs_wallet, cs_main); LOCK2(m_wallet->cs_wallet, cs_main);
pwallet->CommitTransaction(tx, {}, {}); m_wallet->CommitTransaction(tx, {}, {});
} }
fKeepKeys = true; fKeepKeys = true;

View File

@ -54,7 +54,7 @@ class CTransactionBuilderOutput
CScript script; CScript script;
public: public:
CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn, std::shared_ptr<CWallet> pwalletIn, CAmount nAmountIn); CTransactionBuilderOutput(CTransactionBuilder* pTxBuilderIn, const std::shared_ptr<CWallet>& wallet, CAmount nAmountIn);
CTransactionBuilderOutput(CTransactionBuilderOutput&&) = delete; CTransactionBuilderOutput(CTransactionBuilderOutput&&) = delete;
CTransactionBuilderOutput& operator=(CTransactionBuilderOutput&&) = delete; CTransactionBuilderOutput& operator=(CTransactionBuilderOutput&&) = delete;
/// Get the scriptPubKey of this output /// Get the scriptPubKey of this output
@ -77,7 +77,7 @@ public:
class CTransactionBuilder class CTransactionBuilder
{ {
/// Wallet the transaction will be build for /// Wallet the transaction will be build for
std::shared_ptr<CWallet> pwallet; const std::shared_ptr<CWallet>& m_wallet;
/// See CTransactionBuilder() for initialization /// See CTransactionBuilder() for initialization
CCoinControl coinControl; CCoinControl coinControl;
/// Dummy since we anyway use tallyItem's destination as change destination in coincontrol. /// Dummy since we anyway use tallyItem's destination as change destination in coincontrol.
@ -100,7 +100,7 @@ class CTransactionBuilder
friend class CTransactionBuilderOutput; friend class CTransactionBuilderOutput;
public: public:
CTransactionBuilder(std::shared_ptr<CWallet> pwalletIn, const CompactTallyItem& tallyItemIn); CTransactionBuilder(const std::shared_ptr<CWallet>& wallet, const CompactTallyItem& tallyItemIn);
~CTransactionBuilder(); ~CTransactionBuilder();
/// Check it would be possible to add a single output with the amount nAmount. Returns true if its possible and false if not. /// Check it would be possible to add a single output with the amount nAmount. Returns true if its possible and false if not.
bool CouldAddOutput(CAmount nAmountOutput) const EXCLUSIVE_LOCKS_REQUIRED(!cs_outputs); bool CouldAddOutput(CAmount nAmountOutput) const EXCLUSIVE_LOCKS_REQUIRED(!cs_outputs);

View File

@ -33,7 +33,7 @@ class Loader
public: public:
virtual ~Loader() {} virtual ~Loader() {}
//! Add new wallet to CoinJoin client manager //! Add new wallet to CoinJoin client manager
virtual void AddWallet(CWallet&) = 0; virtual void AddWallet(const std::shared_ptr<CWallet>&) = 0;
//! Remove wallet from CoinJoin client manager //! Remove wallet from CoinJoin client manager
virtual void RemoveWallet(const std::string&) = 0; virtual void RemoveWallet(const std::string&) = 0;
virtual void FlushWallet(const std::string&) = 0; virtual void FlushWallet(const std::string&) = 0;

View File

@ -59,6 +59,10 @@ static std::shared_ptr<CWallet> TestLoadWallet(interfaces::Chain* chain, interfa
std::vector<bilingual_str> warnings; std::vector<bilingual_str> warnings;
auto database = MakeWalletDatabase("", options, status, error); auto database = MakeWalletDatabase("", options, status, error);
auto wallet = CWallet::Create(chain, coinjoin_loader, "", std::move(database), options.create_flags, error, warnings); auto wallet = CWallet::Create(chain, coinjoin_loader, "", std::move(database), options.create_flags, error, warnings);
if (coinjoin_loader) {
// TODO: see CreateWalletWithoutChain
AddWallet(wallet);
}
if (chain) { if (chain) {
wallet->postInitProcess(); wallet->postInitProcess();
} }

View File

@ -125,7 +125,7 @@ bool AddWallet(const std::shared_ptr<CWallet>& wallet)
} }
wallet->ConnectScriptPubKeyManNotifiers(); wallet->ConnectScriptPubKeyManNotifiers();
wallet->AutoLockMasternodeCollaterals(); wallet->AutoLockMasternodeCollaterals();
wallet->coinjoin_loader().AddWallet(*wallet); wallet->coinjoin_loader().AddWallet(wallet);
wallet->NotifyCanGetAddressesChanged(); wallet->NotifyCanGetAddressesChanged();
return true; return true;
} }
@ -1432,7 +1432,7 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
if (wtx == nullptr || wtx->tx == nullptr) { if (wtx == nullptr || wtx->tx == nullptr) {
// no such tx in this wallet // no such tx in this wallet
*nRoundsRef = -1; *nRoundsRef = -1;
WalletCJLogPrint((*this), "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -1); WalletCJLogPrint(this, "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -1);
return *nRoundsRef; return *nRoundsRef;
} }
@ -1440,7 +1440,7 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
if (outpoint.n >= wtx->tx->vout.size()) { if (outpoint.n >= wtx->tx->vout.size()) {
// should never actually hit this // should never actually hit this
*nRoundsRef = -4; *nRoundsRef = -4;
WalletCJLogPrint((*this), "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -4); WalletCJLogPrint(this, "%s FAILED %-70s %3d\n", __func__, outpoint.ToStringShort(), -4);
return *nRoundsRef; return *nRoundsRef;
} }
@ -1448,14 +1448,14 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
if (CoinJoin::IsCollateralAmount(txOutRef->nValue)) { if (CoinJoin::IsCollateralAmount(txOutRef->nValue)) {
*nRoundsRef = -3; *nRoundsRef = -3;
WalletCJLogPrint((*this), "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef); WalletCJLogPrint(this, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef; return *nRoundsRef;
} }
// make sure the final output is non-denominate // make sure the final output is non-denominate
if (!CoinJoin::IsDenominatedAmount(txOutRef->nValue)) { //NOT DENOM if (!CoinJoin::IsDenominatedAmount(txOutRef->nValue)) { //NOT DENOM
*nRoundsRef = -2; *nRoundsRef = -2;
WalletCJLogPrint((*this), "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef); WalletCJLogPrint(this, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef; return *nRoundsRef;
} }
@ -1463,7 +1463,7 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
if (!CoinJoin::IsDenominatedAmount(out.nValue)) { if (!CoinJoin::IsDenominatedAmount(out.nValue)) {
// this one is denominated but there is another non-denominated output found in the same tx // this one is denominated but there is another non-denominated output found in the same tx
*nRoundsRef = 0; *nRoundsRef = 0;
WalletCJLogPrint((*this), "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef); WalletCJLogPrint(this, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef; return *nRoundsRef;
} }
} }
@ -1471,7 +1471,7 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
// make sure we spent all of it with 0 fee, reset to 0 rounds otherwise // make sure we spent all of it with 0 fee, reset to 0 rounds otherwise
if (wtx->GetDebit(ISMINE_SPENDABLE) != wtx->GetCredit(ISMINE_SPENDABLE)) { if (wtx->GetDebit(ISMINE_SPENDABLE) != wtx->GetCredit(ISMINE_SPENDABLE)) {
*nRoundsRef = 0; *nRoundsRef = 0;
WalletCJLogPrint((*this), "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef); WalletCJLogPrint(this, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef; return *nRoundsRef;
} }
@ -1491,7 +1491,7 @@ int CWallet::GetRealOutpointCoinJoinRounds(const COutPoint& outpoint, int nRound
*nRoundsRef = fDenomFound *nRoundsRef = fDenomFound
? (nShortest >= nRoundsMax - 1 ? nRoundsMax : nShortest + 1) // good, we a +1 to the shortest one but only nRoundsMax rounds max allowed ? (nShortest >= nRoundsMax - 1 ? nRoundsMax : nShortest + 1) // good, we a +1 to the shortest one but only nRoundsMax rounds max allowed
: 0; // too bad, we are the fist one in that chain : 0; // too bad, we are the fist one in that chain
WalletCJLogPrint((*this), "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef); WalletCJLogPrint(this, "%s UPDATED %-70s %3d\n", __func__, outpoint.ToStringShort(), *nRoundsRef);
return *nRoundsRef; return *nRoundsRef;
} }
@ -3253,7 +3253,7 @@ bool CWallet::SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::ve
CCoinControl coin_control; CCoinControl coin_control;
coin_control.nCoinType = CoinType::ONLY_READY_TO_MIX; coin_control.nCoinType = CoinType::ONLY_READY_TO_MIX;
AvailableCoins(vCoins, &coin_control); AvailableCoins(vCoins, &coin_control);
WalletCJLogPrint((*this), "CWallet::%s -- vCoins.size(): %d\n", __func__, vCoins.size()); WalletCJLogPrint(this, "CWallet::%s -- vCoins.size(): %d\n", __func__, vCoins.size());
Shuffle(vCoins.rbegin(), vCoins.rend(), FastRandomContext()); Shuffle(vCoins.rbegin(), vCoins.rend(), FastRandomContext());
@ -3271,11 +3271,11 @@ bool CWallet::SelectTxDSInsByDenomination(int nDenom, CAmount nValueMax, std::ve
nValueTotal += nValue; nValueTotal += nValue;
vecTxDSInRet.emplace_back(CTxDSIn(txin, scriptPubKey, nRounds)); vecTxDSInRet.emplace_back(CTxDSIn(txin, scriptPubKey, nRounds));
setRecentTxIds.emplace(txHash); setRecentTxIds.emplace(txHash);
WalletCJLogPrint((*this), "CWallet::%s -- hash: %s, nValue: %d.%08d\n", WalletCJLogPrint(this, "CWallet::%s -- hash: %s, nValue: %d.%08d\n",
__func__, txHash.ToString(), nValue / COIN, nValue % COIN); __func__, txHash.ToString(), nValue / COIN, nValue % COIN);
} }
WalletCJLogPrint((*this), "CWallet::%s -- setRecentTxIds.size(): %d\n", __func__, setRecentTxIds.size()); WalletCJLogPrint(this, "CWallet::%s -- setRecentTxIds.size(): %d\n", __func__, setRecentTxIds.size());
return nValueTotal > 0; return nValueTotal > 0;
} }
@ -4980,7 +4980,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain* chain, interfaces::C
} }
if (coinjoin_loader) { if (coinjoin_loader) {
coinjoin_loader->AddWallet(*walletInstance); coinjoin_loader->AddWallet(walletInstance);
} }
{ {

View File

@ -153,7 +153,7 @@ extern const std::map<uint64_t,std::string> WALLET_FLAG_CAVEATS;
#define WalletCJLogPrint(wallet, ...) \ #define WalletCJLogPrint(wallet, ...) \
do { \ do { \
if (LogAcceptCategory(BCLog::COINJOIN, BCLog::Level::Debug)) { \ if (LogAcceptCategory(BCLog::COINJOIN, BCLog::Level::Debug)) { \
wallet.WalletLogPrintf(__VA_ARGS__); \ wallet->WalletLogPrintf(__VA_ARGS__); \
} \ } \
} while (0) } while (0)