mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-04 03:03:51 +01:00
More accurate elements commitment tx size estimation
This commit is contained in:
parent
dc4ae9deb4
commit
eef0c087fc
4 changed files with 27 additions and 19 deletions
|
@ -28,6 +28,7 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs,
|
||||||
bool option_anchor_outputs)
|
bool option_anchor_outputs)
|
||||||
{
|
{
|
||||||
size_t weight;
|
size_t weight;
|
||||||
|
size_t num_outputs;
|
||||||
|
|
||||||
/* BOLT #3:
|
/* BOLT #3:
|
||||||
*
|
*
|
||||||
|
@ -35,11 +36,13 @@ static inline size_t commit_tx_base_weight(size_t num_untrimmed_htlcs,
|
||||||
* - MUST be calculated to match:
|
* - MUST be calculated to match:
|
||||||
* 1. Start with `weight` = 724 (1124 if `option_anchors` applies).
|
* 1. Start with `weight` = 724 (1124 if `option_anchors` applies).
|
||||||
*/
|
*/
|
||||||
if (option_anchor_outputs)
|
if (option_anchor_outputs) {
|
||||||
weight = 1124;
|
weight = 1124;
|
||||||
else
|
num_outputs = 4;
|
||||||
|
} else {
|
||||||
weight = 724;
|
weight = 724;
|
||||||
|
num_outputs = 2;
|
||||||
|
}
|
||||||
/* BOLT #3:
|
/* BOLT #3:
|
||||||
*
|
*
|
||||||
* 2. For each committed HTLC, if that output is not trimmed as
|
* 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`.
|
* to `weight`.
|
||||||
*/
|
*/
|
||||||
weight += 172 * num_untrimmed_htlcs;
|
weight += 172 * num_untrimmed_htlcs;
|
||||||
|
num_outputs += num_untrimmed_htlcs;
|
||||||
|
|
||||||
/* Extra fields for Elements */
|
/* Extra fields for Elements */
|
||||||
weight += elements_tx_overhead(chainparams, 1, 1);
|
weight += elements_tx_overhead(chainparams, 1, num_outputs);
|
||||||
|
|
||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ from utils import (
|
||||||
check_coin_moves, first_channel_id, account_balance, basic_fee,
|
check_coin_moves, first_channel_id, account_balance, basic_fee,
|
||||||
scriptpubkey_addr, default_ln_port,
|
scriptpubkey_addr, default_ln_port,
|
||||||
EXPERIMENTAL_FEATURES, mine_funding_to_announce, first_scid,
|
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
|
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:
|
for d in disconnects:
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
with pytest.raises(RpcError):
|
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
|
# First peer valishes, but later it just disconnects
|
||||||
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
||||||
|
|
||||||
# This one will succeed.
|
# This one will succeed.
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
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!
|
# Should still only have one peer!
|
||||||
assert len(l1.rpc.listpeers()['peers']) == 1
|
assert len(l1.rpc.listpeers()['peers']) == 1
|
||||||
|
@ -575,13 +575,13 @@ def test_disconnect_fundee(node_factory):
|
||||||
for d in disconnects:
|
for d in disconnects:
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
with pytest.raises(RpcError):
|
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
|
# First peer valishes, but later it just disconnects
|
||||||
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
wait_for(lambda: all([p['connected'] is False for p in l1.rpc.listpeers()['peers']]))
|
||||||
|
|
||||||
# This one will succeed.
|
# This one will succeed.
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
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!
|
# Should still only have one peer!
|
||||||
assert len(l1.rpc.listpeers()) == 1
|
assert len(l1.rpc.listpeers()) == 1
|
||||||
|
@ -615,12 +615,12 @@ def test_disconnect_fundee_v2(node_factory):
|
||||||
for d in disconnects:
|
for d in disconnects:
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
with pytest.raises(RpcError):
|
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
|
assert l1.rpc.getpeer(l2.info['id']) is None
|
||||||
|
|
||||||
# This one will succeed.
|
# This one will succeed.
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
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!
|
# Should still only have one peer!
|
||||||
assert len(l1.rpc.listpeers()['peers']) == 1
|
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)
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||||
with pytest.raises(RpcError):
|
with pytest.raises(RpcError):
|
||||||
l1.rpc.fundchannel(l2.info['id'], 25000)
|
l1.rpc.fundchannel(l2.info['id'], CHANNEL_SIZE)
|
||||||
|
|
||||||
# Peer remembers, opener doesn't.
|
# Peer remembers, opener doesn't.
|
||||||
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'] == [])
|
||||||
|
@ -666,7 +666,7 @@ def test_reconnect_signed(node_factory):
|
||||||
l1.fundwallet(2000000)
|
l1.fundwallet(2000000)
|
||||||
|
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
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.
|
# They haven't forgotten each other.
|
||||||
assert l1.rpc.getpeer(l2.info['id'])['id'] == l2.info['id']
|
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.
|
# l2 closes on l1, l1 forgets.
|
||||||
with pytest.raises(RpcError):
|
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
|
assert l1.rpc.getpeer(l2.info['id']) is None
|
||||||
|
|
||||||
# Reconnect.
|
# Reconnect.
|
||||||
|
@ -717,7 +717,7 @@ def test_reconnect_openingd(node_factory):
|
||||||
l2.daemon.wait_for_log('Handed peer, entering loop')
|
l2.daemon.wait_for_log('Handed peer, entering loop')
|
||||||
|
|
||||||
# Should work fine.
|
# 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.daemon.wait_for_log('sendrawtx exit 0')
|
||||||
|
|
||||||
l1.bitcoin.generate_block(3)
|
l1.bitcoin.generate_block(3)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from pyln.client import RpcError, Millisatoshi
|
||||||
from utils import (
|
from utils import (
|
||||||
DEVELOPER, wait_for, TIMEOUT, only_one, sync_blockheight,
|
DEVELOPER, wait_for, TIMEOUT, only_one, sync_blockheight,
|
||||||
expected_node_features,
|
expected_node_features,
|
||||||
mine_funding_to_announce, default_ln_port
|
mine_funding_to_announce, default_ln_port, CHANNEL_SIZE
|
||||||
)
|
)
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -632,11 +632,11 @@ def test_routing_gossip_reconnect(node_factory):
|
||||||
{'may_reconnect': True},
|
{'may_reconnect': True},
|
||||||
{}])
|
{}])
|
||||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
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
|
# Now open new channels and everybody should sync
|
||||||
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
l2.rpc.connect(l3.info['id'], 'localhost', l3.port)
|
||||||
l2.openchannel(l3, 25000)
|
l2.openchannel(l3, CHANNEL_SIZE)
|
||||||
|
|
||||||
# Settle the gossip
|
# Settle the gossip
|
||||||
for n in [l1, l2, l3]:
|
for n in [l1, l2, l3]:
|
||||||
|
@ -694,7 +694,7 @@ def test_routing_gossip(node_factory, bitcoind):
|
||||||
for i in range(len(nodes) - 1):
|
for i in range(len(nodes) - 1):
|
||||||
src, dst = nodes[i], nodes[i + 1]
|
src, dst = nodes[i], nodes[i + 1]
|
||||||
src.rpc.connect(dst.info['id'], 'localhost', dst.port)
|
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
|
# openchannel calls fundwallet which mines a block; so first channel
|
||||||
# is 4 deep, last is unconfirmed.
|
# is 4 deep, last is unconfirmed.
|
||||||
|
|
|
@ -8,6 +8,10 @@ import time
|
||||||
EXPERIMENTAL_FEATURES = env("EXPERIMENTAL_FEATURES", "0") == "1"
|
EXPERIMENTAL_FEATURES = env("EXPERIMENTAL_FEATURES", "0") == "1"
|
||||||
COMPAT = env("COMPAT", "1") == "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:
|
def default_ln_port(network: str) -> int:
|
||||||
network_map = {
|
network_map = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue