wallet: Remove isminetype

Since the only remaining isminetypes are ISMINE_NO and ISMINE_SPENDABLE,
this enum is now just a bool and can be removed. IsMine is changed to
return a bool and any usage of isminetypes and isminefilters are changed
to be the remaining ISMINE_SPENDABLE case.
This commit is contained in:
Ava Chow
2025-05-15 17:01:46 -07:00
parent 009a69a616
commit be776a1443
21 changed files with 159 additions and 257 deletions

View File

@@ -14,7 +14,6 @@
#include <wallet/context.h> #include <wallet/context.h>
#include <wallet/db.h> #include <wallet/db.h>
#include <wallet/test/util.h> #include <wallet/test/util.h>
#include <wallet/types.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
#include <wallet/walletutil.h> #include <wallet/walletutil.h>
@@ -58,8 +57,8 @@ static void WalletIsMine(benchmark::Bench& bench, int num_combo = 0)
bench.run([&] { bench.run([&] {
LOCK(wallet->cs_wallet); LOCK(wallet->cs_wallet);
isminetype mine = wallet->IsMine(script); bool mine = wallet->IsMine(script);
assert(mine == ISMINE_NO); assert(!mine);
}); });
TestUnloadWallet(std::move(wallet)); TestUnloadWallet(std::move(wallet));

View File

@@ -43,10 +43,8 @@ namespace wallet {
class CCoinControl; class CCoinControl;
class CWallet; class CWallet;
enum class AddressPurpose; enum class AddressPurpose;
enum isminetype : unsigned int;
struct CRecipient; struct CRecipient;
struct WalletContext; struct WalletContext;
using isminefilter = std::underlying_type_t<isminetype>;
} // namespace wallet } // namespace wallet
namespace interfaces { namespace interfaces {
@@ -224,16 +222,16 @@ public:
virtual CAmount getAvailableBalance(const wallet::CCoinControl& coin_control) = 0; virtual CAmount getAvailableBalance(const wallet::CCoinControl& coin_control) = 0;
//! Return whether transaction input belongs to wallet. //! Return whether transaction input belongs to wallet.
virtual wallet::isminetype txinIsMine(const CTxIn& txin) = 0; virtual bool txinIsMine(const CTxIn& txin) = 0;
//! Return whether transaction output belongs to wallet. //! Return whether transaction output belongs to wallet.
virtual wallet::isminetype txoutIsMine(const CTxOut& txout) = 0; virtual bool txoutIsMine(const CTxOut& txout) = 0;
//! Return debit amount if transaction input belongs to wallet. //! Return debit amount if transaction input belongs to wallet.
virtual CAmount getDebit(const CTxIn& txin, wallet::isminefilter filter) = 0; virtual CAmount getDebit(const CTxIn& txin) = 0;
//! Return credit amount if transaction input belongs to wallet. //! Return credit amount if transaction input belongs to wallet.
virtual CAmount getCredit(const CTxOut& txout, wallet::isminefilter filter) = 0; virtual CAmount getCredit(const CTxOut& txout) = 0;
//! Return AvailableCoins + LockedCoins grouped by wallet address. //! Return AvailableCoins + LockedCoins grouped by wallet address.
//! (put change in one group with wallet address) //! (put change in one group with wallet address)
@@ -355,11 +353,11 @@ public:
struct WalletAddress struct WalletAddress
{ {
CTxDestination dest; CTxDestination dest;
wallet::isminetype is_mine; bool is_mine;
wallet::AddressPurpose purpose; wallet::AddressPurpose purpose;
std::string name; std::string name;
WalletAddress(CTxDestination dest, wallet::isminetype is_mine, wallet::AddressPurpose purpose, std::string name) WalletAddress(CTxDestination dest, bool is_mine, wallet::AddressPurpose purpose, std::string name)
: dest(std::move(dest)), is_mine(is_mine), purpose(std::move(purpose)), name(std::move(name)) : dest(std::move(dest)), is_mine(is_mine), purpose(std::move(purpose)), name(std::move(name))
{ {
} }
@@ -383,11 +381,11 @@ struct WalletBalances
struct WalletTx struct WalletTx
{ {
CTransactionRef tx; CTransactionRef tx;
std::vector<wallet::isminetype> txin_is_mine; std::vector<bool> txin_is_mine;
std::vector<wallet::isminetype> txout_is_mine; std::vector<bool> txout_is_mine;
std::vector<bool> txout_is_change; std::vector<bool> txout_is_change;
std::vector<CTxDestination> txout_address; std::vector<CTxDestination> txout_address;
std::vector<wallet::isminetype> txout_address_is_mine; std::vector<bool> txout_address_is_mine;
CAmount credit; CAmount credit;
CAmount debit; CAmount debit;
CAmount change; CAmount change;

View File

@@ -17,17 +17,12 @@
#include <logging.h> #include <logging.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <validation.h> #include <validation.h>
#include <wallet/types.h>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <QLatin1String> #include <QLatin1String>
using wallet::ISMINE_ALL;
using wallet::ISMINE_SPENDABLE;
using wallet::isminetype;
QString TransactionDesc::FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool) QString TransactionDesc::FormatTxStatus(const interfaces::WalletTxStatus& status, bool inMempool)
{ {
int depth = status.depth_in_main_chain; int depth = status.depth_in_main_chain;
@@ -185,7 +180,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
// //
CAmount nUnmatured = 0; CAmount nUnmatured = 0;
for (const CTxOut& txout : wtx.tx->vout) for (const CTxOut& txout : wtx.tx->vout)
nUnmatured += wallet.getCredit(txout, ISMINE_ALL); nUnmatured += wallet.getCredit(txout);
strHTML += "<b>" + tr("Credit") + ":</b> "; strHTML += "<b>" + tr("Credit") + ":</b> ";
if (status.is_in_main_chain) if (status.is_in_main_chain)
strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")"; strHTML += BitcoinUnits::formatHtmlWithUnit(unit, nUnmatured)+ " (" + tr("matures in %n more block(s)", "", status.blocks_to_maturity) + ")";
@@ -202,19 +197,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
} }
else else
{ {
isminetype fAllFromMe = ISMINE_SPENDABLE; bool all_from_me = std::all_of(wtx.txin_is_mine.begin(), wtx.txin_is_mine.end(), [](bool mine) { return mine; });
for (const isminetype mine : wtx.txin_is_mine) bool all_to_me = std::all_of(wtx.txout_is_mine.begin(), wtx.txout_is_mine.end(), [](bool mine) { return mine; });
{
if(fAllFromMe > mine) fAllFromMe = mine;
}
isminetype fAllToMe = ISMINE_SPENDABLE; if (all_from_me)
for (const isminetype mine : wtx.txout_is_mine)
{
if(fAllToMe > mine) fAllToMe = mine;
}
if (fAllFromMe)
{ {
// Debit // Debit
// //
@@ -222,8 +208,8 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
for (const CTxOut& txout : wtx.tx->vout) for (const CTxOut& txout : wtx.tx->vout)
{ {
// Ignore change // Ignore change
isminetype toSelf = *(mine++); bool toSelf = *(mine++);
if ((toSelf == ISMINE_SPENDABLE) && (fAllFromMe == ISMINE_SPENDABLE)) if (toSelf && all_from_me)
continue; continue;
if (!wtx.value_map.count("to") || wtx.value_map["to"].empty()) if (!wtx.value_map.count("to") || wtx.value_map["to"].empty())
@@ -238,7 +224,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
address, &name, /*purpose=*/nullptr) && !name.empty()) address, &name, /*purpose=*/nullptr) && !name.empty())
strHTML += GUIUtil::HtmlEscape(name) + " "; strHTML += GUIUtil::HtmlEscape(name) + " ";
strHTML += GUIUtil::HtmlEscape(EncodeDestination(address)); strHTML += GUIUtil::HtmlEscape(EncodeDestination(address));
if(toSelf == ISMINE_SPENDABLE) if(toSelf)
strHTML += " (" + tr("own address") + ")"; strHTML += " (" + tr("own address") + ")";
strHTML += "<br>"; strHTML += "<br>";
} }
@@ -249,7 +235,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, txout.nValue) + "<br>";
} }
if (fAllToMe) if (all_to_me)
{ {
// Payment to self // Payment to self
CAmount nChange = wtx.change; CAmount nChange = wtx.change;
@@ -270,13 +256,13 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
auto mine = wtx.txin_is_mine.begin(); auto mine = wtx.txin_is_mine.begin();
for (const CTxIn& txin : wtx.tx->vin) { for (const CTxIn& txin : wtx.tx->vin) {
if (*(mine++)) { if (*(mine++)) {
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>"; strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin)) + "<br>";
} }
} }
mine = wtx.txout_is_mine.begin(); mine = wtx.txout_is_mine.begin();
for (const CTxOut& txout : wtx.tx->vout) { for (const CTxOut& txout : wtx.tx->vout) {
if (*(mine++)) { if (*(mine++)) {
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout)) + "<br>";
} }
} }
} }
@@ -333,10 +319,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += "<hr><br>" + tr("Debug information") + "<br><br>"; strHTML += "<hr><br>" + tr("Debug information") + "<br><br>";
for (const CTxIn& txin : wtx.tx->vin) for (const CTxIn& txin : wtx.tx->vin)
if(wallet.txinIsMine(txin)) if(wallet.txinIsMine(txin))
strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin, ISMINE_ALL)) + "<br>"; strHTML += "<b>" + tr("Debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -wallet.getDebit(txin)) + "<br>";
for (const CTxOut& txout : wtx.tx->vout) for (const CTxOut& txout : wtx.tx->vout)
if(wallet.txoutIsMine(txout)) if(wallet.txoutIsMine(txout))
strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout, ISMINE_ALL)) + "<br>"; strHTML += "<b>" + tr("Credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, wallet.getCredit(txout)) + "<br>";
strHTML += "<br><b>" + tr("Transaction") + ":</b><br>"; strHTML += "<br><b>" + tr("Transaction") + ":</b><br>";
strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true); strHTML += GUIUtil::HtmlEscape(wtx.tx->ToString(), true);
@@ -361,7 +347,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
strHTML += QString::fromStdString(EncodeDestination(address)); strHTML += QString::fromStdString(EncodeDestination(address));
} }
strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue); strHTML = strHTML + " " + tr("Amount") + "=" + BitcoinUnits::formatHtmlWithUnit(unit, vout.nValue);
strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) & ISMINE_SPENDABLE ? tr("true") : tr("false")) + "</li>"; strHTML = strHTML + " IsMine=" + (wallet.txoutIsMine(vout) ? tr("true") : tr("false")) + "</li>";
} }
} }
} }

