diff --git a/bitcoin/tx.h b/bitcoin/tx.h index f62c5c0f7..cd63dbeb7 100644 --- a/bitcoin/tx.h +++ b/bitcoin/tx.h @@ -12,6 +12,10 @@ #include #define BITCOIN_TX_DEFAULT_SEQUENCE 0xFFFFFFFF + +/* BIP 125: Any nsequence < 0xFFFFFFFE is replacable. + * And bitcoind uses this value. */ +#define BITCOIN_TX_RBF_SEQUENCE 0xFFFFFFFD struct wally_psbt; struct bitcoin_txid { diff --git a/common/utxo.c b/common/utxo.c index 7ff9bcfa6..af30e993c 100644 --- a/common/utxo.c +++ b/common/utxo.c @@ -76,7 +76,6 @@ struct bitcoin_tx *tx_spending_utxos(const tal_t *ctx, struct pubkey key; u8 *scriptSig, *scriptPubkey, *redeemscript; - assert(num_output); size_t outcount = add_change_output ? 1 + num_output : num_output; struct bitcoin_tx *tx = bitcoin_tx(ctx, chainparams, tal_count(utxos), outcount, nlocktime); diff --git a/wallet/reservation.c b/wallet/reservation.c index ecb355276..15bacae5a 100644 --- a/wallet/reservation.c +++ b/wallet/reservation.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -164,3 +165,137 @@ static const struct json_command unreserveinputs_command = { false }; AUTODATA(json_command, &unreserveinputs_command); + + +static struct command_result *json_fundpsbt(struct command *cmd, + const char *buffer, + const jsmntok_t *obj UNNEEDED, + const jsmntok_t *params) +{ + struct json_stream *response; + const struct utxo **utxos; + u32 *feerate_per_kw; + u32 *minconf; + struct amount_sat *amount, input, needed, excess, total_fee; + bool all; + u32 locktime, maxheight; + struct bitcoin_tx *tx; + + if (!param(cmd, buffer, params, + p_req("satoshi", param_sat_or_all, &amount), + p_req("feerate", param_feerate_val, &feerate_per_kw), + p_opt_def("minconf", param_number, &minconf, 1), + NULL)) + return command_param_failed(); + + all = amount_sat_eq(*amount, AMOUNT_SAT(-1ULL)); + maxheight = minconf_to_maxheight(*minconf, cmd->ld); + + /* We keep adding until we meet their output requirements. */ + input = AMOUNT_SAT(0); + utxos = tal_arr(cmd, const struct utxo *, 0); + total_fee = AMOUNT_SAT(0); + while (amount_sat_sub(&needed, *amount, input) + && !amount_sat_eq(needed, AMOUNT_SAT(0))) { + struct utxo *utxo; + + utxo = wallet_find_utxo(utxos, cmd->ld->wallet, + cmd->ld->topology->tip->height, + &needed, + *feerate_per_kw, + maxheight, + utxos); + if (utxo) { + struct amount_sat fee; + tal_arr_expand(&utxos, utxo); + + /* It supplies more input. */ + if (!amount_sat_add(&input, input, utxo->amount)) + return command_fail(cmd, LIGHTNINGD, + "impossible UTXO value"); + + /* But increase amount needed, to pay for new input */ + fee = amount_tx_fee(*feerate_per_kw, + utxo_spend_weight(utxo)); + if (!amount_sat_add(amount, *amount, fee)) + /* Either they specified "all", or we + * will fail anyway. */ + *amount = AMOUNT_SAT(-1ULL); + if (!amount_sat_add(&total_fee, total_fee, fee)) + return command_fail(cmd, LIGHTNINGD, + "impossible fee value"); + continue; + } + + /* If they said "all", we expect to run out of utxos. */ + if (all) { + /* If we have none at all though, fail */ + if (!tal_count(utxos)) + return command_fail(cmd, FUND_CANNOT_AFFORD, + "No available UTXOs"); + break; + } + + return command_fail(cmd, FUND_CANNOT_AFFORD, + "Could not afford %s using all %zu available UTXOs: %s short", + type_to_string(tmpctx, + struct amount_sat, + amount), + tal_count(utxos), + type_to_string(tmpctx, + struct amount_sat, + &needed)); + } + + /* Setting the locktime to the next block to be mined has multiple + * benefits: + * - anti fee-snipping (even if not yet likely) + * - less distinguishable transactions (with this we create + * general-purpose transactions which looks like bitcoind: + * native segwit, nlocktime set to tip, and sequence set to + * 0xFFFFFFFD by default. Other wallets are likely to implement + * this too). + */ + locktime = cmd->ld->topology->tip->height; + + /* Eventually fuzz it too. */ + if (locktime > 100 && pseudorand(10) == 0) + locktime -= pseudorand(100); + + /* FIXME: tx_spending_utxos does more than we need, but there + * are other users right now. */ + tx = tx_spending_utxos(cmd, chainparams, utxos, + cmd->ld->wallet->bip32_base, + false, 0, locktime, + BITCOIN_TX_RBF_SEQUENCE); + + if (all) { + /* Count everything not going towards fees as excess. */ + if (!amount_sat_sub(&excess, input, total_fee)) + return command_fail(cmd, FUND_CANNOT_AFFORD, + "All %zu inputs could not afford" + " %s fees", + tal_count(utxos), + type_to_string(tmpctx, + struct amount_sat, + &total_fee)); + } else { + /* This was the condition of exiting the loop above! */ + if (!amount_sat_sub(&excess, input, *amount)) + abort(); + } + + response = json_stream_success(cmd); + json_add_psbt(response, "psbt", tx->psbt); + json_add_amount_sat_only(response, "excess_msat", excess); + return command_success(cmd, response); +} + +static const struct json_command fundpsbt_command = { + "fundpsbt", + "bitcoin", + json_fundpsbt, + "Create PSBT using enough utxos to allow an output of {satoshi} at {feerate}", + false +}; +AUTODATA(json_command, &fundpsbt_command);