Merge #6447: [v22.0.x] backport: v22.0.0 rc.3

c7b0d80939 Merge #6441: fix: hold wallet shared pointer in CJ Manager/Sessions to prevent concurrent unload (pasta)
c074e0965b Merge #6444: fix: add platform transfer to "most common" filter (pasta)
cb04114143 Merge #6442: fix: coin selection with `include_unsafe` option should respect `nCoinType` (pasta)
db5b53a9a7 Merge #6434: fix: early EHF and buried EHF are indistinguish (pasta)

Pull request description:

  ## Issue being fixed or feature implemented
  See commits; backports for rc.3

  ## What was done?

  ## How Has This Been Tested?
  built locally

  ## Breaking Changes

  ## Checklist:
    _Go over all the following points, and put an `x` in all the boxes that apply._
  - [ ] 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
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  kwvg:
    ACK c7b0d80939
  UdjinM6:
    utACK c7b0d80939

Tree-SHA512: a64d6503a845ea86df8660d34cdf819c6fefcae5e82035bd8de40152f4f7d894cd1870315b791cca81e6d4db08d9929e4d1de3338a0338478072c9e6bb66952a
This commit is contained in:
pasta 2024-12-03 12:52:40 -06:00
commit e0151e3dfe
No known key found for this signature in database
GPG Key ID: E2F3D7916E722D38
14 changed files with 178 additions and 147 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

