More accurate elements commitment tx size estimation

This commit is contained in:
Greg Sanders 2023-02-03 11:32:29 -05:00 committed by Alex Myers
parent dc4ae9deb4
commit eef0c087fc
4 changed files with 27 additions and 19 deletions

View file

@ -28,6 +28,7 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs,
bool option_anchor_outputs)
{
size_t weight;
size_t num_outputs;
/* BOLT #3:
*
@ -35,11 +36,13 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs,
* - MUST be calculated to match:
* 1. Start with `weight` = 724 (1124 if `option_anchors` applies).
*/
if (option_anchor_outputs)
if (option_anchor_outputs) {
weight = 1124;
else
num_outputs = 4;
} else {
weight = 724;
num_outputs = 2;
}
/* BOLT #3:
*
* 2. For each committed HTLC, if that output is not trimmed as
@ -47,9 +50,10 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs,
* to `weight`.
*/
weight += 172 * num_untrimmed_htlcs;
num_outputs += num_untrimmed_htlcs;
/* Extra fields for Elements */
weight += elements_tx_overhead(chainparams, 1, 1);
weight += elements_tx_overhead(chainparams, 1, num_outputs);
return weight;
}

View file

@ -10,7 +10,7 @@ from utils import (
check_coin_moves, first_channel_id, account_balance, basic_fee,
scriptpubkey_addr, default_ln_port,
EXPERIMENTAL_FEATURES, mine_funding_to_announce, first_scid,
anchor_expected
anchor_expected, CHANNEL_SIZE
)
from pyln.testing.utils import SLOW_MACHINE, VALGRIND, EXPERIMENTAL_DUAL_FUND, FUNDAMOUNT
@ -530,13 +530,13 @@ def test_disconnect_opener(node_factory):
for d in disconnects:
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
with pytest.raises(RpcError):
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# First peer valishes, but later it just disconnects
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
# This one will succeed.
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# Should still only have one peer!
assert len(l1.rpc.listpeers()['peers']) == 1
@ -575,13 +575,13 @@ def test_disconnect_fundee(node_factory):
for d in disconnects:
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
with pytest.raises(RpcError):
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# First peer valishes, but later it just disconnects
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
# This one will succeed.
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# Should still only have one peer!
assert len(l1.rpc.listpeers()) == 1
@ -615,12 +615,12 @@ def test_disconnect_fundee_v2(node_factory):
for d in disconnects:
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
with pytest.raises(RpcError):
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
assert l1.rpc.getpeer(l2.info['id']) is None
# This one will succeed.
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# Should still only have one peer!
assert len(l1.rpc.listpeers()['peers']) == 1
@ -643,7 +643,7 @@ def test_disconnect_half_signed(node_factory):
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
with pytest.raises(RpcError):
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# Peer remembers, opener doesn't.
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
@ -666,7 +666,7 @@ def test_reconnect_signed(node_factory):
l1.fundwallet(2000000)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
# They haven't forgotten each other.
assert l1.rpc.getpeer(l2.info['id'])['id'] == l2.info['id']
@ -706,7 +706,7 @@ def test_reconnect_openingd(node_factory):
# l2 closes on l1, l1 forgets.
with pytest.raises(RpcError):
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
assert l1.rpc.getpeer(l2.info['id']) is None
# Reconnect.
@ -717,7 +717,7 @@ def test_reconnect_openingd(node_factory):
l2.daemon.wait_for_log('Handed peer, entering loop')
# Should work fine.
l1.rpc.fundchannel(l2.info['id'], 25000)
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
l1.daemon.wait_for_log('sendrawtx exit 0')
l1.bitcoin.generate_block(3)

View file

@ -6,7 +6,7 @@ from pyln.client import RpcError, Millisatoshi
from utils import (
DEVELOPER, wait_for, TIMEOUT, only_one, sync_blockheight,
expected_node_features,
mine_funding_to_announce, default_ln_port
mine_funding_to_announce, default_ln_port, CHANNEL_SIZE
)
import json
@ -632,11 +632,11 @@ def test_routing_gossip_reconnect(node_factory):
{'may_reconnect': True},
{}])
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.openchannel(l2, 25000)
l1.openchannel(l2, CHANNEL_SIZE)
# Now open new channels and everybody should sync
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
l2.openchannel(l3, 25000)
l2.openchannel(l3, CHANNEL_SIZE)
# Settle the gossip
for n in [l1, l2, l3]:
@ -694,7 +694,7 @@ def test_routing_gossip(node_factory, bitcoind):
for i in range(len(nodes) - 1):
src, dst = nodes[i], nodes[i + 1]
src.rpc.connect(dst.info['id'], 'localhost', dst.port)
src.openchannel(dst, 25000, confirm=False, wait_for_announce=False)
src.openchannel(dst, CHANNEL_SIZE, confirm=False, wait_for_announce=False)
# openchannel calls fundwallet which mines a block; so first channel
# is 4 deep, last is unconfirmed.

View file

@ -8,6 +8,10 @@ import time
EXPERIMENTAL_FEATURES = env("EXPERIMENTAL_FEATURES", "0") == "1"
COMPAT = env("COMPAT", "1") == "1"
# Big enough to make channels with 10k effective capacity, including Elements channels
# which have bigger txns
CHANNEL_SIZE = 50000
def default_ln_port(network: str) -> int:
network_map = {