Skip to content

Commit 832cd30

Browse files
committed
splice: Fix weight calculations & use opening feerate
Here we update `psbt_input_get_weight` to allow the caller to specify what kind of input size estimation they would like. Before it was just “zero witness bytes” which we now move to the default behavior and add an assumption option for P2WSH -> 2of2 multisig which is what we typically see in splicing. At the same time we move channeld over to using the opening feerate estimation instead of the less useful “max feerate.” We make splice script use this same feerate. After auditing the feerates for these two places against each other and the actually created transaction, we implement some fixes making them all match. While we’re here, we add relevant debug log messages. Changelog-Changed: Audited and updated splice’s feerate calculations to be precise to the byte — a critical change to accomodate splice script.
1 parent 7c1b4ca commit 832cd30

6 files changed

Lines changed: 201 additions & 77 deletions

File tree

bitcoin/psbt.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <ccan/ccan/mem/mem.h>
88
#include <common/utils.h>
99
#include <wally_psbt.h>
10+
#include <wally_psbt_members.h>
1011
#include <wire/wire.h>
1112

1213

@@ -480,6 +481,28 @@ void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscr
480481
tal_wally_end(psbt);
481482
}
482483

484+
const u8 *psbt_input_get_witscript(const tal_t *ctx,
485+
const struct wally_psbt *psbt,
486+
size_t in)
487+
{
488+
size_t witscript_len, written_len;
489+
u8 *witscript;
490+
if (wally_psbt_get_input_witness_script_len(psbt, in, &witscript_len) != WALLY_OK)
491+
abort();
492+
witscript = tal_arr(ctx, u8, witscript_len);
493+
if (wally_psbt_get_input_witness_script(psbt, in, witscript, witscript_len, &written_len) != WALLY_OK)
494+
abort();
495+
if (witscript_len != written_len)
496+
abort();
497+
return witscript;
498+
}
499+
500+
bool psbt_input_get_ecdsa_sig(const tal_t *ctx,
501+
const struct wally_psbt *psbt,
502+
size_t in,
503+
const struct pubkey *pubkey,
504+
struct bitcoin_signature **sig);
505+
483506
void psbt_elements_input_set_asset(struct wally_psbt *psbt, size_t in,
484507
struct amount_asset *asset)
485508
{
@@ -592,10 +615,16 @@ struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
592615
}
593616

