Merge bitcoin/bitcoin#32523: wallet: Remove isminetypes
be776a1443wallet: Remove isminetype (Ava Chow)009a69a616wallet: Remove ISMINE_USED (Ava Chow)6a7aa01574wallet: Remove COutput::spendable and AvailableCoinsListUnspent (Ava Chow)620abe985einterfaces, gui: Remove is_mine output parameter from getAddress (Ava Chow) Pull request description: The remaining isminetypes are `ISMINE_SPENDABLE` and `ISMINE_USED`. `ISMINE_USED` is only used as a filter for caching balances and is never actually returned from `IsMine`. Since we do still want this behavior, This PR changes the caching to utilize bools and explicit members variables to account for the avoid_reuse case. This allows us to remove `ISMINE_USED`. `ISMINE_SPENDABLE` and `ISMINE_NO` are the only things that are returned by `IsMine`. This is a bool, so it can be replaced as such. After removing `ISMINE_USED` and `ISMINE_SPENDABLE`, we are able to remove isminetypes altogether. ACKs for top commit: murchandamus: ACKbe776a1443fjahr: reACKbe776a1443davidgumberg: crACK https://github.com/bitcoin/bitcoin/commit/be776a1443fdf1a72e0d363c1566d71cb0cda8b5 enirox001: re-ACKbe776a1jlest01: reACK https://github.com/bitcoin/bitcoin/pull/32523/commits/be776a1443fdf1a72e0d363c1566d71cb0cda8b5 Tree-SHA512: 689759f6a6ba20a1ae988b0c3abacb15424844f29a1ec2fcb2d1ca9d87b44ae68313e8f61d6fd310281b681144f0ade67e90fcfab807e982b52ed99441d9c987
This commit is contained in:
32 files changed
+226
-348
No files matched your search
@@ -74,7 +74,7 @@ static void CoinSelection(benchmark::Bench& bench)
|
|||||||
wallet::CoinsResult available_coins;
|
wallet::CoinsResult available_coins;
|
||||||
for (const auto& wtx : wtxs) {
|
for (const auto& wtx : wtxs) {
|
||||||
const auto txout = wtx->tx->vout.at(0);
|
const auto txout = wtx->tx->vout.at(0);
|
||||||
available_coins.coins[OutputType::BECH32].emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
|
available_coins.coins[OutputType::BECH32].emplace_back(COutPoint(wtx->GetHash(), 0), txout, /*depth=*/6 * 24, CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr), /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CoinEligibilityFilter filter_standard(1, 6, 0);
|
const CoinEligibilityFilter filter_standard(1, 6, 0);
|
||||||
@@ -105,7 +105,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>
|
|||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
tx.vout.resize(nInput + 1);
|
tx.vout.resize(nInput + 1);
|
||||||
tx.vout[nInput].nValue = nValue;
|
tx.vout[nInput].nValue = nValue;
|
||||||
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 0, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ true, /*fees=*/ 0);
|
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/0, /*input_bytes=*/-1, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/true, /*fees=*/0);
|
||||||
set.emplace_back();
|
set.emplace_back();
|
||||||
set.back().Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
|
set.back().Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
+9
-12
@@ -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 {
|
||||||
@@ -117,7 +115,6 @@ public:
|
|||||||
//! Look up address in wallet, return whether exists.
|
//! Look up address in wallet, return whether exists.
|
||||||
virtual bool getAddress(const CTxDestination& dest,
|
virtual bool getAddress(const CTxDestination& dest,
|
||||||
std::string* name,
|
std::string* name,
|
||||||
wallet::isminetype* is_mine,
|
|
||||||
wallet::AddressPurpose* purpose) = 0;
|
wallet::AddressPurpose* purpose) = 0;
|
||||||
|
|
||||||
//! Get wallet address list.
|
//! Get wallet address list.
|
||||||
@@ -225,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)
|
||||||
@@ -356,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))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -384,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;
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ bool AddressTableModel::setData(const QModelIndex &index, const QVariant &value,
|
|||||||
// Check for duplicate addresses to prevent accidental deletion of addresses, if you try
|
// Check for duplicate addresses to prevent accidental deletion of addresses, if you try
|
||||||
// to paste an existing address over another address (with a different label)
|
// to paste an existing address over another address (with a different label)
|
||||||
if (walletModel->wallet().getAddress(
|
if (walletModel->wallet().getAddress(
|
||||||
newAddress, /* name= */ nullptr, /* is_mine= */ nullptr, /* purpose= */ nullptr))
|
newAddress, /*name=*/nullptr, /*purpose=*/ nullptr))
|
||||||
{
|
{
|
||||||
editStatus = DUPLICATE_ADDRESS;
|
editStatus = DUPLICATE_ADDRESS;
|
||||||
return false;
|
return false;
|
||||||
@@ -356,7 +356,7 @@ QString AddressTableModel::addRow(const QString &type, const QString &label, con
|
|||||||
// Check for duplicate addresses
|
// Check for duplicate addresses
|
||||||
{
|
{
|
||||||
if (walletModel->wallet().getAddress(
|
if (walletModel->wallet().getAddress(
|
||||||
DecodeDestination(strAddress), /* name= */ nullptr, /* is_mine= */ nullptr, /* purpose= */ nullptr))
|
DecodeDestination(strAddress), /*name=*/nullptr, /*purpose=*/nullptr))
|
||||||
{
|
{
|
||||||
editStatus = DUPLICATE_ADDRESS;
|
editStatus = DUPLICATE_ADDRESS;
|
||||||
return QString();
|
return QString();
|
||||||
@@ -429,7 +429,7 @@ bool AddressTableModel::getAddressData(const QString &address,
|
|||||||
std::string* name,
|
std::string* name,
|
||||||
wallet::AddressPurpose* purpose) const {
|
wallet::AddressPurpose* purpose) const {
|
||||||
CTxDestination destination = DecodeDestination(address.toStdString());
|
CTxDestination destination = DecodeDestination(address.toStdString());
|
||||||
return walletModel->wallet().getAddress(destination, name, /* is_mine= */ nullptr, purpose);
|
return walletModel->wallet().getAddress(destination, name, purpose);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AddressTableModel::lookupAddress(const QString &address) const
|
int AddressTableModel::lookupAddress(const QString &address) const
|
||||||
|
|||||||
+17
-32
@@ -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;
|
||||||
@@ -143,8 +138,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
|||||||
CTxDestination address = DecodeDestination(rec->address);
|
CTxDestination address = DecodeDestination(rec->address);
|
||||||
if (IsValidDestination(address)) {
|
if (IsValidDestination(address)) {
|
||||||
std::string name;
|
std::string name;
|
||||||
isminetype ismine;
|
if (wallet.getAddress(address, &name, /*purpose=*/nullptr))
|
||||||
if (wallet.getAddress(address, &name, &ismine, /* purpose= */ nullptr))
|
|
||||||
{
|
{
|
||||||
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
|
strHTML += "<b>" + tr("From") + ":</b> " + tr("unknown") + "<br>";
|
||||||
strHTML += "<b>" + tr("To") + ":</b> ";
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
||||||
@@ -171,7 +165,7 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
|||||||
CTxDestination dest = DecodeDestination(strAddress);
|
CTxDestination dest = DecodeDestination(strAddress);
|
||||||
std::string name;
|
std::string name;
|
||||||
if (wallet.getAddress(
|
if (wallet.getAddress(
|
||||||
dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
|
dest, &name, /*purpose=*/nullptr) && !name.empty())
|
||||||
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
||||||
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
|
strHTML += GUIUtil::HtmlEscape(strAddress) + "<br>";
|
||||||
}
|
}
|
||||||
@@ -186,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) + ")";
|
||||||
@@ -203,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
|
||||||
//
|
//
|
||||||
@@ -223,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())
|
||||||
@@ -236,10 +221,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
|||||||
strHTML += "<b>" + tr("To") + ":</b> ";
|
strHTML += "<b>" + tr("To") + ":</b> ";
|
||||||
std::string name;
|
std::string name;
|
||||||
if (wallet.getAddress(
|
if (wallet.getAddress(
|
||||||
address, &name, /* is_mine= */ nullptr, /* 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>";
|
||||||
}
|
}
|
||||||
@@ -250,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;
|
||||||
@@ -271,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>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,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);
|
||||||
@@ -357,12 +342,12 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
|
|||||||
if (ExtractDestination(vout.scriptPubKey, address))
|
if (ExtractDestination(vout.scriptPubKey, address))
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
if (wallet.getAddress(address, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr) && !name.empty())
|
if (wallet.getAddress(address, &name, /*purpose=*/nullptr) && !name.empty())
|
||||||
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
strHTML += GUIUtil::HtmlEscape(name) + " ";
|
||||||
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>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ void WalletModel::sendCoins(WalletModelTransaction& transaction)
|
|||||||
// Check if we have a new address or an updated label
|
// Check if we have a new address or an updated label
|
||||||
std::string name;
|
std::string name;
|
||||||
if (!m_wallet->getAddress(
|
if (!m_wallet->getAddress(
|
||||||
dest, &name, /* is_mine= */ nullptr, /* purpose= */ nullptr))
|
dest, &name, /*purpose=*/nullptr))
|
||||||
{
|
{
|
||||||
m_wallet->setAddressBook(dest, strLabel, wallet::AddressPurpose::SEND);
|
m_wallet->setAddressBook(dest, strLabel, wallet::AddressPurpose::SEND);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ public:
|
|||||||
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
|
/** Pre-computed estimated size of this output as a fully-signed input in a transaction. Can be -1 if it could not be calculated */
|
||||||
int input_bytes;
|
int input_bytes;
|
||||||
|
|
||||||
/** Whether we have the private keys to spend this output */
|
|
||||||
bool spendable;
|
|
||||||
|
|
||||||
/** Whether we know how to spend this output, ignoring the lack of keys */
|
/** Whether we know how to spend this output, ignoring the lack of keys */
|
||||||
bool solvable;
|
bool solvable;
|
||||||
|
|
||||||
@@ -75,12 +72,11 @@ public:
|
|||||||
/** The fee necessary to bump this UTXO's ancestor transactions to the target feerate */
|
/** The fee necessary to bump this UTXO's ancestor transactions to the target feerate */
|
||||||
CAmount ancestor_bump_fees{0};
|
CAmount ancestor_bump_fees{0};
|
||||||
|
|
||||||
COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool spendable, bool solvable, bool safe, int64_t time, bool from_me, const std::optional<CFeeRate> feerate = std::nullopt)
|
COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const std::optional<CFeeRate> feerate = std::nullopt)
|
||||||
: outpoint{outpoint},
|
: outpoint{outpoint},
|
||||||
txout{txout},
|
txout{txout},
|
||||||
depth{depth},
|
depth{depth},
|
||||||
input_bytes{input_bytes},
|
input_bytes{input_bytes},
|
||||||
spendable{spendable},
|
|
||||||
solvable{solvable},
|
solvable{solvable},
|
||||||
safe{safe},
|
safe{safe},
|
||||||
time{time},
|
time{time},
|
||||||
@@ -93,8 +89,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool spendable, bool solvable, bool safe, int64_t time, bool from_me, const CAmount fees)
|
COutput(const COutPoint& outpoint, const CTxOut& txout, int depth, int input_bytes, bool solvable, bool safe, int64_t time, bool from_me, const CAmount fees)
|
||||||
: COutput(outpoint, txout, depth, input_bytes, spendable, solvable, safe, time, from_me)
|
: COutput(outpoint, txout, depth, input_bytes, solvable, safe, time, from_me)
|
||||||
{
|
{
|
||||||
// if input_bytes is unknown, then fees should be 0, if input_bytes is known, then the fees should be a positive integer or 0 (input_bytes known and fees = 0 only happens in the tests)
|
// if input_bytes is unknown, then fees should be 0, if input_bytes is known, then the fees should be a positive integer or 0 (input_bytes known and fees = 0 only happens in the tests)
|
||||||
assert((input_bytes < 0 && fees == 0) || (input_bytes > 0 && fees >= 0));
|
assert((input_bytes < 0 && fees == 0) || (input_bytes > 0 && fees >= 0));
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-21
@@ -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);
|
result.credit = CachedTxGetCredit(wallet, wtx, /*avoid_reuse=*/true);
|
||||||
result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL);
|
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
|
||||||
{
|
{
|
||||||
@@ -185,7 +184,6 @@ public:
|
|||||||
}
|
}
|
||||||
bool getAddress(const CTxDestination& dest,
|
bool getAddress(const CTxDestination& dest,
|
||||||
std::string* name,
|
std::string* name,
|
||||||
isminetype* is_mine,
|
|
||||||
AddressPurpose* purpose) override
|
AddressPurpose* purpose) override
|
||||||
{
|
{
|
||||||
LOCK(m_wallet->cs_wallet);
|
LOCK(m_wallet->cs_wallet);
|
||||||
@@ -194,16 +192,9 @@ public:
|
|||||||
if (name) {
|
if (name) {
|
||||||
*name = entry->GetLabel();
|
*name = entry->GetLabel();
|
||||||
}
|
}
|
||||||
std::optional<isminetype> dest_is_mine;
|
|
||||||
if (is_mine || purpose) {
|
|
||||||
dest_is_mine = m_wallet->IsMine(dest);
|
|
||||||
}
|
|
||||||
if (is_mine) {
|
|
||||||
*is_mine = *dest_is_mine;
|
|
||||||
}
|
|
||||||
if (purpose) {
|
if (purpose) {
|
||||||
// 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
|
||||||
*purpose = entry->purpose.value_or(*dest_is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND);
|
*purpose = entry->purpose.value_or(m_wallet->IsMine(dest) ? AddressPurpose::RECEIVE : AddressPurpose::SEND);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -213,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);
|
||||||
});
|
});
|
||||||
@@ -431,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
|
||||||
{
|
{
|
||||||
|
|||||||
+28
-44
@@ -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)
|
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.m_cached[filter]) {
|
if (!amount.IsCached(avoid_reuse)) {
|
||||||
amount.Set(filter, 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.m_value[filter];
|
return amount.Get(avoid_reuse);
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
|
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);
|
|
||||||
}
|
|
||||||
return credit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
|
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);
|
|
||||||
}
|
|
||||||
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);
|
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) > 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()));
|
||||||
|
|||||||
+9
-11
@@ -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)
|
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);
|
|
||||||
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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -498,7 +498,7 @@ RPCHelpMan listunspent()
|
|||||||
{RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"},
|
{RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"},
|
||||||
{RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeem script if the output script is P2SH"},
|
{RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeem script if the output script is P2SH"},
|
||||||
{RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witness script if the output script is P2WSH or P2SH-P2WSH"},
|
{RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witness script if the output script is P2WSH or P2SH-P2WSH"},
|
||||||
{RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
|
{RPCResult::Type::BOOL, "spendable", "(DEPRECATED) Always true"},
|
||||||
{RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
|
{RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
|
||||||
{RPCResult::Type::BOOL, "reused", /*optional=*/true, "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"},
|
{RPCResult::Type::BOOL, "reused", /*optional=*/true, "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"},
|
||||||
{RPCResult::Type::STR, "desc", /*optional=*/true, "(only when solvable) A descriptor for spending this output"},
|
{RPCResult::Type::STR, "desc", /*optional=*/true, "(only when solvable) A descriptor for spending this output"},
|
||||||
@@ -598,8 +598,9 @@ RPCHelpMan listunspent()
|
|||||||
cctl.m_min_depth = nMinDepth;
|
cctl.m_min_depth = nMinDepth;
|
||||||
cctl.m_max_depth = nMaxDepth;
|
cctl.m_max_depth = nMaxDepth;
|
||||||
cctl.m_include_unsafe_inputs = include_unsafe;
|
cctl.m_include_unsafe_inputs = include_unsafe;
|
||||||
|
filter_coins.check_version_trucness = false;
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
vecOutputs = AvailableCoinsListUnspent(*pwallet, &cctl, filter_coins).All();
|
vecOutputs = AvailableCoins(*pwallet, &cctl, /*feerate=*/std::nullopt, filter_coins).All();
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK(pwallet->cs_wallet);
|
LOCK(pwallet->cs_wallet);
|
||||||
@@ -672,7 +673,7 @@ RPCHelpMan listunspent()
|
|||||||
entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
|
entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entry.pushKV("spendable", out.spendable);
|
entry.pushKV("spendable", true); // Any coins we list are always spendable
|
||||||
entry.pushKV("solvable", out.solvable);
|
entry.pushKV("solvable", out.solvable);
|
||||||
if (out.solvable) {
|
if (out.solvable) {
|
||||||
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, /*avoid_reuse=*/false);
|
||||||
CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, filter);
|
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));
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+11
-28
@@ -309,8 +309,8 @@ util::Result<PreSelectedInputs> FetchSelectedInputs(const CWallet& wallet, const
|
|||||||
return util::Error{strprintf(_("Not solvable pre-selected input %s"), outpoint.ToString())}; // Not solvable, can't estimate size for fee
|
return util::Error{strprintf(_("Not solvable pre-selected input %s"), outpoint.ToString())}; // Not solvable, can't estimate size for fee
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set some defaults for depth, spendable, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
|
/* Set some defaults for depth, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
|
||||||
COutput output(outpoint, txout, /*depth=*/ 0, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, coin_selection_params.m_effective_feerate);
|
COutput output(outpoint, txout, /*depth=*/0, input_bytes, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, coin_selection_params.m_effective_feerate);
|
||||||
output.ApplyBumpFee(map_of_bump_fees.at(output.outpoint));
|
output.ApplyBumpFee(map_of_bump_fees.at(output.outpoint));
|
||||||
result.Insert(output, coin_selection_params.m_subtract_fee_outputs);
|
result.Insert(output, coin_selection_params.m_subtract_fee_outputs);
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -452,10 +449,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
|
|||||||
// Because CalculateMaximumSignedInputSize infers a solvable descriptor to get the satisfaction size,
|
// Because CalculateMaximumSignedInputSize infers a solvable descriptor to get the satisfaction size,
|
||||||
// it is safe to assume that this input is solvable if input_bytes is greater than -1.
|
// it is safe to assume that this input is solvable if input_bytes is greater than -1.
|
||||||
bool solvable = input_bytes > -1;
|
bool solvable = input_bytes > -1;
|
||||||
bool spendable = (mine & ISMINE_SPENDABLE) != ISMINE_NO;
|
|
||||||
|
|
||||||
// Filter by spendable outputs only
|
|
||||||
if (!spendable && params.only_spendable) continue;
|
|
||||||
|
|
||||||
// Obtain script type
|
// Obtain script type
|
||||||
std::vector<std::vector<uint8_t>> script_solutions;
|
std::vector<std::vector<uint8_t>> script_solutions;
|
||||||
@@ -474,7 +467,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto available_output_type = GetOutputType(type, is_from_p2sh);
|
auto available_output_type = GetOutputType(type, is_from_p2sh);
|
||||||
auto available_output = COutput(outpoint, output, nDepth, input_bytes, spendable, solvable, tx_safe, wtx.GetTxTime(), tx_from_me, feerate);
|
auto available_output = COutput(outpoint, output, nDepth, input_bytes, solvable, tx_safe, wtx.GetTxTime(), tx_from_me, feerate);
|
||||||
if (wtx.tx->version == TRUC_VERSION && nDepth == 0 && params.check_version_trucness) {
|
if (wtx.tx->version == TRUC_VERSION && nDepth == 0 && params.check_version_trucness) {
|
||||||
unconfirmed_truc_coins.emplace_back(available_output_type, available_output);
|
unconfirmed_truc_coins.emplace_back(available_output_type, available_output);
|
||||||
auto [it, _] = truc_txid_by_value.try_emplace(wtx.tx->GetHash(), 0);
|
auto [it, _] = truc_txid_by_value.try_emplace(wtx.tx->GetHash(), 0);
|
||||||
@@ -528,13 +521,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, CoinFilterParams params)
|
|
||||||
{
|
|
||||||
params.only_spendable = false;
|
|
||||||
params.check_version_trucness = false;
|
|
||||||
return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
|
const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
|
||||||
{
|
{
|
||||||
AssertLockHeld(wallet.cs_wallet);
|
AssertLockHeld(wallet.cs_wallet);
|
||||||
@@ -563,21 +549,18 @@ std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
|
|||||||
|
|
||||||
CCoinControl coin_control;
|
CCoinControl coin_control;
|
||||||
CoinFilterParams coins_params;
|
CoinFilterParams coins_params;
|
||||||
coins_params.only_spendable = false;
|
|
||||||
coins_params.skip_locked = false;
|
coins_params.skip_locked = false;
|
||||||
for (const COutput& coin : AvailableCoins(wallet, &coin_control, /*feerate=*/std::nullopt, coins_params).All()) {
|
for (const COutput& coin : AvailableCoins(wallet, &coin_control, /*feerate=*/std::nullopt, coins_params).All()) {
|
||||||
CTxDestination address;
|
CTxDestination address;
|
||||||
if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable))) {
|
if (!ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
|
||||||
if (!ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
|
// For backwards compatibility, we convert P2PK output scripts into PKHash destinations
|
||||||
// For backwards compatibility, we convert P2PK output scripts into PKHash destinations
|
if (auto pk_dest = std::get_if<PubKeyDestination>(&address)) {
|
||||||
if (auto pk_dest = std::get_if<PubKeyDestination>(&address)) {
|
address = PKHash(pk_dest->GetPubKey());
|
||||||
address = PKHash(pk_dest->GetPubKey());
|
} else {
|
||||||
} else {
|
continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
result[address].emplace_back(coin);
|
|
||||||
}
|
}
|
||||||
|
result[address].emplace_back(coin);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ struct CoinFilterParams {
|
|||||||
CAmount min_sum_amount{MAX_MONEY};
|
CAmount min_sum_amount{MAX_MONEY};
|
||||||
// Maximum number of outputs that can be returned
|
// Maximum number of outputs that can be returned
|
||||||
uint64_t max_count{0};
|
uint64_t max_count{0};
|
||||||
// By default, return only spendable outputs
|
|
||||||
bool only_spendable{true};
|
|
||||||
// By default, do not include immature coinbase outputs
|
// By default, do not include immature coinbase outputs
|
||||||
bool include_immature_coinbase{false};
|
bool include_immature_coinbase{false};
|
||||||
// By default, skip locked UTXOs
|
// By default, skip locked UTXOs
|
||||||
@@ -96,12 +94,6 @@ CoinsResult AvailableCoins(const CWallet& wallet,
|
|||||||
std::optional<CFeeRate> feerate = std::nullopt,
|
std::optional<CFeeRate> feerate = std::nullopt,
|
||||||
const CoinFilterParams& params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
const CoinFilterParams& params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper function for AvailableCoins which skips the `feerate` and `CoinFilterParams::only_spendable` parameters. Use this function
|
|
||||||
* to list all available coins (e.g. listunspent RPC) while not intending to fund a transaction.
|
|
||||||
*/
|
|
||||||
CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl = nullptr, CoinFilterParams params = {}) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find non-change parent output.
|
* Find non-change parent output.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ static OutputGroup MakeCoin(const CAmount& amount, bool is_eff_value = true, Coi
|
|||||||
tx.vout[0].nValue = amount + int(is_eff_value) * fees;
|
tx.vout[0].nValue = amount + int(is_eff_value) * fees;
|
||||||
tx.nLockTime = next_lock_time++; // so all transactions get different hashes
|
tx.nLockTime = next_lock_time++; // so all transactions get different hashes
|
||||||
OutputGroup group(cs_params);
|
OutputGroup group(cs_params);
|
||||||
group.Insert(std::make_shared<COutput>(COutPoint(tx.GetHash(), 0), tx.vout.at(0), /*depth=*/1, /*input_bytes=*/custom_spending_vsize, /*spendable=*/true, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, /*fees=*/fees), /*ancestors=*/0, /*descendants=*/0);
|
group.Insert(std::make_shared<COutput>(COutPoint(tx.GetHash(), 0), tx.vout.at(0), /*depth=*/1, /*input_bytes=*/custom_spending_vsize, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, /*fees=*/fees), /*ancestors=*/0, /*descendants=*/0);
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ static void add_coin(const CAmount& nValue, int nInput, SelectionResult& result)
|
|||||||
tx.vout.resize(nInput + 1);
|
tx.vout.resize(nInput + 1);
|
||||||
tx.vout[nInput].nValue = nValue;
|
tx.vout[nInput].nValue = nValue;
|
||||||
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
||||||
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, /*fees=*/ 0);
|
COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, /*input_bytes=*/-1, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, /*fees=*/ 0);
|
||||||
OutputGroup group;
|
OutputGroup group;
|
||||||
group.Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
|
group.Insert(std::make_shared<COutput>(output), /*ancestors=*/ 0, /*descendants=*/ 0);
|
||||||
result.AddInput(group);
|
result.AddInput(group);
|
||||||
@@ -55,7 +55,7 @@ static void add_coin(const CAmount& nValue, int nInput, SelectionResult& result,
|
|||||||
tx.vout.resize(nInput + 1);
|
tx.vout.resize(nInput + 1);
|
||||||
tx.vout[nInput].nValue = nValue;
|
tx.vout[nInput].nValue = nValue;
|
||||||
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
||||||
std::shared_ptr<COutput> coin = std::make_shared<COutput>(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ 148, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, fee);
|
std::shared_ptr<COutput> coin = std::make_shared<COutput>(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, /*input_bytes=*/148, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, fee);
|
||||||
OutputGroup group;
|
OutputGroup group;
|
||||||
group.Insert(coin, /*ancestors=*/ 0, /*descendants=*/ 0);
|
group.Insert(coin, /*ancestors=*/ 0, /*descendants=*/ 0);
|
||||||
coin->long_term_fee = long_term_fee; // group.Insert() will modify long_term_fee, so we need to set it afterwards
|
coin->long_term_fee = long_term_fee; // group.Insert() will modify long_term_fee, so we need to set it afterwards
|
||||||
@@ -78,7 +78,7 @@ static void add_coin(CoinsResult& available_coins, CWallet& wallet, const CAmoun
|
|||||||
assert(ret.second);
|
assert(ret.second);
|
||||||
CWalletTx& wtx = (*ret.first).second;
|
CWalletTx& wtx = (*ret.first).second;
|
||||||
const auto& txout = wtx.tx->vout.at(nInput);
|
const auto& txout = wtx.tx->vout.at(nInput);
|
||||||
available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, custom_size == 0 ? CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr) : custom_size, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, wtx.GetTxTime(), fIsFromMe, feerate});
|
available_coins.Add(OutputType::BECH32, {COutPoint(wtx.GetHash(), nInput), txout, nAge, custom_size == 0 ? CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr) : custom_size, /*solvable=*/true, /*safe=*/true, wtx.GetTxTime(), fIsFromMe, feerate});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -911,26 +911,26 @@ BOOST_AUTO_TEST_CASE(effective_value_test)
|
|||||||
tx.vout[nInput].nValue = nValue;
|
tx.vout[nInput].nValue = nValue;
|
||||||
|
|
||||||
// standard case, pass feerate in constructor
|
// standard case, pass feerate in constructor
|
||||||
COutput output1(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, feerate);
|
COutput output1(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, input_bytes, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, feerate);
|
||||||
const CAmount expected_ev1 = 9852; // 10000 - 148
|
const CAmount expected_ev1 = 9852; // 10000 - 148
|
||||||
BOOST_CHECK_EQUAL(output1.GetEffectiveValue(), expected_ev1);
|
BOOST_CHECK_EQUAL(output1.GetEffectiveValue(), expected_ev1);
|
||||||
|
|
||||||
// input bytes unknown (input_bytes = -1), pass feerate in constructor
|
// input bytes unknown (input_bytes = -1), pass feerate in constructor
|
||||||
COutput output2(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, feerate);
|
COutput output2(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, /*input_bytes=*/-1, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/ false, feerate);
|
||||||
BOOST_CHECK_EQUAL(output2.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
|
BOOST_CHECK_EQUAL(output2.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
|
||||||
|
|
||||||
// negative effective value, pass feerate in constructor
|
// negative effective value, pass feerate in constructor
|
||||||
COutput output3(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, CFeeRate(100000));
|
COutput output3(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, input_bytes, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, CFeeRate(100000));
|
||||||
const CAmount expected_ev3 = -4800; // 10000 - 14800
|
const CAmount expected_ev3 = -4800; // 10000 - 14800
|
||||||
BOOST_CHECK_EQUAL(output3.GetEffectiveValue(), expected_ev3);
|
BOOST_CHECK_EQUAL(output3.GetEffectiveValue(), expected_ev3);
|
||||||
|
|
||||||
// standard case, pass fees in constructor
|
// standard case, pass fees in constructor
|
||||||
const CAmount fees = 148;
|
const CAmount fees = 148;
|
||||||
COutput output4(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, input_bytes, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, fees);
|
COutput output4(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, input_bytes, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, fees);
|
||||||
BOOST_CHECK_EQUAL(output4.GetEffectiveValue(), expected_ev1);
|
BOOST_CHECK_EQUAL(output4.GetEffectiveValue(), expected_ev1);
|
||||||
|
|
||||||
// input bytes unknown (input_bytes = -1), pass fees in constructor
|
// input bytes unknown (input_bytes = -1), pass fees in constructor
|
||||||
COutput output5(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 1, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ false, /*fees=*/ 0);
|
COutput output5(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/1, /*input_bytes=*/-1, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/false, /*fees=*/0);
|
||||||
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
|
BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ static void AddCoin(const CAmount& value, int n_input, int n_input_bytes, int lo
|
|||||||
tx.vout.resize(n_input + 1);
|
tx.vout.resize(n_input + 1);
|
||||||
tx.vout[n_input].nValue = value;
|
tx.vout[n_input].nValue = value;
|
||||||
tx.nLockTime = locktime; // all transactions get different hashes
|
tx.nLockTime = locktime; // all transactions get different hashes
|
||||||
coins.emplace_back(COutPoint(tx.GetHash(), n_input), tx.vout.at(n_input), /*depth=*/0, n_input_bytes, /*spendable=*/true, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/true, fee_rate);
|
coins.emplace_back(COutPoint(tx.GetHash(), n_input), tx.vout.at(n_input), /*depth=*/0, n_input_bytes, /*solvable=*/true, /*safe=*/true, /*time=*/0, /*from_me=*/true, fee_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Randomly distribute coins to instances of OutputGroup
|
// Randomly distribute coins to instances of OutputGroup
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ static void addCoin(CoinsResult& coins,
|
|||||||
txout,
|
txout,
|
||||||
depth,
|
depth,
|
||||||
CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr),
|
CalculateMaximumSignedInputSize(txout, &wallet, /*coin_control=*/nullptr),
|
||||||
/*spendable=*/ true,
|
|
||||||
/*solvable=*/ true,
|
/*solvable=*/ true,
|
||||||
/*safe=*/ true,
|
/*safe=*/ true,
|
||||||
wtx.GetTxTime(),
|
wtx.GetTxTime(),
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
|
|||||||
// Lock both coins. Confirm number of available coins drops to 0.
|
// Lock both coins. Confirm number of available coins drops to 0.
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).Size(), 2U);
|
BOOST_CHECK_EQUAL(AvailableCoins(*wallet).Size(), 2U);
|
||||||
}
|
}
|
||||||
for (const auto& group : list) {
|
for (const auto& group : list) {
|
||||||
for (const auto& coin : group.second) {
|
for (const auto& coin : group.second) {
|
||||||
@@ -434,7 +434,7 @@ BOOST_FIXTURE_TEST_CASE(ListCoinsTest, ListCoinsTestingSetup)
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
LOCK(wallet->cs_wallet);
|
LOCK(wallet->cs_wallet);
|
||||||
BOOST_CHECK_EQUAL(AvailableCoinsListUnspent(*wallet).Size(), 0U);
|
BOOST_CHECK_EQUAL(AvailableCoins(*wallet).Size(), 0U);
|
||||||
}
|
}
|
||||||
// Confirm ListCoins still returns same result as before, despite coins
|
// Confirm ListCoins still returns same result as before, despite coins
|
||||||
// being locked.
|
// being locked.
|
||||||
|
|||||||
+27
-15
@@ -128,21 +128,38 @@ std::string TxStateString(const T& state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cachable amount subdivided into watchonly and spendable parts.
|
* Cachable amount subdivided into avoid reuse and all balances
|
||||||
*/
|
*/
|
||||||
struct CachableAmount
|
struct CachableAmount
|
||||||
{
|
{
|
||||||
// NO and ALL are never (supposed to be) cached
|
std::optional<CAmount> m_avoid_reuse_value;
|
||||||
std::bitset<ISMINE_ENUM_ELEMENTS> m_cached;
|
std::optional<CAmount> m_all_value;
|
||||||
CAmount m_value[ISMINE_ENUM_ELEMENTS];
|
|
||||||
inline void Reset()
|
inline void Reset()
|
||||||
{
|
{
|
||||||
m_cached.reset();
|
m_avoid_reuse_value.reset();
|
||||||
|
m_all_value.reset();
|
||||||
}
|
}
|
||||||
void Set(isminefilter filter, CAmount value)
|
void Set(bool avoid_reuse, CAmount value)
|
||||||
{
|
{
|
||||||
m_cached.set(filter);
|
if (avoid_reuse) {
|
||||||
m_value[filter] = value;
|
m_avoid_reuse_value = value;
|
||||||
|
} else {
|
||||||
|
m_all_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CAmount Get(bool avoid_reuse)
|
||||||
|
{
|
||||||
|
if (avoid_reuse) {
|
||||||
|
Assert(m_avoid_reuse_value.has_value());
|
||||||
|
return m_avoid_reuse_value.value();
|
||||||
|
}
|
||||||
|
Assert(m_all_value.has_value());
|
||||||
|
return m_all_value.value();
|
||||||
|
}
|
||||||
|
bool IsCached(bool avoid_reuse)
|
||||||
|
{
|
||||||
|
if (avoid_reuse) return m_avoid_reuse_value.has_value();
|
||||||
|
return m_all_value.has_value();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,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());
|
||||||
}
|
}
|
||||||
@@ -385,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
|
||||||
|
|
||||||
|
|||||||
@@ -17,37 +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_USED: the scriptPubKey corresponds to a used address owned by the wallet user;
|
|
||||||
* ISMINE_ALL: all ISMINE flags except for USED;
|
|
||||||
* ISMINE_ALL_USED: all ISMINE flags including 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.
|
|
||||||
* ISMINE_USED: the scriptPubKey corresponds to a used address owned by the wallet user.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
enum isminetype : unsigned int {
|
|
||||||
ISMINE_NO = 0,
|
|
||||||
ISMINE_SPENDABLE = 1 << 1,
|
|
||||||
ISMINE_USED = 1 << 2,
|
|
||||||
ISMINE_ALL = ISMINE_SPENDABLE,
|
|
||||||
ISMINE_ALL_USED = ISMINE_ALL | ISMINE_USED,
|
|
||||||
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
|
||||||
|
|||||||
+19
-23
@@ -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});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-10
@@ -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();
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user