mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-18 22:54:25 +01:00
dual-fund: remove anchor assumption for all dual-funded channels
Only add the anchor channel_type if it's negotiated separately!
This commit is contained in:
@@ -250,11 +250,14 @@ struct channel *new_unsaved_channel(struct peer *peer,
|
||||
/* BOLT-7b04b1461739c5036add61782d58ac490842d98b #9
|
||||
* | 222/223 | `option_dual_fund`
|
||||
* | Use v2 of channel open, enables dual funding
|
||||
* | IN9
|
||||
* | `option_anchor_outputs` */
|
||||
* | IN9 */
|
||||
channel->static_remotekey_start[LOCAL]
|
||||
= channel->static_remotekey_start[REMOTE] = 0;
|
||||
channel->type = channel_type_anchor_outputs(channel);
|
||||
|
||||
channel->type = default_channel_type(channel,
|
||||
peer->ld->our_features,
|
||||
peer->their_features);
|
||||
|
||||
channel->future_per_commitment_point = NULL;
|
||||
|
||||
channel->lease_commit_sig = NULL;
|
||||
|
||||
@@ -2605,8 +2605,6 @@ static struct command_result *init_set_feerate(struct command *cmd,
|
||||
}
|
||||
if (!*feerate_per_kw) {
|
||||
*feerate_per_kw = tal(cmd, u32);
|
||||
/* FIXME: Anchors are on by default, we should use the lowest
|
||||
* possible feerate */
|
||||
**feerate_per_kw = **feerate_per_kw_funding;
|
||||
}
|
||||
|
||||
|
||||
@@ -1045,10 +1045,10 @@ static char *opt_set_websocket_port(const char *arg, struct lightningd *ld)
|
||||
|
||||
static char *opt_set_dual_fund(struct lightningd *ld)
|
||||
{
|
||||
/* Dual funding implies anchor outputs */
|
||||
/* Dual funding implies static remotkey */
|
||||
feature_set_or(ld->our_features,
|
||||
take(feature_set_for_feature(NULL,
|
||||
OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS))));
|
||||
OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY))));
|
||||
feature_set_or(ld->our_features,
|
||||
take(feature_set_for_feature(NULL,
|
||||
OPTIONAL_FEATURE(OPT_DUAL_FUND))));
|
||||
|
||||
@@ -4,7 +4,8 @@ from pyln.client import Millisatoshi
|
||||
from db import Sqlite3Db
|
||||
from fixtures import TEST_NETWORK
|
||||
from utils import (
|
||||
sync_blockheight, wait_for, only_one, first_channel_id, TIMEOUT
|
||||
sync_blockheight, wait_for, only_one, first_channel_id, TIMEOUT,
|
||||
anchor_expected
|
||||
)
|
||||
|
||||
from pathlib import Path
|
||||
@@ -332,6 +333,7 @@ def test_bookkeeping_rbf_withdraw(node_factory, bitcoind):
|
||||
@pytest.mark.openchannel('v2')
|
||||
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "turns off bookkeeper at start")
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', "network fees hardcoded")
|
||||
@pytest.mark.developer("dev-force-features")
|
||||
def test_bookkeeping_missed_chans_leases(node_factory, bitcoind):
|
||||
"""
|
||||
Test that a lease is correctly recorded if bookkeeper was off
|
||||
@@ -342,6 +344,10 @@ def test_bookkeeping_missed_chans_leases(node_factory, bitcoind):
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'plugin': str(coin_mvt_plugin),
|
||||
'disable-plugin': 'bookkeeper'}
|
||||
|
||||
if not anchor_expected():
|
||||
opts['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2 = node_factory.get_nodes(2, opts=opts)
|
||||
|
||||
open_amt = 500000
|
||||
|
||||
@@ -739,7 +739,7 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams):
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.slow_test
|
||||
@pytest.mark.developer("requres 'dev-queryrates'")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', 'dev-force-features'")
|
||||
def test_channel_lease_falls_behind(node_factory, bitcoind):
|
||||
'''
|
||||
If our peer falls too far behind/doesn't send us an update for
|
||||
@@ -749,6 +749,11 @@ def test_channel_lease_falls_behind(node_factory, bitcoind):
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100},
|
||||
{'funder-policy': 'match', 'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
amount = 500000
|
||||
feerate = 2000
|
||||
@@ -779,7 +784,7 @@ def test_channel_lease_falls_behind(node_factory, bitcoind):
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("requres 'dev-queryrates'")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', 'dev-force-features'")
|
||||
@pytest.mark.slow_test
|
||||
def test_channel_lease_post_expiry(node_factory, bitcoind, chainparams):
|
||||
|
||||
@@ -789,6 +794,9 @@ def test_channel_lease_post_expiry(node_factory, bitcoind, chainparams):
|
||||
'may_reconnect': True, 'plugin': coin_mvt_plugin,
|
||||
'dev-no-reconnect': None}
|
||||
|
||||
if not anchor_expected():
|
||||
opts['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
|
||||
feerate = 2000
|
||||
@@ -893,7 +901,7 @@ def test_channel_lease_post_expiry(node_factory, bitcoind, chainparams):
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.slow_test
|
||||
@pytest.mark.developer("requres 'dev-queryrates'")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', 'dev-force-features'")
|
||||
def test_channel_lease_unilat_closes(node_factory, bitcoind):
|
||||
'''
|
||||
Check that channel leases work
|
||||
@@ -905,6 +913,9 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind):
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'funder-lease-requests-only': False}
|
||||
|
||||
if not anchor_expected():
|
||||
opts['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, l3 = node_factory.get_nodes(3, opts=opts)
|
||||
# Allow l2 some warnings
|
||||
l2.allow_warning = True
|
||||
@@ -1005,7 +1016,7 @@ def test_channel_lease_unilat_closes(node_factory, bitcoind):
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db")
|
||||
@pytest.mark.developer("requres 'dev-queryrates'")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', 'dev-force-features'")
|
||||
def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
|
||||
'''
|
||||
Check that lessee can recover funds if lessor cheats
|
||||
@@ -1019,6 +1030,11 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'may_reconnect': True, 'allow_broken_log': True,
|
||||
'plugin': balance_snaps}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
amount = 500000
|
||||
feerate = 2000
|
||||
@@ -1081,7 +1097,7 @@ def test_channel_lease_lessor_cheat(node_factory, bitcoind, chainparams):
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@unittest.skipIf(os.getenv('TEST_DB_PROVIDER', 'sqlite3') != 'sqlite3', "Makes use of the sqlite3 db")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', dev-no-reconnect")
|
||||
@pytest.mark.developer("requres 'dev-queryrates', dev-no-reconnect, dev-force-features")
|
||||
def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams):
|
||||
'''
|
||||
Check that lessor can recover funds if lessee cheats
|
||||
@@ -1093,6 +1109,11 @@ def test_channel_lease_lessee_cheat(node_factory, bitcoind, chainparams):
|
||||
{'funder-policy': 'match', 'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'may_reconnect': True, 'dev-no-reconnect': None}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
amount = 500000
|
||||
feerate = 2000
|
||||
|
||||
@@ -2668,12 +2668,8 @@ def test_forget_channel(node_factory):
|
||||
def test_peerinfo(node_factory, bitcoind):
|
||||
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts={'may_reconnect': True})
|
||||
|
||||
if l1.config('experimental-dual-fund'):
|
||||
lfeatures = expected_peer_features(extra=[21, 29])
|
||||
nfeatures = expected_node_features(extra=[21, 29])
|
||||
else:
|
||||
lfeatures = expected_peer_features()
|
||||
nfeatures = expected_node_features()
|
||||
lfeatures = expected_peer_features()
|
||||
nfeatures = expected_node_features()
|
||||
|
||||
# Gossiping but no node announcement yet
|
||||
assert l1.rpc.getpeer(l2.info['id'])['connected']
|
||||
@@ -3469,10 +3465,6 @@ def test_wumbo_channels(node_factory, bitcoind):
|
||||
conn = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
|
||||
|
||||
expected_features = expected_peer_features(wumbo_channels=True)
|
||||
if l1.config('experimental-dual-fund'):
|
||||
expected_features = expected_peer_features(wumbo_channels=True,
|
||||
extra=[21, 29])
|
||||
|
||||
assert conn['features'] == expected_features
|
||||
assert only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['features'] == expected_features
|
||||
|
||||
@@ -3557,7 +3549,7 @@ def test_channel_features(node_factory, bitcoind):
|
||||
# We should see features in unconfirmed channels.
|
||||
chan = only_one(l1.rpc.listpeerchannels()['channels'])
|
||||
assert 'option_static_remotekey' in chan['features']
|
||||
if EXPERIMENTAL_FEATURES or l1.config('experimental-dual-fund'):
|
||||
if EXPERIMENTAL_FEATURES:
|
||||
assert 'option_anchor_outputs' in chan['features']
|
||||
|
||||
# l2 should agree.
|
||||
@@ -3570,7 +3562,7 @@ def test_channel_features(node_factory, bitcoind):
|
||||
|
||||
chan = only_one(l1.rpc.listpeerchannels()['channels'])
|
||||
assert 'option_static_remotekey' in chan['features']
|
||||
if EXPERIMENTAL_FEATURES or l1.config('experimental-dual-fund'):
|
||||
if EXPERIMENTAL_FEATURES:
|
||||
assert 'option_anchor_outputs' in chan['features']
|
||||
|
||||
# l2 should agree.
|
||||
|
||||
@@ -1307,12 +1307,8 @@ def test_node_reannounce(node_factory, bitcoind, chainparams):
|
||||
wait_for(lambda: 'alias' in only_one(l2.rpc.listnodes(l1.info['id'])['nodes']))
|
||||
assert only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['alias'].startswith('JUNIORBEAM')
|
||||
|
||||
lfeatures = expected_node_features()
|
||||
if l1.config('experimental-dual-fund'):
|
||||
lfeatures = expected_node_features(extra=[21, 29])
|
||||
|
||||
# Make sure it gets features correct.
|
||||
assert only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['features'] == lfeatures
|
||||
assert only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])['features'] == expected_node_features()
|
||||
|
||||
l1.stop()
|
||||
l1.daemon.opts['alias'] = 'SENIORBEAM'
|
||||
|
||||
@@ -2,7 +2,7 @@ from fixtures import * # noqa: F401,F403
|
||||
from fixtures import TEST_NETWORK
|
||||
from pyln.client import RpcError, Millisatoshi
|
||||
from utils import (
|
||||
only_one, wait_for, sync_blockheight, first_channel_id, calc_lease_fee, check_coin_moves
|
||||
only_one, wait_for, sync_blockheight, first_channel_id, calc_lease_fee, check_coin_moves, anchor_expected
|
||||
)
|
||||
|
||||
from pathlib import Path
|
||||
@@ -19,9 +19,15 @@ def find_next_feerate(node, peer):
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("requres 'dev-queryrates'")
|
||||
@pytest.mark.developer("requres 'dev-queryrates' + 'dev-force-features'")
|
||||
def test_queryrates(node_factory, bitcoind):
|
||||
l1, l2 = node_factory.get_nodes(2, opts={'dev-no-reconnect': None})
|
||||
|
||||
opts = {'dev-no-reconnect': None}
|
||||
|
||||
if not anchor_expected():
|
||||
opts['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2 = node_factory.get_nodes(2, opts=opts)
|
||||
|
||||
amount = 10 ** 6
|
||||
|
||||
@@ -340,11 +346,16 @@ def test_v2_rbf_single(node_factory, bitcoind, chainparams):
|
||||
|
||||
@unittest.skipIf(TEST_NETWORK != 'regtest', 'elementsd doesnt yet support PSBT features we need')
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("requres 'dev-force-features'")
|
||||
def test_v2_rbf_liquidity_ad(node_factory, bitcoind, chainparams):
|
||||
|
||||
opts = {'funder-policy': 'match', 'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'may_reconnect': True}
|
||||
|
||||
if not anchor_expected():
|
||||
opts['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2 = node_factory.get_nodes(2, opts=opts)
|
||||
|
||||
# what happens when we RBF?
|
||||
@@ -1216,21 +1227,23 @@ def test_funder_contribution_limits(node_factory, bitcoind):
|
||||
|
||||
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("requres 'dev-disconnect'")
|
||||
@pytest.mark.developer("requres 'dev-disconnect', 'dev-force-features'")
|
||||
def test_inflight_dbload(node_factory, bitcoind):
|
||||
"""Bad db field access breaks Postgresql on startup with opening leases"""
|
||||
disconnects = ["@WIRE_COMMITMENT_SIGNED"]
|
||||
l1, l2 = node_factory.get_nodes(2, opts=[{'experimental-dual-fund': None,
|
||||
'dev-no-reconnect': None,
|
||||
'may_reconnect': True,
|
||||
'disconnect': disconnects},
|
||||
{'experimental-dual-fund': None,
|
||||
'dev-no-reconnect': None,
|
||||
'may_reconnect': True,
|
||||
'funder-policy': 'match',
|
||||
'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat',
|
||||
'lease-fee-basis': 100}])
|
||||
|
||||
opts = [{'experimental-dual-fund': None, 'dev-no-reconnect': None,
|
||||
'may_reconnect': True, 'disconnect': disconnects},
|
||||
{'experimental-dual-fund': None, 'dev-no-reconnect': None,
|
||||
'may_reconnect': True, 'funder-policy': 'match',
|
||||
'funder-policy-mod': 100, 'lease-fee-base-sat': '100sat',
|
||||
'lease-fee-basis': 100}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2 = node_factory.get_nodes(2, opts=opts)
|
||||
|
||||
feerate = 2000
|
||||
amount = 500000
|
||||
@@ -1528,6 +1541,7 @@ def test_buy_liquidity_ad_no_v2(node_factory, bitcoind):
|
||||
|
||||
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("dev-force-features required")
|
||||
def test_v2_replay_bookkeeping(node_factory, bitcoind):
|
||||
""" Test that your bookkeeping for a liquidity ad is good
|
||||
even if we replay the opening and locking tx!
|
||||
@@ -1539,6 +1553,11 @@ def test_v2_replay_bookkeeping(node_factory, bitcoind):
|
||||
{'funder-policy': 'match', 'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'may_reconnect': True}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
amount = 500000
|
||||
feerate = 2000
|
||||
@@ -1591,6 +1610,7 @@ def test_v2_replay_bookkeeping(node_factory, bitcoind):
|
||||
|
||||
|
||||
@pytest.mark.openchannel('v2')
|
||||
@pytest.mark.developer("dev-force-features required")
|
||||
def test_buy_liquidity_ad_check_bookkeeping(node_factory, bitcoind):
|
||||
""" Test that your bookkeeping for a liquidity ad is good."""
|
||||
|
||||
@@ -1601,6 +1621,11 @@ def test_buy_liquidity_ad_check_bookkeeping(node_factory, bitcoind):
|
||||
{'funder-policy': 'match', 'funder-policy-mod': 100,
|
||||
'lease-fee-base-sat': '100sat', 'lease-fee-basis': 100,
|
||||
'may_reconnect': True}]
|
||||
|
||||
if not anchor_expected():
|
||||
for opt in opts:
|
||||
opt['dev-force-features'] = '+21'
|
||||
|
||||
l1, l2, = node_factory.get_nodes(2, opts=opts)
|
||||
amount = 500000
|
||||
feerate = 2000
|
||||
|
||||
@@ -1606,15 +1606,10 @@ def test_plugin_feature_announce(node_factory):
|
||||
wait_for_announce=True
|
||||
)
|
||||
|
||||
extra = []
|
||||
if l1.config('experimental-dual-fund'):
|
||||
extra.append(21) # option-anchor-outputs
|
||||
extra.append(29) # option-dual-fund
|
||||
|
||||
# Check the featurebits we've set in the `init` message from
|
||||
# feature-test.py.
|
||||
assert l1.daemon.is_in_log(r'\[OUT\] 001000022100....{}'
|
||||
.format(expected_peer_features(extra=[201] + extra)))
|
||||
.format(expected_peer_features(extra=[201])))
|
||||
|
||||
# Check the invoice featurebit we set in feature-test.py
|
||||
inv = l1.rpc.invoice(123, 'lbl', 'desc')['bolt11']
|
||||
@@ -1623,7 +1618,7 @@ def test_plugin_feature_announce(node_factory):
|
||||
|
||||
# Check the featurebit set in the `node_announcement`
|
||||
node = l1.rpc.listnodes(l1.info['id'])['nodes'][0]
|
||||
assert node['features'] == expected_node_features(extra=[203] + extra)
|
||||
assert node['features'] == expected_node_features(extra=[203])
|
||||
|
||||
|
||||
def test_hook_chaining(node_factory):
|
||||
|
||||
@@ -48,8 +48,6 @@ def expected_peer_features(wumbo_channels=False, extra=[]):
|
||||
if wumbo_channels:
|
||||
features += [19]
|
||||
if EXPERIMENTAL_DUAL_FUND:
|
||||
# option_anchor_outputs
|
||||
features += [21]
|
||||
# option_dual_fund
|
||||
features += [29]
|
||||
return hex_bits(features + extra)
|
||||
@@ -70,8 +68,6 @@ def expected_node_features(wumbo_channels=False, extra=[]):
|
||||
if wumbo_channels:
|
||||
features += [19]
|
||||
if EXPERIMENTAL_DUAL_FUND:
|
||||
# option_anchor_outputs
|
||||
features += [21]
|
||||
# option_dual_fund
|
||||
features += [29]
|
||||
return hex_bits(features + extra)
|
||||
|
||||
Reference in New Issue
Block a user