594617
size_t psbt_input_get_weight(const struct wally_psbt *psbt,
595-
size_t in)
618+
size_t in,
619+
enum PSBT_GUESS guess)
596620
{
597621
size_t weight;
598622
const struct wally_map_item *redeem_script;
623+
struct wally_psbt_input *input = &psbt->inputs[in];
624+
struct wally_tx_output *utxo_out = NULL;
625+
626+
if (input->utxo)
627+
utxo_out = &input->utxo->outputs[input->index];
599628

600629
redeem_script = wally_map_get_integer(&psbt->inputs[in].psbt_fields, /* PSBT_IN_REDEEM_SCRIPT */ 0x04);
601630

@@ -605,8 +634,20 @@ size_t psbt_input_get_weight(const struct wally_psbt *psbt,
605634
weight +=
606635
(redeem_script->value_len +
607636
varint_size(redeem_script->value_len)) * 4;
637+
} else if ((guess & PSBT_GUESS_2OF2)
638+
&& utxo_out
639+
&& is_p2wsh(utxo_out->script, utxo_out->script_len, NULL)) {
640+
weight = bitcoin_tx_input_weight(false,
641+
bitcoin_tx_2of2_input_witness_weight());
642+
} else if (utxo_out
643+
&& is_p2wpkh(utxo_out->script, utxo_out->script_len, NULL)) {
644+
weight = bitcoin_tx_input_weight(false,
645+
bitcoin_tx_input_witness_weight(UTXO_P2SH_P2WPKH));
646+
} else if (utxo_out
647+
&& is_p2tr(utxo_out->script, utxo_out->script_len, NULL)) {
648+
weight = bitcoin_tx_input_weight(false,
649+
bitcoin_tx_input_witness_weight(UTXO_P2TR));
608650
} else {
609-
/* zero scriptSig length */
610651
weight += varint_size(0) * 4;
611652
}
612653

bitcoin/psbt.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ WARN_UNUSED_RESULT bool psbt_input_get_ecdsa_sig(const tal_t *ctx,
207207

208208
void psbt_input_set_witscript(struct wally_psbt *psbt, size_t in, const u8 *wscript);
209209

210+
const u8 *psbt_input_get_witscript(const tal_t *ctx,
211+
const struct wally_psbt *psbt,
212+
size_t in);
213+
210214
/* psbt_input_set_unknown - Set the given Key-Value in the psbt's input keymap
211215
* @ctx - tal context for allocations
212216
* @in - psbt input to set key-value on
@@ -265,9 +269,20 @@ void psbt_output_set_unknown(const tal_t *ctx,
265269
struct amount_sat psbt_input_get_amount(const struct wally_psbt *psbt,
266270
size_t in);
267271

268-
/* psbt_input_get_weight - Calculate the tx weight for input index `in` */
272+
enum PSBT_GUESS {
273+
PSBT_GUESS_ZERO = 0x0, /* Assume unknown is 0 bytes (fallback) */
274+
PSBT_GUESS_2OF2 = 0x1, /* Assume P2WSH is 2of2 multisig (req prevtx) */
275+
};
276+
277+
/* psbt_input_get_weight - Calculate the tx weight for input index `in`.
278+
*
279+
* @psbt - psbt
280+
* @in - index of input who's weight you want
281+
* @guess - How to guess if we have incomplete information
282+
* */
269283
size_t psbt_input_get_weight(const struct wally_psbt *psbt,
270-
size_t in);
284+
size_t in,
285+
enum PSBT_GUESS guess);
271286

272287
/* psbt_output_get_amount - Returns the value of this output
273288
*

channeld/channeld.c

Lines changed: 86 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3178,47 +3178,70 @@ static struct wally_psbt_output *find_channel_output(struct peer *peer,
31783178
return NULL;
31793179
}
31803180

3181-
static size_t calc_weight(enum tx_role role, const struct wally_psbt *psbt)
3181+
static size_t calc_weight(enum tx_role role, const struct wally_psbt *psbt,
3182+
bool log_math)
31823183
{
3183-
size_t weight = 0;
3184+
size_t lweight = 0, weight = 0;
31843185

3185-
/* BOLT #2:
3186-
* The *initiator* is responsible for paying the fees for the following fields,
3187-
* to be referred to as the `common fields`.
3188-
*
3189-
* - version
3190-
* - segwit marker + flag
3191-
* - input count
3192-
* - output count
3193-
* - locktime
3194-
*/
3195-
if (role == TX_INITIATOR)
3196-
weight += bitcoin_tx_core_weight(psbt->num_inputs,
3197-
psbt->num_outputs);
3186+
if (log_math)
3187+
status_debug("Counting tx weight;");
31983188

31993189
/* BOLT #2:
32003190
* The rest of the transaction bytes' fees are the responsibility of
32013191
* the peer who contributed that input or output via `tx_add_input` or
32023192
* `tx_add_output`, at the agreed upon `feerate`.
32033193
*/
3204-
for (size_t i = 0; i < psbt->num_inputs; i++)
3194+
for (size_t i = 0; i < psbt->num_inputs; i++) {
32053195
if (is_initiators_serial(&psbt->inputs[i].unknowns)) {
32063196
if (role == TX_INITIATOR)
3207-
weight += psbt_input_get_weight(psbt, i);
3197+
weight += psbt_input_get_weight(psbt, i, PSBT_GUESS_2OF2);
32083198
}
3209-
else
3199+
else {
32103200
if (role != TX_INITIATOR)
3211-
weight += psbt_input_get_weight(psbt, i);
3201+
weight += psbt_input_get_weight(psbt, i, PSBT_GUESS_2OF2);
3202+
}
3203+
if (log_math)
3204+
status_debug(" Adding input"
3205+
" %lu; weight: %lu", i, weight - lweight);
3206+
lweight = weight;
3207+
}
32123208

3213-
for (size_t i = 0; i < psbt->num_outputs; i++)
3209+
for (size_t i = 0; i < psbt->num_outputs; i++) {
32143210
if (is_initiators_serial(&psbt->outputs[i].unknowns)) {
32153211
if (role == TX_INITIATOR)
32163212
weight += psbt_output_get_weight(psbt, i);
32173213
}
3218-
else
3214+
else {
32193215
if (role != TX_INITIATOR)
32203216
weight += psbt_output_get_weight(psbt, i);
3217+
}
3218+
if (log_math)
3219+
status_debug(" Adding output"
3220+
" %lu; weight: %lu", i, weight - lweight);
3221+
lweight = weight;
3222+
}
32213223

3224+
/* BOLT #2:
3225+
* The *initiator* is responsible for paying the fees for the following fields,
3226+
* to be referred to as the `common fields`.
3227+
*
3228+
* - version
3229+
* - segwit marker + flag
3230+
* - input count
3231+
* - output count
3232+
* - locktime
3233+
*/
3234+
if (role == TX_INITIATOR) {
3235+
weight += bitcoin_tx_core_weight(psbt->num_inputs,
3236+
psbt->num_outputs);
3237+
if (log_math)
3238+
status_debug(" Adding bitcoin_tx_core_weight;"
3239+
" weight: %lu", weight - lweight);
3240+
lweight = weight;
3241+
}
3242+
3243+
if (log_math)
3244+
status_debug("Total weight: %lu", weight);
32223245
return weight;
32233246
}
32243247

