aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorfanquake <fanquake@gmail.com>2022-08-19 08:50:39 +0100
committerfanquake <fanquake@gmail.com>2022-08-19 08:53:44 +0100
commit0425ce577f9245386afd15c70ef01ae3b4d32153 (patch)
treec39f7bdd352bbefd166feb4d33249a82f3d81d43 /src/wallet
parent888628cee00c014f4d9ec7c390f38146e498c9c2 (diff)
parentef8e2a5b09dea73de8d57e6b976d77edbde5f8ff (diff)
downloadbitcoin-0425ce577f9245386afd15c70ef01ae3b4d32153.tar.xz
Merge bitcoin/bitcoin#25679: wallet: Correctly identify external inputs that are also in the wallet
ef8e2a5b09dea73de8d57e6b976d77edbde5f8ff tests: Test that external inputs of txs in wallet is handled correctly (Andrew Chow) eb879634db2116b23e884dab21318743f974f1f3 wallet: Try estimating input size with external data if wallet fails (Andrew Chow) a537d7aaa069bc216aeab381bbc4d312b5ffedf1 wallet: SelectExternal actually external inputs (Andrew Chow) f2d00bfe1a32a11c0d88e8c1d3bae6a6b01db15e wallet: Add CWallet::IsMine(COutPoint) (Andrew Chow) Pull request description: if a transaction is being funded that has an external input, and that input's parent is also in the wallet, we will fail to detect that and fail to fund the transaction. In order to correctly detect such inputs, we need to be doing `IsMine` on all specified inputs in order to use `Select` and `SelectExternal` correctly. Additionally `SelectCoins` needs to call `CalculateMaximumSignedInputSize` with the correct parameters which depends on whether the wallet is able to solve for the input. Because there are some situations where the wallet could find an external input to belong to it (e.g. watching an address - unable to solve, but will be ISMINE_WATCHONLY), instead of switching which `CalculateMaximumSignedInputSize` to use, we should call the one that uses the wallet, and if that fails, try again with the one that uses external solving data. Also adds a test for this case. ACKs for top commit: instagibbs: ACK https://github.com/bitcoin/bitcoin/pull/25679/commits/ef8e2a5b09dea73de8d57e6b976d77edbde5f8ff furszy: ACK ef8e2a5b ishaanam: reACK ef8e2a5b09dea73de8d57e6b976d77edbde5f8ff Tree-SHA512: a43c4aefeed4605f33a36ce87ebb916e2c153fea6d415b02c9a89275e84a7e3bf12840b33c296d2d2bde46350390da48d9262f9567338e3f21d5936aae4caa1e
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/spend.cpp16
-rw-r--r--src/wallet/wallet.cpp13
-rw-r--r--src/wallet/wallet.h1
3 files changed, 26 insertions, 4 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index d6362c1f14..001acd04e2 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -569,8 +569,12 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
if (!coin_control.GetExternalOutput(outpoint, txout)) {
return std::nullopt;
}
+ }
+
+ if (input_bytes == -1) {
input_bytes = CalculateMaximumSignedInputSize(txout, outpoint, &coin_control.m_external_provider, &coin_control);
}
+
// If available, override calculated size with coin control specified size
if (coin_control.HasInputWeight(outpoint)) {
input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0);
@@ -1127,12 +1131,16 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
wallet.chain().findCoins(coins);
for (const CTxIn& txin : tx.vin) {
- // if it's not in the wallet and corresponding UTXO is found than select as external output
const auto& outPoint = txin.prevout;
- if (wallet.mapWallet.find(outPoint.hash) == wallet.mapWallet.end() && !coins[outPoint].out.IsNull()) {
- coinControl.SelectExternal(outPoint, coins[outPoint].out);
- } else {
+ if (wallet.IsMine(outPoint)) {
+ // The input was found in the wallet, so select as internal
coinControl.Select(outPoint);
+ } else if (coins[outPoint].out.IsNull()) {
+ error = _("Unable to find UTXO for external input");
+ return false;
+ } else {
+ // The input was not in the wallet, but is in the UTXO set, so select as external
+ coinControl.SelectExternal(outPoint, coins[outPoint].out);
}
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d598425326..45d2c3692d 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -1428,6 +1428,19 @@ bool CWallet::IsMine(const CTransaction& tx) const
return false;
}
+isminetype CWallet::IsMine(const COutPoint& outpoint) const
+{
+ AssertLockHeld(cs_wallet);
+ auto wtx = GetWalletTx(outpoint.hash);
+ if (!wtx) {
+ return ISMINE_NO;
+ }
+ if (outpoint.n >= wtx->tx->vout.size()) {
+ return ISMINE_NO;
+ }
+ return IsMine(wtx->tx->vout[outpoint.n]);
+}
+
bool CWallet::IsFromMe(const CTransaction& tx) const
{
return (GetDebit(tx, ISMINE_ALL) > 0);
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 4fc41b2f53..3a46d0a987 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -685,6 +685,7 @@ public:
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);
+ isminetype IsMine(const COutPoint& outpoint) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;