aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorW. J. van der Laan <laanwj@protonmail.com>2021-05-10 15:55:22 +0200
committerW. J. van der Laan <laanwj@protonmail.com>2021-05-10 16:05:23 +0200
commit32692d26813ba099c1451ae5941d38923bec761c (patch)
tree893b98d913055c7be76c0422b05007c18b649346 /src
parent8bed1706eac45a90a016471275e4857a22984289 (diff)
parent11d6459b6e101f05f36e13799c400bef82d2fc21 (diff)
Merge bitcoin/bitcoin#21359: rpc: include_unsafe option for fundrawtransaction
11d6459b6e101f05f36e13799c400bef82d2fc21 rpc: include_unsafe option for fundrawtransaction (t-bast) Pull request description: Allow RPC users to opt-in to unsafe inputs when funding a raw transaction. Applications that need to manage a complex RBF flow (such as lightning nodes using anchor outputs) are very limited if they can only use safe inputs. I also added this option to `send` and `walletcreatefundedpsbt` who internally delegate to `fundrawtransaction`. Fixes #21299 ACKs for top commit: laanwj: Code review ACK 11d6459b6e101f05f36e13799c400bef82d2fc21 Tree-SHA512: 5e542a4febcfd6f41cf784678ff02ec9282eae2082c274983f72c5ea87b7ebbe1bd5fdc6a020d7a9d5996157754eb4966b8aeb6c1ceebf0b1519f735579b8bac
Diffstat (limited to 'src')
-rw-r--r--src/wallet/coincontrol.h2
-rw-r--r--src/wallet/coinselection.h3
-rw-r--r--src/wallet/rpcwallet.cpp14
-rw-r--r--src/wallet/wallet.cpp13
4 files changed, 27 insertions, 5 deletions
diff --git a/src/wallet/coincontrol.h b/src/wallet/coincontrol.h
index 716e1922fe..85cbec76b7 100644
--- a/src/wallet/coincontrol.h
+++ b/src/wallet/coincontrol.h
@@ -29,6 +29,8 @@ public:
std::optional<OutputType> m_change_type;
//! If false, only selected inputs are used
bool m_add_inputs = true;
+ //! If false, only safe inputs will be used
+ bool m_include_unsafe_inputs = false;
//! If false, allows unselected inputs, but requires all selected inputs be used
bool fAllowOtherInputs = false;
//! Includes watch only addresses which are solvable
diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h
index 5c1b36be6e..5645e6db46 100644
--- a/src/wallet/coinselection.h
+++ b/src/wallet/coinselection.h
@@ -65,8 +65,7 @@ struct CoinEligibilityFilter
/** Minimum number of confirmations for outputs that we sent to ourselves.
* We may use unconfirmed UTXOs sent from ourselves, e.g. change outputs. */
const int conf_mine;
- /** Minimum number of confirmations for outputs received from a different
- * wallet. We never spend unconfirmed foreign outputs as we cannot rely on these funds yet. */
+ /** Minimum number of confirmations for outputs received from a different wallet. */
const int conf_theirs;
/** Maximum number of unconfirmed ancestors aggregated across all UTXOs in an OutputGroup. */
const uint64_t max_ancestors;
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 7777543ece..3f1c1aeab5 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -3076,6 +3076,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
RPCTypeCheckObj(options,
{
{"add_inputs", UniValueType(UniValue::VBOOL)},
+ {"include_unsafe", UniValueType(UniValue::VBOOL)},
{"add_to_wallet", UniValueType(UniValue::VBOOL)},
{"changeAddress", UniValueType(UniValue::VSTR)},
{"change_address", UniValueType(UniValue::VSTR)},
@@ -3136,6 +3137,10 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
}
+ if (options.exists("include_unsafe")) {
+ coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();
+ }
+
if (options.exists("feeRate")) {
if (options.exists("fee_rate")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");
@@ -3206,6 +3211,9 @@ static RPCHelpMan fundrawtransaction()
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
+ {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
+ "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
+ "If that happens, you will need to fund the transaction with different inputs and republish it."},
{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
@@ -4031,6 +4039,9 @@ static RPCHelpMan send()
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
+ "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
+ "If that happens, you will need to fund the transaction with different inputs and republish it."},
{"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
{"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
{"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
@@ -4374,6 +4385,9 @@ static RPCHelpMan walletcreatefundedpsbt()
{"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
{
{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
+ {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
+ "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
+ "If that happens, you will need to fund the transaction with different inputs and republish it."},
{"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index d90cc58b88..60d60d1e81 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2516,8 +2516,7 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(1, 1, 0), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) return true;
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
- // possible) if we cannot fund the transaction otherwise. We never spend unconfirmed
- // outputs received from other wallets.
+ // possible) if we cannot fund the transaction otherwise.
if (m_spend_zero_conf_change) {
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, 2), vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) return true;
if (SelectCoinsMinConf(value_to_select, CoinEligibilityFilter(0, 1, std::min((size_t)4, max_ancestors/3), std::min((size_t)4, max_descendants/3)),
@@ -2535,6 +2534,14 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
return true;
}
+ // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
+ // received from other wallets.
+ if (coin_control.m_include_unsafe_inputs
+ && SelectCoinsMinConf(value_to_select,
+ CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
+ vCoins, setCoinsRet, nValueRet, coin_selection_params, bnb_used)) {
+ return true;
+ }
// Try with unlimited ancestors/descendants. The transaction will still need to meet
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
// OutputGroups use heuristics that may overestimate ancestor/descendant counts.
@@ -2836,7 +2843,7 @@ bool CWallet::CreateTransactionInternal(
txNew.nLockTime = GetLocktimeForNewTransaction(chain(), GetLastBlockHash(), GetLastBlockHeight());
{
std::vector<COutput> vAvailableCoins;
- AvailableCoins(vAvailableCoins, true, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0);
+ AvailableCoins(vAvailableCoins, !coin_control.m_include_unsafe_inputs, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0);
CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;