View File

@@ -7,16 +7,11 @@
#include <chain.h> #include <chain.h>
#include <interfaces/wallet.h> #include <interfaces/wallet.h>
#include <key_io.h> #include <key_io.h>
#include <wallet/types.h>
#include <cstdint> #include <cstdint>
#include <QDateTime> #include <QDateTime>
using wallet::ISMINE_NO;
using wallet::ISMINE_SPENDABLE;
using wallet::isminetype;
/* Return positive answer if transaction should be shown in list. /* Return positive answer if transaction should be shown in list.
*/ */
bool TransactionRecord::showTransaction() bool TransactionRecord::showTransaction()
@@ -39,26 +34,26 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
Txid hash = wtx.tx->GetHash(); Txid hash = wtx.tx->GetHash();
std::map<std::string, std::string> mapValue = wtx.value_map; std::map<std::string, std::string> mapValue = wtx.value_map;
isminetype fAllFromMe = ISMINE_SPENDABLE; bool all_from_me = true;
bool any_from_me = false; bool any_from_me = false;
if (wtx.is_coinbase) { if (wtx.is_coinbase) {
fAllFromMe = ISMINE_NO; all_from_me = false;
} else { } else {
for (const isminetype mine : wtx.txin_is_mine) for (const bool mine : wtx.txin_is_mine)
{ {
if(fAllFromMe > mine) fAllFromMe = mine; all_from_me = all_from_me && mine;
if (mine) any_from_me = true; if (mine) any_from_me = true;
} }
} }
if (fAllFromMe || !any_from_me) { if (all_from_me || !any_from_me) {
CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
{ {
const CTxOut& txout = wtx.tx->vout[i]; const CTxOut& txout = wtx.tx->vout[i];
if (fAllFromMe) { if (all_from_me) {
// Change is only really possible if we're the sender // Change is only really possible if we're the sender
// Otherwise, someone just sent bitcoins to a change address, which should be shown // Otherwise, someone just sent bitcoins to a change address, which should be shown
if (wtx.txout_is_change[i]) { if (wtx.txout_is_change[i]) {
@@ -97,7 +92,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
parts.append(sub); parts.append(sub);
} }
isminetype mine = wtx.txout_is_mine[i]; bool mine = wtx.txout_is_mine[i];
if(mine) if(mine)
{ {
// //

View File

@@ -5,7 +5,6 @@
#include <common/system.h> #include <common/system.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <interfaces/chain.h> #include <interfaces/chain.h>
#include <node/types.h>
#include <policy/fees.h> #include <policy/fees.h>
#include <policy/policy.h> #include <policy/policy.h>
#include <util/moneystr.h> #include <util/moneystr.h>
@@ -48,8 +47,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
if (require_mine) { if (require_mine) {
// check that original tx consists entirely of our inputs // check that original tx consists entirely of our inputs
// if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee) // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
isminefilter filter = ISMINE_SPENDABLE; if (!AllInputsMine(wallet, *wtx.tx)) {
if (!AllInputsMine(wallet, *wtx.tx, filter)) {
errors.emplace_back(Untranslated("Transaction contains inputs that don't belong to this wallet")); errors.emplace_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
return feebumper::Result::WALLET_ERROR; return feebumper::Result::WALLET_ERROR;
} }

View File

@@ -23,7 +23,6 @@
#include <wallet/context.h> #include <wallet/context.h>
#include <wallet/feebumper.h> #include <wallet/feebumper.h>
#include <wallet/fees.h> #include <wallet/fees.h>
#include <wallet/types.h>
#include <wallet/load.h> #include <wallet/load.h>
#include <wallet/receive.h> #include <wallet/receive.h>
#include <wallet/rpc/wallet.h> #include <wallet/rpc/wallet.h>
@@ -74,10 +73,10 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
result.txout_address.emplace_back(); result.txout_address.emplace_back();
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ? result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
wallet.IsMine(result.txout_address.back()) : wallet.IsMine(result.txout_address.back()) :
ISMINE_NO); false);
} }
result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL, /*avoid_reuse=*/true); result.credit = CachedTxGetCredit(wallet, wtx, /*avoid_reuse=*/true);
result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL, /*avoid_reuse=*/true); result.debit = CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/true);
result.change = CachedTxGetChange(wallet, wtx); result.change = CachedTxGetChange(wallet, wtx);
result.time = wtx.GetTxTime(); result.time = wtx.GetTxTime();
result.value_map = wtx.mapValue; result.value_map = wtx.mapValue;
@@ -173,7 +172,7 @@ public:
bool isSpendable(const CTxDestination& dest) override bool isSpendable(const CTxDestination& dest) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; return m_wallet->IsMine(dest);
} }
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override
{ {
@@ -205,7 +204,7 @@ public:
std::vector<WalletAddress> result; std::vector<WalletAddress> result;
m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) { m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
if (is_change) return; if (is_change) return;
isminetype is_mine = m_wallet->IsMine(dest); bool is_mine = m_wallet->IsMine(dest);
// In very old wallets, address purpose may not be recorded so we derive it from IsMine // In very old wallets, address purpose may not be recorded so we derive it from IsMine
result.emplace_back(dest, is_mine, purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND), label); result.emplace_back(dest, is_mine, purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND), label);
}); });
@@ -423,25 +422,25 @@ public:
return total_amount; return total_amount;
} }
isminetype txinIsMine(const CTxIn& txin) override bool txinIsMine(const CTxIn& txin) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return InputIsMine(*m_wallet, txin); return InputIsMine(*m_wallet, txin);
} }
isminetype txoutIsMine(const CTxOut& txout) override bool txoutIsMine(const CTxOut& txout) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->IsMine(txout); return m_wallet->IsMine(txout);
} }
CAmount getDebit(const CTxIn& txin, isminefilter filter) override CAmount getDebit(const CTxIn& txin) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return m_wallet->GetDebit(txin, filter); return m_wallet->GetDebit(txin);
} }
CAmount getCredit(const CTxOut& txout, isminefilter filter) override CAmount getCredit(const CTxOut& txout) override
{ {
LOCK(m_wallet->cs_wallet); LOCK(m_wallet->cs_wallet);
return OutputGetCredit(*m_wallet, txout, filter); return OutputGetCredit(*m_wallet, txout);
} }
CoinsList listCoins() override CoinsList listCoins() override
{ {

View File

@@ -10,39 +10,39 @@
#include <wallet/wallet.h> #include <wallet/wallet.h>
namespace wallet { namespace wallet {
isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin) bool InputIsMine(const CWallet& wallet, const CTxIn& txin)
{ {
AssertLockHeld(wallet.cs_wallet); AssertLockHeld(wallet.cs_wallet);
const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash); const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
if (prev && txin.prevout.n < prev->tx->vout.size()) { if (prev && txin.prevout.n < prev->tx->vout.size()) {
return wallet.IsMine(prev->tx->vout[txin.prevout.n]); return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
} }
return ISMINE_NO; return false;
} }
bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter) bool AllInputsMine(const CWallet& wallet, const CTransaction& tx)
{ {
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
for (const CTxIn& txin : tx.vin) { for (const CTxIn& txin : tx.vin) {
if (!(InputIsMine(wallet, txin) & filter)) return false; if (!InputIsMine(wallet, txin)) return false;
} }
return true; return true;
} }
CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter) CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout)
{ {
if (!MoneyRange(txout.nValue)) if (!MoneyRange(txout.nValue))
throw std::runtime_error(std::string(__func__) + ": value out of range"); throw std::runtime_error(std::string(__func__) + ": value out of range");
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
return ((wallet.IsMine(txout) & filter) ? txout.nValue : 0); return (wallet.IsMine(txout) ? txout.nValue : 0);
} }
CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter) CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx)
{ {
CAmount nCredit = 0; CAmount nCredit = 0;
for (const CTxOut& txout : tx.vout) for (const CTxOut& txout : tx.vout)
{ {
nCredit += OutputGetCredit(wallet, txout, filter); nCredit += OutputGetCredit(wallet, txout);
if (!MoneyRange(nCredit)) if (!MoneyRange(nCredit))
throw std::runtime_error(std::string(__func__) + ": value out of range"); throw std::runtime_error(std::string(__func__) + ": value out of range");
} }
@@ -97,17 +97,17 @@ CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
return nChange; return nChange;
} }
static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter, bool avoid_reuse) static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, bool avoid_reuse)
{ {
auto& amount = wtx.m_amounts[type]; auto& amount = wtx.m_amounts[type];
if (!amount.IsCached(avoid_reuse)) { if (!amount.IsCached(avoid_reuse)) {
amount.Set(avoid_reuse, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter)); amount.Set(avoid_reuse, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx) : TxGetCredit(wallet, *wtx.tx));
wtx.m_is_cache_empty = false; wtx.m_is_cache_empty = false;
} }
return amount.Get(avoid_reuse); return amount.Get(avoid_reuse);
} }
CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter, bool avoid_reuse) CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse)
{ {
AssertLockHeld(wallet.cs_wallet); AssertLockHeld(wallet.cs_wallet);
@@ -115,26 +115,16 @@ CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const ism
if (wallet.IsTxImmatureCoinBase(wtx)) if (wallet.IsTxImmatureCoinBase(wtx))
return 0; return 0;
CAmount credit = 0; // GetBalance can assume transactions in mapWallet won't change
const isminefilter get_amount_filter{filter & ISMINE_ALL}; return GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, avoid_reuse);
if (get_amount_filter) {
// GetBalance can assume transactions in mapWallet won't change
credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter, avoid_reuse);
}
return credit;
} }
CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter, bool avoid_reuse) CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse)
{ {
if (wtx.tx->vin.empty()) if (wtx.tx->vin.empty())
return 0; return 0;
CAmount debit = 0; return GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, avoid_reuse);
const isminefilter get_amount_filter{filter & ISMINE_ALL};
if (get_amount_filter) {
debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter, avoid_reuse);
}
return debit;
} }
CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx) CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
@@ -148,7 +138,7 @@ CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
std::list<COutputEntry>& listReceived, std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter, std::list<COutputEntry>& listSent, CAmount& nFee,
bool include_change) bool include_change)
{ {
nFee = 0; nFee = 0;
@@ -156,7 +146,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
listSent.clear(); listSent.clear();
// Compute fee: // Compute fee:
CAmount nDebit = CachedTxGetDebit(wallet, wtx, filter, /*avoid_reuse=*/false); CAmount nDebit = CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/false);
if (nDebit > 0) // debit>0 means we signed/sent this transaction if (nDebit > 0) // debit>0 means we signed/sent this transaction
{ {
CAmount nValueOut = wtx.tx->GetValueOut(); CAmount nValueOut = wtx.tx->GetValueOut();
@@ -168,7 +158,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
{ {
const CTxOut& txout = wtx.tx->vout[i]; const CTxOut& txout = wtx.tx->vout[i];
isminetype fIsMine = wallet.IsMine(txout); bool ismine = wallet.IsMine(txout);
// Only need to handle txouts if AT LEAST one of these is true: // Only need to handle txouts if AT LEAST one of these is true:
// 1) they debit from us (sent) // 1) they debit from us (sent)
// 2) the output is to us (received) // 2) the output is to us (received)
@@ -177,7 +167,7 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
if (!include_change && OutputIsChange(wallet, txout)) if (!include_change && OutputIsChange(wallet, txout))
continue; continue;
} }
else if (!(fIsMine & filter)) else if (!ismine)
continue; continue;
// In either case, we need to get the destination address // In either case, we need to get the destination address
@@ -197,15 +187,15 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
listSent.push_back(output); listSent.push_back(output);
// If we are receiving the output, add it as a "received" entry // If we are receiving the output, add it as a "received" entry
if (fIsMine & filter) if (ismine)
listReceived.push_back(output); listReceived.push_back(output);
} }
} }
bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter) bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx)
{ {
return (CachedTxGetDebit(wallet, wtx, filter, /*avoid_reuse=*/false) > 0); return (CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/false) > 0);
} }
// NOLINTNEXTLINE(misc-no-recursion) // NOLINTNEXTLINE(misc-no-recursion)
@@ -219,7 +209,7 @@ bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txi
if (wtx.isConfirmed()) return true; if (wtx.isConfirmed()) return true;
if (wtx.isBlockConflicted()) return false; if (wtx.isBlockConflicted()) return false;
// using wtx's cached debit // using wtx's cached debit
if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false; if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx)) return false;
// Don't trust unconfirmed transactions from us unless they are in the mempool. // Don't trust unconfirmed transactions from us unless they are in the mempool.
if (!wtx.InMempool()) return false; if (!wtx.InMempool()) return false;
@@ -232,7 +222,7 @@ bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txi
if (parent == nullptr) return false; if (parent == nullptr) return false;
const CTxOut& parentOut = parent->tx->vout[txin.prevout.n]; const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
// Check that this specific input being spent is trusted // Check that this specific input being spent is trusted
if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false; if (!wallet.IsMine(parentOut)) return false;
// If we've already trusted this parent, continue // If we've already trusted this parent, continue
if (trusted_parents.count(parent->GetHash())) continue; if (trusted_parents.count(parent->GetHash())) continue;
// Recurse to check that the parent is also trusted // Recurse to check that the parent is also trusted
@@ -264,13 +254,7 @@ Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) { if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) {
// Get the amounts for mine // Get the amounts for mine
CAmount credit_mine = 0; CAmount credit_mine = txo.GetTxOut().nValue;
if (txo.GetIsMine() == ISMINE_SPENDABLE) {
credit_mine = txo.GetTxOut().nValue;
} else {
// We shouldn't see any other isminetypes
Assume(false);
}
// Set the amounts in the return object // Set the amounts in the return object
if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) { if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
@@ -300,7 +284,7 @@ std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
if (wallet.IsTxImmatureCoinBase(wtx)) continue; if (wallet.IsTxImmatureCoinBase(wtx)) continue;
int nDepth = wallet.GetTxDepthInMainChain(wtx); int nDepth = wallet.GetTxDepthInMainChain(wtx);
if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1)) continue; if (nDepth < (CachedTxIsFromMe(wallet, wtx) ? 0 : 1)) continue;
CTxDestination addr; CTxDestination addr;
Assume(wallet.IsMine(txo.GetTxOut())); Assume(wallet.IsMine(txo.GetTxOut()));