@ -24,6 +24,7 @@
static const std::string MNEHF_REQUESTID_PREFIX = "mnhf"; static const std::string MNEHF_REQUESTID_PREFIX = "mnhf";
static const std::string DB_SIGNALS = "mnhf_s"; static const std::string DB_SIGNALS = "mnhf_s";
static const std::string DB_SIGNALS_v2 = "mnhf_s2";
uint256 MNHFTxPayload::GetRequestId() const uint256 MNHFTxPayload::GetRequestId() const
{ {
@ -57,34 +58,33 @@ CMNHFManager::Signals CMNHFManager::GetSignalsStage(const CBlockIndex* const pin
{ {
if (!DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return {}; if (!DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return {};
Signals signals = GetForBlock(pindexPrev); Signals signals_tmp = GetForBlock(pindexPrev);
if (pindexPrev == nullptr) return {}; if (pindexPrev == nullptr) return {};
const int height = pindexPrev->nHeight + 1; const int height = pindexPrev->nHeight + 1;
for (auto it = signals.begin(); it != signals.end(); ) {
bool found{false}; Signals signals_ret;
const auto signal_pindex = pindexPrev->GetAncestor(it->second);
for (auto signal : signals_tmp) {
bool expired{false};
const auto signal_pindex = pindexPrev->GetAncestor(signal.second);
assert(signal_pindex != nullptr); assert(signal_pindex != nullptr);
const int64_t signal_time = signal_pindex->GetMedianTimePast(); const int64_t signal_time = signal_pindex->GetMedianTimePast();
for (int index = 0; index < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++index) { for (int index = 0; index < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++index) {
const auto& deployment = Params().GetConsensus().vDeployments[index]; const auto& deployment = Params().GetConsensus().vDeployments[index];
if (deployment.bit != it->first) continue; if (deployment.bit != signal.first) continue;
if (signal_time < deployment.nStartTime) { if (signal_time < deployment.nStartTime) {
// new deployment is using the same bit as the old one // new deployment is using the same bit as the old one
LogPrintf("CMNHFManager::GetSignalsStage: mnhf signal bit=%d height:%d is expired at height=%d\n", it->first, it->second, height); LogPrintf("CMNHFManager::GetSignalsStage: mnhf signal bit=%d height:%d is expired at height=%d\n",
it = signals.erase(it); signal.first, signal.second, height);
} else { expired = true;
++it;
} }
found = true;
break;
} }
if (!found) { if (!expired) {
// no deployment means we buried it and aren't using the same bit (yet) signals_ret.insert(signal);
LogPrintf("CMNHFManager::GetSignalsStage: mnhf signal bit=%d height:%d is not known at height=%d\n", it->first, it->second, height);
it = signals.erase(it);
} }
} }
return signals; return signals_ret;
} }
bool MNHFTx::Verify(const llmq::CQuorumManager& qman, const uint256& quorumHash, const uint256& requestId, const uint256& msgHash, TxValidationState& state) const bool MNHFTx::Verify(const llmq::CQuorumManager& qman, const uint256& quorumHash, const uint256& requestId, const uint256& msgHash, TxValidationState& state) const
@ -287,6 +287,9 @@ CMNHFManager::Signals CMNHFManager::GetForBlock(const CBlockIndex* pindex)
const Consensus::Params& consensusParams{Params().GetConsensus()}; const Consensus::Params& consensusParams{Params().GetConsensus()};
while (!to_calculate.empty()) { while (!to_calculate.empty()) {
const CBlockIndex* pindex_top{to_calculate.top()}; const CBlockIndex* pindex_top{to_calculate.top()};
if (pindex_top->nHeight % 1000 == 0) {
LogPrintf("re-index EHF signals at block %d\n", pindex_top->nHeight);
}
CBlock block; CBlock block;
if (!ReadBlockFromDisk(block, pindex_top, consensusParams)) { if (!ReadBlockFromDisk(block, pindex_top, consensusParams)) {
throw std::runtime_error("failed-getehfforblock-read"); throw std::runtime_error("failed-getehfforblock-read");
@ -328,11 +331,19 @@ std::optional<CMNHFManager::Signals> CMNHFManager::GetFromCache(const CBlockInde
return signals; return signals;
} }
} }
if (m_evoDb.Read(std::make_pair(DB_SIGNALS, blockHash), signals)) { if (m_evoDb.Read(std::make_pair(DB_SIGNALS_v2, blockHash), signals)) {
LOCK(cs_cache); LOCK(cs_cache);
mnhfCache.insert(blockHash, signals); mnhfCache.insert(blockHash, signals);
return signals; return signals;
} }
if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR)) {
// before mn_rr activation we are safe
if (m_evoDb.Read(std::make_pair(DB_SIGNALS, blockHash), signals)) {
LOCK(cs_cache);
mnhfCache.insert(blockHash, signals);
return signals;
}
}
return std::nullopt; return std::nullopt;
} }
@ -346,7 +357,7 @@ void CMNHFManager::AddToCache(const Signals& signals, const CBlockIndex* const p
} }
if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return;
m_evoDb.Write(std::make_pair(DB_SIGNALS, blockHash), signals); m_evoDb.Write(std::make_pair(DB_SIGNALS_v2, blockHash), signals);
} }
void CMNHFManager::AddSignal(const CBlockIndex* const pindex, int bit) void CMNHFManager::AddSignal(const CBlockIndex* const pindex, int bit)
@ -364,6 +375,25 @@ void CMNHFManager::ConnectManagers(gsl::not_null<ChainstateManager*> chainman, g
m_qman = qman; m_qman = qman;
} }
bool CMNHFManager::ForceSignalDBUpdate()
{
// force ehf signals db update
auto dbTx = m_evoDb.BeginTransaction();
const bool last_legacy = bls::bls_legacy_scheme.load();
bls::bls_legacy_scheme.store(false);
GetSignalsStage(m_chainman->ActiveChainstate().m_chain.Tip());
bls::bls_legacy_scheme.store(last_legacy);
dbTx->Commit();
// flush it to disk
if (!m_evoDb.CommitRootTransaction()) {
LogPrintf("CMNHFManager::%s -- failed to commit to evoDB\n", __func__);
return false;
}
return true;
}
std::string MNHFTx::ToString() const std::string MNHFTx::ToString() const
{ {
return strprintf("MNHFTx(versionBit=%d, quorumHash=%s, sig=%s)", return strprintf("MNHFTx(versionBit=%d, quorumHash=%s, sig=%s)",

View File

@ -155,6 +155,8 @@ public:
*/ */
void DisconnectManagers() { m_chainman = nullptr; m_qman = nullptr; }; void DisconnectManagers() { m_chainman = nullptr; m_qman = nullptr; };
bool ForceSignalDBUpdate() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
private: private:
void AddToCache(const Signals& signals, const CBlockIndex* const pindex); void AddToCache(const Signals& signals, const CBlockIndex* const pindex);

View File

@ -2064,6 +2064,10 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
strLoadError = _("Error upgrading evo database"); strLoadError = _("Error upgrading evo database");
break; break;
} }
if (!node.mnhf_manager->ForceSignalDBUpdate()) {
strLoadError = _("Error upgrading evo database for EHF");
break;
}
for (CChainState* chainstate : chainman.GetAll()) { for (CChainState* chainstate : chainman.GetAll()) {
if (!is_coinsview_empty(chainstate)) { if (!is_coinsview_empty(chainstate)) {

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

@ -23,7 +23,7 @@ public:
/** Type filter bit field (all types) */ /** Type filter bit field (all types) */
static const quint32 ALL_TYPES = 0xFFFFFFFF; static const quint32 ALL_TYPES = 0xFFFFFFFF;
/** Type filter bit field (all types but Darksend-SPAM) */ /** Type filter bit field (all types but Darksend-SPAM) */
static const quint32 COMMON_TYPES = 4223; static const quint32 COMMON_TYPES = 0x307f;
static quint32 TYPE(int type) { return 1<<type; } static quint32 TYPE(int type) { return 1<<type; }

View File

@ -82,6 +82,7 @@ public:
class TransactionRecord class TransactionRecord
{ {
public: public:
// Update COMMON_TYPES in TransactionFilterProxyWhen when adding a new type
enum Type enum Type
{ {
Other, Other,

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;
} }
@ -3041,7 +3041,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
if (coin_control.m_include_unsafe_inputs if (coin_control.m_include_unsafe_inputs
&& SelectCoinsMinConf(value_to_select, && SelectCoinsMinConf(value_to_select,
CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */), CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) { vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used, nCoinType)) {
return true; return true;
} }
// Try with unlimited ancestors/descendants. The transaction will still need to meet // Try with unlimited ancestors/descendants. The transaction will still need to meet
@ -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)) { \ if (LogAcceptCategory(BCLog::COINJOIN)) { \
wallet.WalletLogPrintf(__VA_ARGS__); \ wallet->WalletLogPrintf(__VA_ARGS__); \
} \ } \
} while (0) } while (0)