@@ -3319,8 +3342,7 @@ static struct amount_sat check_balances(struct peer *peer,
33193342
{
33203343
struct amount_sat min_initiator_fee, min_accepter_fee,
33213344
max_initiator_fee, max_accepter_fee,
3322-
funding_amount_res, min_multiplied,
3323-
initiator_penalty_fee, accepter_penalty_fee;
3345+
funding_amount_res;
33243346
struct amount_msat funding_amount,
33253347
initiator_fee, accepter_fee;
33263348
struct amount_msat in[NUM_TX_ROLES], out[NUM_TX_ROLES],
@@ -3469,33 +3491,26 @@ static struct amount_sat check_balances(struct peer *peer,
34693491
"amount_sat_less / amount_sat_sub mismtach");
34703492

34713493
min_initiator_fee = amount_tx_fee(peer->splicing->feerate_per_kw,
3472-
calc_weight(TX_INITIATOR, psbt));
3494+
calc_weight(TX_INITIATOR, psbt, false));
34733495
min_accepter_fee = amount_tx_fee(peer->splicing->feerate_per_kw,
3474-
calc_weight(TX_ACCEPTER, psbt));
3496+
calc_weight(TX_ACCEPTER, psbt, false));
34753497

34763498
/* As a safeguard max feerate is checked (only) locally, if it's
34773499
* particularly high we fail and tell the user but allow them to
34783500
* override with `splice_force_feerate` */
3479-
max_accepter_fee = amount_tx_fee(peer->feerate_max,
3480-
calc_weight(TX_ACCEPTER, psbt));
3481-
max_initiator_fee = amount_tx_fee(peer->feerate_max,
3482-
calc_weight(TX_INITIATOR, psbt));
3483-
initiator_penalty_fee = amount_tx_fee(peer->feerate_penalty,
3484-
calc_weight(TX_INITIATOR, psbt));
3485-
accepter_penalty_fee = amount_tx_fee(peer->feerate_penalty,
3486-
calc_weight(TX_ACCEPTER, psbt));
3487-
3488-
/* Sometimes feerate_max is some absurdly high value, in that case we
3489-
* give a fee warning based of a multiple of the min value. */
3490-
amount_sat_mul(&min_multiplied, min_accepter_fee, 5);
3491-
max_accepter_fee = SAT_MIN(min_multiplied, max_accepter_fee);
3492-
if (amount_sat_greater(accepter_penalty_fee, max_accepter_fee))
3493-
max_accepter_fee = accepter_penalty_fee;
3494-
3495-
amount_sat_mul(&min_multiplied, min_initiator_fee, 5);
3496-
max_initiator_fee = SAT_MIN(min_multiplied, max_initiator_fee);
3497-
if (amount_sat_greater(initiator_penalty_fee, max_initiator_fee))
3498-
max_initiator_fee = initiator_penalty_fee;
3501+
max_accepter_fee = amount_tx_fee(peer->feerate_opening,
3502+
calc_weight(TX_ACCEPTER, psbt, false));
3503+
max_initiator_fee = amount_tx_fee(peer->feerate_opening,
3504+
calc_weight(TX_INITIATOR, psbt, opener));
3505+
3506+
if (opener) {
3507+
status_debug("User specified fee of %s. Opening feerate %"PRIu32
3508+
" * weight %lu / 1000 = %s",
3509+
fmt_amount_m_as_sat(tmpctx, initiator_fee),
3510+
peer->feerate_opening,
3511+
calc_weight(TX_INITIATOR, psbt, false),
3512+
fmt_amount_sat(tmpctx, max_initiator_fee));
3513+
}
34993514