View File

@@ -8,27 +8,25 @@
#include <consensus/amount.h> #include <consensus/amount.h>
#include <primitives/transaction_identifier.h> #include <primitives/transaction_identifier.h>
#include <wallet/transaction.h> #include <wallet/transaction.h>
#include <wallet/types.h>
#include <wallet/wallet.h> #include <wallet/wallet.h>
namespace wallet { namespace wallet {
isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); bool InputIsMine(const CWallet& wallet, const CTxIn& txin) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
/** Returns whether all of the inputs match the filter */ /** Returns whether all of the inputs belong to the wallet*/
bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter); bool AllInputsMine(const CWallet& wallet, const CTransaction& tx);
CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter); CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout);
CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter); CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx);
bool ScriptIsChange(const CWallet& wallet, const CScript& script) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); bool ScriptIsChange(const CWallet& wallet, const CScript& script) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
bool OutputIsChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); bool OutputIsChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx); CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx);
CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter, bool avoid_reuse) CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
//! filter decides which addresses will count towards the debit CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse);
CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter, bool avoid_reuse);
CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx); CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx);
struct COutputEntry struct COutputEntry
{ {
@@ -39,9 +37,9 @@ struct COutputEntry
void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx, void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
std::list<COutputEntry>& listReceived, std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, std::list<COutputEntry>& listSent,
CAmount& nFee, const isminefilter& filter, CAmount& nFee,
bool include_change); bool include_change);
bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter); bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx);
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet); bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx); bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx);

