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:
niftynei
2022-10-19 13:35:45 -05:00
committed by Rusty Russell
parent efe66f9689
commit c9c367d770
10 changed files with 88 additions and 56 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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))));

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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'

View File

@@ -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

View File

@@ -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):

View File

@@ -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)