mirror of
https://github.com/aljazceru/lightning.git
synced 2026-02-02 20:54:23 +01:00
fundpsbt: simplify the logic a little.
It keeps multiple different variables around the loop, but a simple "are we done yet?" helper makes this clearer and reduces special cases or all-vs-target. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -175,6 +175,38 @@ static const struct json_command unreserveinputs_command = {
|
||||
};
|
||||
AUTODATA(json_command, &unreserveinputs_command);
|
||||
|
||||
/**
|
||||
* inputs_sufficient - are we there yet?
|
||||
* @input: total input amount
|
||||
* @amount: required output amount
|
||||
* @feerate_per_kw: feerate we have to pay
|
||||
* @weight: weight of transaction so far.
|
||||
* @diff: (output) set to amount over or under requirements.
|
||||
*
|
||||
* Returns true if inputs >= fees + amount, otherwise false. diff is
|
||||
* the amount over (if returns true) or under (if returns false)
|
||||
*/
|
||||
static bool inputs_sufficient(struct amount_sat input,
|
||||
struct amount_sat amount,
|
||||
u32 feerate_per_kw,
|
||||
size_t weight,
|
||||
struct amount_sat *diff)
|
||||
{
|
||||
struct amount_sat fee;
|
||||
|
||||
fee = amount_tx_fee(feerate_per_kw, weight);
|
||||
|
||||
/* If we can't add fees, amount is huge (e.g. "all") */
|
||||
if (!amount_sat_add(&amount, amount, fee))
|
||||
return false;
|
||||
|
||||
/* One of these must work! */
|
||||
if (amount_sat_sub(diff, input, amount))
|
||||
return true;
|
||||
if (!amount_sat_sub(diff, amount, input))
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
|
||||
static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
const char *buffer,
|
||||
@@ -185,7 +217,7 @@ static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
struct utxo **utxos;
|
||||
u32 *feerate_per_kw;
|
||||
u32 *minconf, *weight;
|
||||
struct amount_sat *amount, input, needed, excess, total_fee;
|
||||
struct amount_sat *amount, input, diff;
|
||||
bool all, *reserve;
|
||||
u32 locktime, maxheight, current_height;
|
||||
struct bitcoin_tx *tx;
|
||||
@@ -204,27 +236,21 @@ static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
|
||||
current_height = get_block_height(cmd->ld->topology);
|
||||
|
||||
/* Can overflow if amount is "all" */
|
||||
if (!amount_sat_add(amount, *amount,
|
||||
amount_tx_fee(*feerate_per_kw, *weight)))
|
||||
;
|
||||
|
||||
/* We keep adding until we meet their output requirements. */
|
||||
input = AMOUNT_SAT(0);
|
||||
utxos = tal_arr(cmd, struct utxo *, 0);
|
||||
total_fee = amount_tx_fee(*feerate_per_kw, *weight);
|
||||
while (amount_sat_sub(&needed, *amount, input)
|
||||
&& !amount_sat_eq(needed, AMOUNT_SAT(0))) {
|
||||
|
||||
input = AMOUNT_SAT(0);
|
||||
while (!inputs_sufficient(input, *amount, *feerate_per_kw, *weight,
|
||||
&diff)) {
|
||||
struct utxo *utxo;
|
||||
|
||||
utxo = wallet_find_utxo(utxos, cmd->ld->wallet,
|
||||
cmd->ld->topology->tip->height,
|
||||
&needed,
|
||||
&diff,
|
||||
*feerate_per_kw,
|
||||
maxheight,
|
||||
cast_const2(const struct utxo **, utxos));
|
||||
if (utxo) {
|
||||
struct amount_sat fee;
|
||||
tal_arr_expand(&utxos, utxo);
|
||||
|
||||
/* It supplies more input. */
|
||||
@@ -232,17 +258,8 @@ static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
return command_fail(cmd, LIGHTNINGD,
|
||||
"impossible UTXO value");
|
||||
|
||||
/* But increase amount needed, to pay for new input */
|
||||
/* But also adds weight */
|
||||
*weight += utxo_spend_weight(utxo);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -263,7 +280,18 @@ static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
tal_count(utxos),
|
||||
type_to_string(tmpctx,
|
||||
struct amount_sat,
|
||||
&needed));
|
||||
&diff));
|
||||
}
|
||||
|
||||
if (all) {
|
||||
/* Anything above 0 is "excess" */
|
||||
if (!inputs_sufficient(input, AMOUNT_SAT(0),
|
||||
*feerate_per_kw, *weight,
|
||||
&diff))
|
||||
return command_fail(cmd, FUND_CANNOT_AFFORD,
|
||||
"All %zu inputs could not afford"
|
||||
" fees",
|
||||
tal_count(utxos));
|
||||
}
|
||||
|
||||
/* Setting the locktime to the next block to be mined has multiple
|
||||
@@ -289,27 +317,11 @@ static struct command_result *json_fundpsbt(struct command *cmd,
|
||||
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_num(response, "feerate_per_kw", *feerate_per_kw);
|
||||
json_add_num(response, "estimated_final_weight", *weight);
|
||||
json_add_amount_sat_only(response, "excess_msat", excess);
|
||||
json_add_amount_sat_only(response, "excess_msat", diff);
|
||||
if (*reserve)
|
||||
reserve_and_report(response, cmd->ld->wallet, current_height,
|
||||
utxos);
|
||||
|
||||
Reference in New Issue
Block a user