View File

@@ -448,8 +448,8 @@ RPCHelpMan getaddressinfo()
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey); std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
isminetype mine = pwallet->IsMine(dest); bool mine = pwallet->IsMine(dest);
ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE)); ret.pushKV("ismine", mine);
if (provider) { if (provider) {
auto inferred = InferDescriptor(scriptPubKey, *provider); auto inferred = InferDescriptor(scriptPubKey, *provider);

View File

@@ -1505,7 +1505,7 @@ RPCHelpMan sendall()
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n)); throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not available. UTXO (%s:%d) was already spent.", input.prevout.hash.ToString(), input.prevout.n));
} }
const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)}; const CWalletTx* tx{pwallet->GetWalletTx(input.prevout.hash)};
if (!tx || input.prevout.n >= tx->tx->vout.size() || !(pwallet->IsMine(tx->tx->vout[input.prevout.n]) & ISMINE_SPENDABLE)) { if (!tx || input.prevout.n >= tx->tx->vout.size() || !pwallet->IsMine(tx->tx->vout[input.prevout.n])) {
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n)); throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Input not found. UTXO (%s:%d) is not part of wallet.", input.prevout.hash.ToString(), input.prevout.n));
} }
if (pwallet->GetTxDepthInMainChain(*tx) == 0) { if (pwallet->GetTxDepthInMainChain(*tx) == 0) {

View File

@@ -83,8 +83,6 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
if (!params[1].isNull()) if (!params[1].isNull())
fIncludeEmpty = params[1].get_bool(); fIncludeEmpty = params[1].get_bool();
isminefilter filter = ISMINE_SPENDABLE;
std::optional<CTxDestination> filtered_address{std::nullopt}; std::optional<CTxDestination> filtered_address{std::nullopt};
if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) { if (!by_label && !params[3].isNull() && !params[3].get_str().empty()) {
if (!IsValidDestinationString(params[3].get_str())) { if (!IsValidDestinationString(params[3].get_str())) {
@@ -116,8 +114,7 @@ static UniValue ListReceived(const CWallet& wallet, const UniValue& params, cons
continue; continue;
} }
isminefilter mine = wallet.IsMine(address); if (!wallet.IsMine(address))
if (!(mine & filter))
continue; continue;
tallyitem& item = mapTally[address]; tallyitem& item = mapTally[address];
@@ -302,12 +299,11 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
* @param nMinDepth The minimum confirmation depth. * @param nMinDepth The minimum confirmation depth.
* @param fLong Whether to include the JSON version of the transaction. * @param fLong Whether to include the JSON version of the transaction.
* @param ret The vector into which the result is stored. * @param ret The vector into which the result is stored.
* @param filter_ismine The "is mine" filter flags.
* @param filter_label Optional label string to filter incoming transactions. * @param filter_label Optional label string to filter incoming transactions.
*/ */
template <class Vec> template <class Vec>
static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong,
Vec& ret, const isminefilter& filter_ismine, const std::optional<std::string>& filter_label, Vec& ret, const std::optional<std::string>& filter_label,
bool include_change = false) bool include_change = false)
EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{ {
@@ -315,7 +311,7 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
std::list<COutputEntry> listReceived; std::list<COutputEntry> listReceived;
std::list<COutputEntry> listSent; std::list<COutputEntry> listSent;
CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine, include_change); CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, include_change);
// Sent // Sent
if (!filter_label.has_value()) if (!filter_label.has_value())
@@ -484,7 +480,6 @@ RPCHelpMan listtransactions()
int nFrom = 0; int nFrom = 0;
if (!request.params[2].isNull()) if (!request.params[2].isNull())
nFrom = request.params[2].getInt<int>(); nFrom = request.params[2].getInt<int>();
isminefilter filter = ISMINE_SPENDABLE;
if (nCount < 0) if (nCount < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
@@ -501,7 +496,7 @@ RPCHelpMan listtransactions()
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{ {
CWalletTx *const pwtx = (*it).second; CWalletTx *const pwtx = (*it).second;
ListTransactions(*pwallet, *pwtx, 0, true, ret, filter, filter_label); ListTransactions(*pwallet, *pwtx, 0, true, ret, filter_label);
if ((int)ret.size() >= (nCount+nFrom)) break; if ((int)ret.size() >= (nCount+nFrom)) break;
} }
} }
@@ -589,7 +584,6 @@ RPCHelpMan listsinceblock()
std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain. std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain. std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
int target_confirms = 1; int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
uint256 blockId; uint256 blockId;
if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
@@ -623,7 +617,7 @@ RPCHelpMan listsinceblock()
for (const auto& [_, tx] : wallet.mapWallet) { for (const auto& [_, tx] : wallet.mapWallet) {
if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) { if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
ListTransactions(wallet, tx, 0, true, transactions, filter, filter_label, include_change); ListTransactions(wallet, tx, 0, true, transactions, filter_label, include_change);
} }
} }
@@ -640,7 +634,7 @@ RPCHelpMan listsinceblock()
if (it != wallet.mapWallet.end()) { if (it != wallet.mapWallet.end()) {
// We want all transactions regardless of confirmation count to appear here, // We want all transactions regardless of confirmation count to appear here,
// even negative confirmation ones, hence the big negative. // even negative confirmation ones, hence the big negative.
ListTransactions(wallet, it->second, -100000000, true, removed, filter, filter_label, include_change); ListTransactions(wallet, it->second, -100000000, true, removed, filter_label, include_change);
} }
} }
blockId = block.hashPrevBlock; blockId = block.hashPrevBlock;
@@ -730,8 +724,6 @@ RPCHelpMan gettransaction()
Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))}; Txid hash{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
isminefilter filter = ISMINE_SPENDABLE;
bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool(); bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
UniValue entry(UniValue::VOBJ); UniValue entry(UniValue::VOBJ);
@@ -741,19 +733,19 @@ RPCHelpMan gettransaction()
} }
const CWalletTx& wtx = it->second; const CWalletTx& wtx = it->second;
CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, filter, /*avoid_reuse=*/false); CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, /*avoid_reuse=*/false);
CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, filter, /*avoid_reuse=*/false); CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, /*avoid_reuse=*/false);
CAmount nNet = nCredit - nDebit; CAmount nNet = nCredit - nDebit;
CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx, filter) ? wtx.tx->GetValueOut() - nDebit : 0); CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx) ? wtx.tx->GetValueOut() - nDebit : 0);
entry.pushKV("amount", ValueFromAmount(nNet - nFee)); entry.pushKV("amount", ValueFromAmount(nNet - nFee));
if (CachedTxIsFromMe(*pwallet, wtx, filter)) if (CachedTxIsFromMe(*pwallet, wtx))
entry.pushKV("fee", ValueFromAmount(nFee)); entry.pushKV("fee", ValueFromAmount(nFee));
WalletTxToJSON(*pwallet, wtx, entry); WalletTxToJSON(*pwallet, wtx, entry);
UniValue details(UniValue::VARR); UniValue details(UniValue::VARR);
ListTransactions(*pwallet, wtx, 0, false, details, filter, /*filter_label=*/std::nullopt); ListTransactions(*pwallet, wtx, 0, false, details, /*filter_label=*/std::nullopt);
entry.pushKV("details", std::move(details)); entry.pushKV("details", std::move(details));
entry.pushKV("hex", EncodeHexTx(*wtx.tx)); entry.pushKV("hex", EncodeHexTx(*wtx.tx));

