lightningd: add large-channels / wumbo option.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Changelog-added: `large-channels` option to negotiate opening larger channels.
This commit is contained in:
Rusty Russell
2020-04-03 10:33:58 +10:30
parent 1d90f21833
commit 07a281faf8
4 changed files with 77 additions and 1 deletions

View File

@@ -281,6 +281,14 @@ extremely busy node for you to even notice\.
.SH Lightning channel and HTLC options .SH Lightning channel and HTLC options
\fBlarge-channels\fR
Removes capacity limits for channel creation\. Version 1\.0 of the specification
limited channel sizes to 16777216 satoshi\. With this option (which your
node will advertize to peers), your node will accept larger incoming channels
and if the peer supports it, will open larger channels\. Note: this option
is spelled \fBlarge-channels\fR but it's pronounced \fBwumbo\fR\.
\fBwatchtime-blocks\fR=\fIBLOCKS\fR \fBwatchtime-blocks\fR=\fIBLOCKS\fR
How long we need to spot an outdated close attempt: on opening a channel How long we need to spot an outdated close attempt: on opening a channel
we tell our peer that this is how long theyll have to wait if they we tell our peer that this is how long theyll have to wait if they

View File

@@ -230,6 +230,13 @@ extremely busy node for you to even notice.
### Lightning channel and HTLC options ### Lightning channel and HTLC options
**large-channels**
Removes capacity limits for channel creation. Version 1.0 of the specification
limited channel sizes to 16777215 satoshi. With this option (which your
node will advertize to peers), your node will accept larger incoming channels
and if the peer supports it, will open larger channels. Note: this option
is spelled **large-channels** but it's pronounced **wumbo**.
**watchtime-blocks**=*BLOCKS* **watchtime-blocks**=*BLOCKS*
How long we need to spot an outdated close attempt: on opening a channel How long we need to spot an outdated close attempt: on opening a channel
we tell our peer that this is how long theyll have to wait if they we tell our peer that this is how long theyll have to wait if they

View File

@@ -742,6 +742,14 @@ static char *opt_start_daemon(struct lightningd *ld)
errx(1, "Died with signal %u", WTERMSIG(exitcode)); errx(1, "Died with signal %u", WTERMSIG(exitcode));
} }
static char *opt_set_wumbo(struct lightningd *ld)
{
feature_set_or(ld->feature_set,
take(feature_set_for_feature(NULL,
OPTIONAL_FEATURE(OPT_LARGE_CHANNELS))));
return NULL;
}
static void register_opts(struct lightningd *ld) static void register_opts(struct lightningd *ld)
{ {
/* This happens before plugins started */ /* This happens before plugins started */
@@ -774,6 +782,11 @@ static void register_opts(struct lightningd *ld)
&ld->wallet_dsn, &ld->wallet_dsn,
"Location of the wallet database."); "Location of the wallet database.");
/* This affects our features, so set early. */
opt_register_early_noarg("--large-channels|--wumbo",
opt_set_wumbo, ld,
"Allow channels larger than 0.16777215 BTC");
opt_register_noarg("--help|-h", opt_lightningd_usage, ld, opt_register_noarg("--help|-h", opt_lightningd_usage, ld,
"Print this message."); "Print this message.");
opt_register_arg("--rgb", opt_set_rgb, NULL, ld, opt_register_arg("--rgb", opt_set_rgb, NULL, ld,
@@ -1188,6 +1201,10 @@ static void add_config(struct lightningd *ld,
? "false" : "true"); ? "false" : "true");
} else if (opt->cb == (void *)opt_set_hsm_password) { } else if (opt->cb == (void *)opt_set_hsm_password) {
json_add_bool(response, "encrypted-hsm", ld->encrypted_hsm); json_add_bool(response, "encrypted-hsm", ld->encrypted_hsm);
} else if (opt->cb == (void *)opt_set_wumbo) {
json_add_bool(response, "wumbo",
feature_offered(ld->feature_set->bits[INIT_FEATURE],
OPT_LARGE_CHANNELS));
} else { } else {
/* Insert more decodes here! */ /* Insert more decodes here! */
assert(!"A noarg option was added but was not handled"); assert(!"A noarg option was added but was not handled");

View File

@@ -3,7 +3,7 @@ from decimal import Decimal
from fixtures import * # noqa: F401,F403 from fixtures import * # noqa: F401,F403
from fixtures import TEST_NETWORK from fixtures import TEST_NETWORK
from flaky import flaky # noqa: F401 from flaky import flaky # noqa: F401
from pyln.client import RpcError from pyln.client import RpcError, Millisatoshi
from utils import ( from utils import (
DEVELOPER, only_one, wait_for, sync_blockheight, VALGRIND, TIMEOUT, DEVELOPER, only_one, wait_for, sync_blockheight, VALGRIND, TIMEOUT,
SLOW_MACHINE, expected_features SLOW_MACHINE, expected_features
@@ -2220,3 +2220,47 @@ def test_pay_disconnect_stress(node_factory, executor):
pass pass
fut.result() fut.result()
def test_wumbo_channels(node_factory, bitcoind):
f = bytes.fromhex(expected_features())
# OPT_LARGE_CHANNELS = 18 (19 for us). 0x080000
f = (f[:-3] + bytes([f[-3] | 0x08]) + f[-2:]).hex()
l1, l2, l3 = node_factory.get_nodes(3,
opts=[{'large-channels': None},
{'large-channels': None},
{}])
conn = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.port)
assert conn['features'] == f
assert only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['features'] == f
# Now, can we open a giant channel?
l1.fundwallet(1 << 26)
l1.rpc.fundchannel(l2.info['id'], 1 << 24)
# Get that mined, and announced.
bitcoind.generate_block(6, wait_for_mempool=1)
# Connect l3, get gossip.
l3.rpc.connect(l1.info['id'], 'localhost', port=l1.port)
wait_for(lambda: len(l3.rpc.listnodes(l1.info['id'])['nodes']) == 1)
wait_for(lambda: 'features' in only_one(l3.rpc.listnodes(l1.info['id'])['nodes']))
# Make sure channel capacity is what we expected.
assert ([c['amount_msat'] for c in l3.rpc.listchannels()['channels']]
== [Millisatoshi(str(1 << 24) + "sat")] * 2)
# Make sure we can't open a wumbo channel if we don't agree.
with pytest.raises(RpcError, match='Amount exceeded'):
l1.rpc.fundchannel(l3.info['id'], 1 << 24)
# But we can open and announce a normal one.
l1.rpc.fundchannel(l3.info['id'], 'all')
bitcoind.generate_block(6, wait_for_mempool=1)
wait_for(lambda: l1.channel_state(l3) == 'CHANNELD_NORMAL')
# Make sure l2 sees correct size.
wait_for(lambda: [c['amount_msat'] for c in l2.rpc.listchannels(l1.get_channel_scid(l3))['channels']]
== [Millisatoshi(str((1 << 24) - 1) + "sat")] * 2)