35003515
/* Check initiator fee */
35013516
if (amount_msat_less_sat(initiator_fee, min_initiator_fee)) {
@@ -3512,23 +3527,38 @@ static struct amount_sat check_balances(struct peer *peer,
35123527
&& amount_msat_greater_sat(initiator_fee, max_initiator_fee)) {
35133528
msg = towire_channeld_splice_feerate_error(NULL, initiator_fee,
35143529
true);
3530+
status_debug("Our own fee (%s) is too high to use without"
3531+
" forcing. Opening feerate %"PRIu32
3532+
" x weight %lu / 1000 = %s (max)",
3533+
fmt_amount_m_as_sat(tmpctx, initiator_fee),
3534+
peer->feerate_opening,
3535+
calc_weight(TX_INITIATOR, psbt, false),
3536+
fmt_amount_sat(tmpctx, max_initiator_fee));
3537+
35153538
wire_sync_write(MASTER_FD, take(msg));
3539+
35163540
splice_abort(peer,
3517-
"Our own fee (%s) was too high, max without"
3518-
" forcing is %s.",
3519-
fmt_amount_msat(tmpctx, initiator_fee),
3520-
fmt_amount_sat(tmpctx, max_initiator_fee));
3541+
"Our own fee (%s) is too high to use without"
3542+
" forcing. Opening feerate %"PRIu32
3543+
" x weight %lu / 1000 = %s (max)",
3544+
fmt_amount_m_as_sat(tmpctx, initiator_fee),
3545+
peer->feerate_opening,
3546+
calc_weight(TX_INITIATOR, psbt, false),
3547+
fmt_amount_sat(tmpctx, max_initiator_fee));
35213548
}
35223549
/* Check accepter fee */
35233550
if (amount_msat_less_sat(accepter_fee, min_accepter_fee)) {
35243551
msg = towire_channeld_splice_feerate_error(NULL, accepter_fee,
35253552
false);
35263553
wire_sync_write(MASTER_FD, take(msg));
35273554
splice_abort(peer,
3528-
"%s fee (%s) was too low, must be at least %s",
3529-
opener ? "Your" : "Our",
3530-
fmt_amount_msat(tmpctx, accepter_fee),
3531-
fmt_amount_sat(tmpctx, min_accepter_fee));
3555+
"%s fee (%s) was too low, must be at least %s"
3556+
" weight: %"PRIu64", feerate_max: %"PRIu32,
3557+
opener ? "Your" : "Our",
3558+
fmt_amount_msat(tmpctx, accepter_fee),
3559+
fmt_amount_sat(tmpctx, min_accepter_fee),
3560+
calc_weight(TX_INITIATOR, psbt, false),
3561+
peer->feerate_opening);
35323562
}
35333563
if (!peer->splicing->force_feerate && !opener
35343564
&& amount_msat_greater_sat(accepter_fee, max_accepter_fee)) {
@@ -3981,6 +4011,9 @@ static void resume_splice_negotiation(struct peer *peer,
39814011

39824012
peer->splicing = tal_free(peer->splicing);
39834013

4014+
if (our_role == TX_INITIATOR)
4015+
calc_weight(TX_INITIATOR, current_psbt, true);
4016+
39844017
final_tx = bitcoin_tx_with_psbt(tmpctx, current_psbt);
39854018
msg = towire_channeld_splice_confirmed_signed(tmpctx, final_tx,
39864019
new_output_index);

lightningd/channel_control.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,9 +588,10 @@ static void send_splice_tx(struct channel *channel,
588588
u8* tx_bytes = linearize_tx(tmpctx, tx);
589589

590590
log_debug(channel->log,
591-
"Broadcasting splice tx %s for channel %s.",
591+
"Broadcasting splice tx %s for channel %s. Final weight %lu",
592592
tal_hex(tmpctx, tx_bytes),
593-
fmt_channel_id(tmpctx, &channel->cid));
593+
fmt_channel_id(tmpctx, &channel->cid),
594+
bitcoin_tx_weight(tx));
594595

595596
struct send_splice_info *info = tal(NULL, struct send_splice_info);
596597

openingd/dualopend.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -818,14 +818,14 @@ static char *check_balances(const tal_t *ctx,
818818
assert(ok);
819819

820820
initiator_weight +=
821-
psbt_input_get_weight(psbt, i);
821+
psbt_input_get_weight(psbt, i, PSBT_GUESS_ZERO);
822822
} else {
823823
ok = amount_sat_add(&accepter_inputs,
824824
accepter_inputs, amt);
825825
assert(ok);
826826

827827
accepter_weight +=
828-
psbt_input_get_weight(psbt, i);
828+
psbt_input_get_weight(psbt, i, PSBT_GUESS_ZERO);
829829
}
830830
}
831831
tot_output_amt = AMOUNT_SAT(0);

0 commit comments

Comments
 (0)