View File

@@ -525,8 +525,6 @@ RPCHelpMan simulaterawtransaction()
LOCK(wallet.cs_wallet); LOCK(wallet.cs_wallet);
isminefilter filter = ISMINE_SPENDABLE;
const auto& txs = request.params[0].get_array(); const auto& txs = request.params[0].get_array();
CAmount changes{0}; CAmount changes{0};
std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array
@@ -559,7 +557,7 @@ RPCHelpMan simulaterawtransaction()
if (coins.at(outpoint).IsSpent()) { if (coins.at(outpoint).IsSpent()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already"); throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");
} }
changes -= wallet.GetDebit(txin, filter); changes -= wallet.GetDebit(txin);
} }
spent.insert(outpoint); spent.insert(outpoint);
} }
@@ -572,7 +570,7 @@ RPCHelpMan simulaterawtransaction()
const auto& hash = mtx.GetHash(); const auto& hash = mtx.GetHash();
for (size_t i = 0; i < mtx.vout.size(); ++i) { for (size_t i = 0; i < mtx.vout.size(); ++i) {
const auto& txout = mtx.vout[i]; const auto& txout = mtx.vout[i];
bool is_mine = 0 < (wallet.IsMine(txout) & filter); bool is_mine = wallet.IsMine(txout);
changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0; changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
} }
} }

View File

