bitcoin: fix out-by-one-error in bitcoin_tx_input_weight.

We need one byte for the number of witness elements.  Some callers added it themselves,
but it's always needed.  So document and fix the callers.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2025-05-06 05:27:46 +09:30
parent 70f05132d9
commit 1d5cb4b49c
7 changed files with 13 additions and 10 deletions

View File

@ -893,7 +893,8 @@ size_t bitcoin_tx_input_sig_weight(void)
/* Input weight */
size_t bitcoin_tx_input_weight(bool p2sh, size_t witness_weight)
{
size_t weight = witness_weight;
/* We assume < 253 witness elements */
size_t weight = 1 + witness_weight;
/* Input weight: txid + index + sequence */
weight += (32 + 4 + 4) * 4;
@ -914,8 +915,8 @@ size_t bitcoin_tx_input_weight(bool p2sh, size_t witness_weight)
size_t bitcoin_tx_simple_input_witness_weight(void)
{
/* Account for witness (1 byte count + sig + key) */
return 1 + (bitcoin_tx_input_sig_weight() + 1 + 33);
/* Account for witness (sig + key) */
return bitcoin_tx_input_sig_weight() + 1 + 33;
}
/* We only do segwit inputs, and we assume witness is sig + key */

View File

@ -315,7 +315,9 @@ size_t bitcoin_tx_output_weight(size_t outscript_len);
/* Weight to push sig on stack. */
size_t bitcoin_tx_input_sig_weight(void);
/* Segwit input, but with parameter for witness weight (size) */
/* Segwit input, but with parameter for witness weight (size).
* witness_weight must include the varint_size() for each witness element,
* but not the varint_size() for the number of elements. */
size_t bitcoin_tx_input_weight(bool p2sh, size_t witness_weight);
/* The witness weight for a simple (sig + key) input */

View File

@ -186,9 +186,9 @@ static void trim_maximum_feerate(struct amount_sat funding,
* * `txin[0]` script bytes: 0
* * `txin[0]` witness: `0 <signature_for_pubkey1> <signature_for_pubkey2>`
*/
/* Account for witness (1 byte count + 1 empty + sig + sig) */
/* Account for witness (1 empty + sig + sig) */
assert(tal_count(commitment->inputs) == 1);
weight += bitcoin_tx_input_weight(false, 1 + 1 + 2 * bitcoin_tx_input_sig_weight());
weight += bitcoin_tx_input_weight(false, 1 + 2 * bitcoin_tx_input_sig_weight());
for (size_t i = 0; i < tal_count(commitment->outputs); i++) {
struct amount_asset amt;

View File

@ -410,7 +410,7 @@ def test_bookkeeping_missed_chans_leases(node_factory, bitcoind):
_check_events(l1, channel_id, exp_events)
exp_events = [('channel_open', open_amt * 1000, 0),
('onchain_fee', 892000, 0),
('onchain_fee', 894000, 0),
('lease_fee', lease_fee, 0),
('journal_entry', invoice_msat, 0)]
_check_events(l2, channel_id, exp_events)

View File

@ -4274,7 +4274,7 @@ def test_onchain_slow_anchor(node_factory, bitcoind):
height = bitcoind.rpc.getblockchaininfo()['blocks']
l1.daemon.wait_for_log(r"Low-priority anchorspend aiming for block {} \(feerate 7458\)".format(height + 13))
# Can be out-by-one (short sig)!
l1.daemon.wait_for_log(r"Anchorspend for local commit tx fee 12022sat \(w=672\), commit_tx fee 1735sat \(w=768\): package feerate 9553 perkw")
l1.daemon.wait_for_log(r"Anchorspend for local commit tx fee 12037 \(w=674\), commit_tx fee 1735sat \(w=768\): package feerate 9550 perkw")
assert not l1.daemon.is_in_log("Low-priority anchorspend aiming for block {}".format(height + 12))
bitcoind.generate_block(1)

View File

@ -746,7 +746,7 @@ def test_withdraw_misc(node_factory, bitcoind, chainparams):
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit_msat': 2000000000, 'debit_msat': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit_msat': 11957423000, 'debit_msat': 0, 'tags': ['deposit']},
{'type': 'chain_mvt', 'credit_msat': 11957393000, 'debit_msat': 0, 'tags': ['deposit']},
]
check_coin_moves(l1, 'external', external_moves, chainparams)

View File

@ -1526,7 +1526,7 @@ def test_funder_contribution_limits(node_factory, bitcoind):
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.fundchannel(l2, 10**7)
assert l2.daemon.is_in_log('Policy .* returned funding amount of 107530sat')
assert l2.daemon.is_in_log('Policy .* returned funding amount of 107470sat')
assert l2.daemon.is_in_log(r'calling `signpsbt` .* inputs')
l1.rpc.connect(l3.info['id'], 'localhost', l3.port)