From eef0c087fc86c08bac0bde5187f5a0fd4d587e20 Mon Sep 17 00:00:00 2001 From: Greg Sanders Date: Fri, 3 Feb 2023 11:32:29 -0500 Subject: [PATCH] More accurate elements commitment tx size estimation --- common/initial_commit_tx.h | 12 ++++++++---- tests/test_connection.py | 22 +++++++++++----------- tests/test_gossip.py | 8 ++++---- tests/utils.py | 4 ++++ 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/common/initial_commit_tx.h b/common/initial_commit_tx.h index 7a5edf0f2..4e7e39b3b 100644 --- a/common/initial_commit_tx.h +++ b/common/initial_commit_tx.h @@ -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; } diff --git a/tests/test_connection.py b/tests/test_connection.py index 4b106ef07..b9d176ce4 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -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) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index c5ee3dcd3..506795739 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -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. diff --git a/tests/utils.py b/tests/utils.py index d81758d1f..9b8eea7e0 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -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 = {