@@ -197,15 +197,15 @@ IsMineResult LegacyWalletIsMineInnerDONOTUSE(const LegacyDataSPKM& keystore, con
} // namespace } // namespace
isminetype LegacyDataSPKM::IsMine(const CScript& script) const bool LegacyDataSPKM::IsMine(const CScript& script) const
{ {
switch (LegacyWalletIsMineInnerDONOTUSE(*this, script, IsMineSigVersion::TOP)) { switch (LegacyWalletIsMineInnerDONOTUSE(*this, script, IsMineSigVersion::TOP)) {
case IsMineResult::INVALID: case IsMineResult::INVALID:
case IsMineResult::NO: case IsMineResult::NO:
return ISMINE_NO; return false;
case IsMineResult::WATCH_ONLY: case IsMineResult::WATCH_ONLY:
case IsMineResult::SPENDABLE: case IsMineResult::SPENDABLE:
return ISMINE_SPENDABLE; return true;
} }
assert(false); assert(false);
} }
@@ -506,12 +506,12 @@ std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetCandidateScriptP
std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys() const std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetScriptPubKeys() const
{ {
// Run IsMine() on each candidate output script. Any script that is not ISMINE_NO is an output // Run IsMine() on each candidate output script. Any script that IsMine is an output
// script to return. // script to return.
// This both filters out things that are not watched by the wallet, and things that are invalid. // This both filters out things that are not watched by the wallet, and things that are invalid.
std::unordered_set<CScript, SaltedSipHasher> spks; std::unordered_set<CScript, SaltedSipHasher> spks;
for (const CScript& script : GetCandidateScriptPubKeys()) { for (const CScript& script : GetCandidateScriptPubKeys()) {
if (IsMine(script) != ISMINE_NO) { if (IsMine(script)) {
spks.insert(script); spks.insert(script);
} }
} }
@@ -524,7 +524,7 @@ std::unordered_set<CScript, SaltedSipHasher> LegacyDataSPKM::GetNotMineScriptPub
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
std::unordered_set<CScript, SaltedSipHasher> spks; std::unordered_set<CScript, SaltedSipHasher> spks;
for (const CScript& script : setWatchOnly) { for (const CScript& script : setWatchOnly) {
if (IsMine(script) == ISMINE_NO) spks.insert(script); if (!IsMine(script)) spks.insert(script);
} }
return spks; return spks;
} }
@@ -612,7 +612,7 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
for (const CScript& spk : desc_spks) { for (const CScript& spk : desc_spks) {
size_t erased = spks.erase(spk); size_t erased = spks.erase(spk);
assert(erased == 1); assert(erased == 1);
assert(IsMine(spk) == ISMINE_SPENDABLE); assert(IsMine(spk));
} }
out.desc_spkms.push_back(std::move(desc_spk_man)); out.desc_spkms.push_back(std::move(desc_spk_man));
@@ -661,7 +661,7 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
for (const CScript& spk : desc_spks) { for (const CScript& spk : desc_spks) {
size_t erased = spks.erase(spk); size_t erased = spks.erase(spk);
assert(erased == 1); assert(erased == 1);
assert(IsMine(spk) == ISMINE_SPENDABLE); assert(IsMine(spk));
} }
out.desc_spkms.push_back(std::move(desc_spk_man)); out.desc_spkms.push_back(std::move(desc_spk_man));
@@ -748,7 +748,7 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
for (const CScript& desc_spk : desc_spks) { for (const CScript& desc_spk : desc_spks) {
auto del_it = spks.find(desc_spk); auto del_it = spks.find(desc_spk);
assert(del_it != spks.end()); assert(del_it != spks.end());
assert(IsMine(desc_spk) != ISMINE_NO); assert(IsMine(desc_spk));
it = spks.erase(del_it); it = spks.erase(del_it);
} }
} }
@@ -762,14 +762,14 @@ std::optional<MigrationData> LegacyDataSPKM::MigrateToDescriptor()
// Legacy wallets can also contain scripts whose P2SH, P2WSH, or P2SH-P2WSH it is not watching for // Legacy wallets can also contain scripts whose P2SH, P2WSH, or P2SH-P2WSH it is not watching for
// but can provide script data to a PSBT spending them. These "solvable" output scripts will need to // but can provide script data to a PSBT spending them. These "solvable" output scripts will need to
// be put into the separate "solvables" wallet. // be put into the separate "solvables" wallet.
// These can be detected by going through the entire candidate output scripts, finding the ISMINE_NO scripts, // These can be detected by going through the entire candidate output scripts, finding the not IsMine scripts,
// and checking CanProvide() which will dummy sign. // and checking CanProvide() which will dummy sign.
for (const CScript& script : GetCandidateScriptPubKeys()) { for (const CScript& script : GetCandidateScriptPubKeys()) {
// Since we only care about P2SH, P2WSH, and P2SH-P2WSH, filter out any scripts that are not those // Since we only care about P2SH, P2WSH, and P2SH-P2WSH, filter out any scripts that are not those
if (!script.IsPayToScriptHash() && !script.IsPayToWitnessScriptHash()) { if (!script.IsPayToScriptHash() && !script.IsPayToWitnessScriptHash()) {
continue; continue;
} }
if (IsMine(script) != ISMINE_NO) { if (IsMine(script)) {
continue; continue;
} }
SignatureData dummy_sigdata; SignatureData dummy_sigdata;
@@ -861,13 +861,10 @@ util::Result<CTxDestination> DescriptorScriptPubKeyMan::GetNewDestination(const
} }
} }
isminetype DescriptorScriptPubKeyMan::IsMine(const CScript& script) const bool DescriptorScriptPubKeyMan::IsMine(const CScript& script) const
{ {
LOCK(cs_desc_man); LOCK(cs_desc_man);
if (m_map_script_pub_keys.count(script) > 0) { return m_map_script_pub_keys.contains(script);
return ISMINE_SPENDABLE;
}
return ISMINE_NO;
} }
bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key) bool DescriptorScriptPubKeyMan::CheckDecryptionKey(const CKeyingMaterial& master_key)

View File

@@ -85,7 +85,7 @@ public:
explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}
virtual ~ScriptPubKeyMan() = default; virtual ~ScriptPubKeyMan() = default;
virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; } virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; }
virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; } virtual bool IsMine(const CScript& script) const { return false; }
//! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it. //! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it.
virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key) { return false; } virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key) { return false; }
@@ -197,7 +197,7 @@ private:
// Used only in migration. // Used only in migration.
std::unordered_set<CScript, SaltedSipHasher> GetCandidateScriptPubKeys() const; std::unordered_set<CScript, SaltedSipHasher> GetCandidateScriptPubKeys() const;
isminetype IsMine(const CScript& script) const override; bool IsMine(const CScript& script) const override;
bool CanProvide(const CScript& script, SignatureData& sigdata) override; bool CanProvide(const CScript& script, SignatureData& sigdata) override;
public: public:
using ScriptPubKeyMan::ScriptPubKeyMan; using ScriptPubKeyMan::ScriptPubKeyMan;
@@ -324,7 +324,7 @@ public:
mutable RecursiveMutex cs_desc_man; mutable RecursiveMutex cs_desc_man;
util::Result<CTxDestination> GetNewDestination(const OutputType type) override; util::Result<CTxDestination> GetNewDestination(const OutputType type) override;
isminetype IsMine(const CScript& script) const override; bool IsMine(const CScript& script) const override;
bool CheckDecryptionKey(const CKeyingMaterial& master_key) override; bool CheckDecryptionKey(const CKeyingMaterial& master_key) override;
bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override; bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) override;

View File

@@ -437,14 +437,11 @@ CoinsResult AvailableCoins(const CWallet& wallet,
if (wallet.IsSpent(outpoint)) if (wallet.IsSpent(outpoint))
continue; continue;
isminetype mine = wallet.IsMine(output);
assert(mine != ISMINE_NO);
if (!allow_used_addresses && wallet.IsSpentKey(output.scriptPubKey)) { if (!allow_used_addresses && wallet.IsSpentKey(output.scriptPubKey)) {
continue; continue;
} }
bool tx_from_me = CachedTxIsFromMe(wallet, wtx, ISMINE_ALL); bool tx_from_me = CachedTxIsFromMe(wallet, wtx);
std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider(output.scriptPubKey); std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider(output.scriptPubKey);

View File

@@ -124,15 +124,14 @@ FUZZ_TARGET(scriptpubkeyman, .init = initialize_spkm)
fuzzed_data_provider, fuzzed_data_provider,
[&] { [&] {
const CScript script{ConsumeScript(fuzzed_data_provider)}; const CScript script{ConsumeScript(fuzzed_data_provider)};
auto is_mine{spk_manager->IsMine(script)}; if (spk_manager->IsMine(script)) {
if (is_mine == isminetype::ISMINE_SPENDABLE) {
assert(spk_manager->GetScriptPubKeys().count(script)); assert(spk_manager->GetScriptPubKeys().count(script));
} }
}, },
[&] { [&] {
auto spks{spk_manager->GetScriptPubKeys()}; auto spks{spk_manager->GetScriptPubKeys()};
for (const CScript& spk : spks) { for (const CScript& spk : spks) {
assert(spk_manager->IsMine(spk) == ISMINE_SPENDABLE); assert(spk_manager->IsMine(spk));
CTxDestination dest; CTxDestination dest;
bool extract_dest{ExtractDestination(spk, dest)}; bool extract_dest{ExtractDestination(spk, dest)};
if (extract_dest) { if (extract_dest) {

View File

@@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
std::unique_ptr<interfaces::Chain>& chain = m_node.chain; std::unique_ptr<interfaces::Chain>& chain = m_node.chain;
CScript scriptPubKey; CScript scriptPubKey;
isminetype result; bool result;
// P2PK compressed - Descriptor // P2PK compressed - Descriptor
{ {
@@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForRawPubKey(pubkeys[0]); scriptPubKey = GetScriptForRawPubKey(pubkeys[0]);
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2PK uncompressed - Descriptor // P2PK uncompressed - Descriptor
@@ -57,7 +57,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey); scriptPubKey = GetScriptForRawPubKey(uncompressedPubkey);
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2PKH compressed - Descriptor // P2PKH compressed - Descriptor
@@ -69,7 +69,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0])); scriptPubKey = GetScriptForDestination(PKHash(pubkeys[0]));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2PKH uncompressed - Descriptor // P2PKH uncompressed - Descriptor
@@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey)); scriptPubKey = GetScriptForDestination(PKHash(uncompressedPubkey));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2SH - Descriptor // P2SH - Descriptor
@@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor // (P2PKH inside) P2SH inside P2SH (invalid) - Descriptor
@@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2WPKH uncompressed (invalid) - Descriptor // P2WPKH uncompressed (invalid) - Descriptor
@@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); scriptPubKey = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2SH multisig - Descriptor // P2SH multisig - Descriptor
@@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]}); CScript redeemScript = GetScriptForMultisig(2, {uncompressedPubkey, pubkeys[1]});
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2WSH multisig with compressed keys - Descriptor // P2WSH multisig with compressed keys - Descriptor
@@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]}); CScript redeemScript = GetScriptForMultisig(2, {pubkeys[0], pubkeys[1]});
scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// P2WSH multisig with uncompressed key (invalid) - Descriptor // P2WSH multisig with uncompressed key (invalid) - Descriptor
@@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript)); CScript redeemScript = GetScriptForDestination(WitnessV0ScriptHash(witnessScript));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
// Combo - Descriptor // Combo - Descriptor
@@ -229,28 +229,28 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
// Test P2PK // Test P2PK
result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0])); result = spk_manager->IsMine(GetScriptForRawPubKey(pubkeys[0]));
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
// Test P2PKH // Test P2PKH
result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0]))); result = spk_manager->IsMine(GetScriptForDestination(PKHash(pubkeys[0])));
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
// Test P2SH (combo descriptor does not describe P2SH) // Test P2SH (combo descriptor does not describe P2SH)
CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0])); CScript redeemScript = GetScriptForDestination(PKHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO); BOOST_CHECK(!result);
// Test P2WPKH // Test P2WPKH
scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
// P2SH-P2WPKH output // P2SH-P2WPKH output
redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0])); redeemScript = GetScriptForDestination(WitnessV0KeyHash(pubkeys[0]));
scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript)); scriptPubKey = GetScriptForDestination(ScriptHash(redeemScript));
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
// Test P2TR (combo descriptor does not describe P2TR) // Test P2TR (combo descriptor does not describe P2TR)
XOnlyPubKey xpk(pubkeys[0]); XOnlyPubKey xpk(pubkeys[0]);
@@ -260,7 +260,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
WitnessV1Taproot output = builder.GetOutput(); WitnessV1Taproot output = builder.GetOutput();
scriptPubKey = GetScriptForDestination(output); scriptPubKey = GetScriptForDestination(output);
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_NO); BOOST_CHECK(!result);
} }
// Taproot - Descriptor // Taproot - Descriptor
@@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(ismine_standard)
WitnessV1Taproot output = builder.GetOutput(); WitnessV1Taproot output = builder.GetOutput();
scriptPubKey = GetScriptForDestination(output); scriptPubKey = GetScriptForDestination(output);
result = spk_manager->IsMine(scriptPubKey); result = spk_manager->IsMine(scriptPubKey);
BOOST_CHECK_EQUAL(result, ISMINE_SPENDABLE); BOOST_CHECK(result);
} }
} }

View File

@@ -388,13 +388,11 @@ class WalletTXO
private: private:
const CWalletTx& m_wtx; const CWalletTx& m_wtx;
const CTxOut& m_output; const CTxOut& m_output;
isminetype m_ismine;
public: public:
WalletTXO(const CWalletTx& wtx, const CTxOut& output, const isminetype ismine) WalletTXO(const CWalletTx& wtx, const CTxOut& output)
: m_wtx(wtx), : m_wtx(wtx),
m_output(output), m_output(output)
m_ismine(ismine)
{ {
Assume(std::ranges::find(wtx.tx->vout, output) != wtx.tx->vout.end()); Assume(std::ranges::find(wtx.tx->vout, output) != wtx.tx->vout.end());
} }
@@ -402,9 +400,6 @@ public:
const CWalletTx& GetWalletTx() const { return m_wtx; } const CWalletTx& GetWalletTx() const { return m_wtx; }
const CTxOut& GetTxOut() const { return m_output; } const CTxOut& GetTxOut() const { return m_output; }
isminetype GetIsMine() const { return m_ismine; }
void SetIsMine(isminetype ismine) { m_ismine = ismine; }
}; };
} // namespace wallet } // namespace wallet

View File

@@ -17,32 +17,6 @@
#include <type_traits> #include <type_traits>
namespace wallet { namespace wallet {
/**
* IsMine() return codes, which depend on ScriptPubKeyMan implementation.
* Not every ScriptPubKeyMan covers all types, please refer to
* https://github.com/bitcoin/bitcoin/blob/master/doc/release-notes/release-notes-0.21.0.md#ismine-semantics
* for better understanding.
*
* For LegacyScriptPubKeyMan,
* ISMINE_NO: the scriptPubKey is not in the wallet;
* ISMINE_SPENDABLE: the scriptPubKey corresponds to an address owned by the wallet user (can spend with the private key);
* ISMINE_ALL: all ISMINE flags except for USED;
* ISMINE_ENUM_ELEMENTS: the number of isminetype enum elements.
*
* For DescriptorScriptPubKeyMan and future ScriptPubKeyMan,
* ISMINE_NO: the scriptPubKey is not in the wallet;
* ISMINE_SPENDABLE: the scriptPubKey matches a scriptPubKey in the wallet.
*
*/
enum isminetype : unsigned int {
ISMINE_NO = 0,
ISMINE_SPENDABLE = 1 << 1,
ISMINE_ALL = ISMINE_SPENDABLE,
ISMINE_ENUM_ELEMENTS,
};
/** used for bitflags of isminetype */
using isminefilter = std::underlying_type_t<isminetype>;
/** /**
* Address purpose field that has been been stored with wallet sending and * Address purpose field that has been been stored with wallet sending and
* receiving addresses since BIP70 payment protocol support was added in * receiving addresses since BIP70 payment protocol support was added in

View File

@@ -1569,45 +1569,45 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
} }
// Note that this function doesn't distinguish between a 0-valued input, // Note that this function doesn't distinguish between a 0-valued input,
// and a not-"is mine" (according to the filter) input. // and a not-"is mine" input.
CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const CAmount CWallet::GetDebit(const CTxIn &txin) const
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
auto txo = GetTXO(txin.prevout); auto txo = GetTXO(txin.prevout);
if (txo && (txo->GetIsMine() & filter)) { if (txo) {
return txo->GetTxOut().nValue; return txo->GetTxOut().nValue;
} }
return 0; return 0;
} }
isminetype CWallet::IsMine(const CTxOut& txout) const bool CWallet::IsMine(const CTxOut& txout) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
return IsMine(txout.scriptPubKey); return IsMine(txout.scriptPubKey);
} }
isminetype CWallet::IsMine(const CTxDestination& dest) const bool CWallet::IsMine(const CTxDestination& dest) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
return IsMine(GetScriptForDestination(dest)); return IsMine(GetScriptForDestination(dest));
} }
isminetype CWallet::IsMine(const CScript& script) const bool CWallet::IsMine(const CScript& script) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
// Search the cache so that IsMine is called only on the relevant SPKMs instead of on everything in m_spk_managers // Search the cache so that IsMine is called only on the relevant SPKMs instead of on everything in m_spk_managers
const auto& it = m_cached_spks.find(script); const auto& it = m_cached_spks.find(script);
if (it != m_cached_spks.end()) { if (it != m_cached_spks.end()) {
isminetype res = ISMINE_NO; bool res = false;
for (const auto& spkm : it->second) { for (const auto& spkm : it->second) {
res = std::max(res, spkm->IsMine(script)); res = res || spkm->IsMine(script);
} }
Assume(res == ISMINE_SPENDABLE); Assume(res);
return res; return res;
} }
return ISMINE_NO; return false;
} }
bool CWallet::IsMine(const CTransaction& tx) const bool CWallet::IsMine(const CTransaction& tx) const
@@ -1619,30 +1619,30 @@ bool CWallet::IsMine(const CTransaction& tx) const
return false; return false;
} }
isminetype CWallet::IsMine(const COutPoint& outpoint) const bool CWallet::IsMine(const COutPoint& outpoint) const
{ {
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
auto wtx = GetWalletTx(outpoint.hash); auto wtx = GetWalletTx(outpoint.hash);
if (!wtx) { if (!wtx) {
return ISMINE_NO; return false;
} }
if (outpoint.n >= wtx->tx->vout.size()) { if (outpoint.n >= wtx->tx->vout.size()) {
return ISMINE_NO; return false;
} }
return IsMine(wtx->tx->vout[outpoint.n]); return IsMine(wtx->tx->vout[outpoint.n]);
} }
bool CWallet::IsFromMe(const CTransaction& tx) const bool CWallet::IsFromMe(const CTransaction& tx) const
{ {
return (GetDebit(tx, ISMINE_ALL) > 0); return (GetDebit(tx) > 0);
} }
CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const CAmount CWallet::GetDebit(const CTransaction& tx) const
{ {
CAmount nDebit = 0; CAmount nDebit = 0;
for (const CTxIn& txin : tx.vin) for (const CTxIn& txin : tx.vin)
{ {
nDebit += GetDebit(txin, filter); nDebit += GetDebit(txin);
if (!MoneyRange(nDebit)) if (!MoneyRange(nDebit))
throw std::runtime_error(std::string(__func__) + ": value out of range"); throw std::runtime_error(std::string(__func__) + ": value out of range");
} }
@@ -2377,7 +2377,7 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address]; CAddressBookData& record = mi != m_address_book.end() ? mi->second : m_address_book[address];
record.SetLabel(strName); record.SetLabel(strName);
is_mine = IsMine(address) != ISMINE_NO; is_mine = IsMine(address);
if (new_purpose) { /* update purpose only if requested */ if (new_purpose) { /* update purpose only if requested */
record.purpose = new_purpose; record.purpose = new_purpose;
} }
@@ -4444,15 +4444,11 @@ void CWallet::RefreshTXOsFromTx(const CWalletTx& wtx)
AssertLockHeld(cs_wallet); AssertLockHeld(cs_wallet);
for (uint32_t i = 0; i < wtx.tx->vout.size(); ++i) { for (uint32_t i = 0; i < wtx.tx->vout.size(); ++i) {
const CTxOut& txout = wtx.tx->vout.at(i); const CTxOut& txout = wtx.tx->vout.at(i);
isminetype ismine = IsMine(txout); if (!IsMine(txout)) continue;
if (ismine == ISMINE_NO) {
continue;
}
COutPoint outpoint(wtx.GetHash(), i); COutPoint outpoint(wtx.GetHash(), i);
if (m_txos.contains(outpoint)) { if (m_txos.contains(outpoint)) {
m_txos.at(outpoint).SetIsMine(ismine);
} else { } else {
m_txos.emplace(outpoint, WalletTXO{wtx, txout, ismine}); m_txos.emplace(outpoint, WalletTXO{wtx, txout});
} }
} }
} }

View File

@@ -786,19 +786,16 @@ public:
util::Result<CTxDestination> GetNewDestination(const OutputType type, const std::string label); util::Result<CTxDestination> GetNewDestination(const OutputType type, const std::string label);
util::Result<CTxDestination> GetNewChangeDestination(const OutputType type); util::Result<CTxDestination> GetNewChangeDestination(const OutputType type);
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** /** Returns amount of debit, i.e. the amount leaving this wallet due to this input */
* Returns amount of debit if the input matches the CAmount GetDebit(const CTxIn& txin) const;
* filter, otherwise returns 0 bool IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
*/
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
isminetype IsMine(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool IsMine(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** should probably be renamed to IsRelevantToMe */ /** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const; bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetDebit(const CTransaction& tx) const;
DBErrors LoadWallet(); DBErrors LoadWallet();