mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 18:57:06 +01:00
channeld: support private channel creation, fixes #2125
Adds a new 'announce' field for `fundchannel`, which if false won't broadcast a `channel_announcement`.
This commit is contained in:
parent
eab992cecd
commit
a39c97c960
5 changed files with 47 additions and 5 deletions
|
@ -417,6 +417,22 @@ static void channel_announcement_negotiate(struct peer *peer)
|
||||||
peer->channel_local_active = true;
|
peer->channel_local_active = true;
|
||||||
make_channel_local_active(peer);
|
make_channel_local_active(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BOLT #7:
|
||||||
|
*
|
||||||
|
* A node:
|
||||||
|
* - if the `open_channel` message has the `announce_channel` bit set
|
||||||
|
* AND a `shutdown` message has not been sent:
|
||||||
|
* - MUST send the `announcement_signatures` message.
|
||||||
|
* - MUST NOT send `announcement_signatures` messages until
|
||||||
|
* `funding_locked` has been sent AND the funding transaction has
|
||||||
|
* at least six confirmations.
|
||||||
|
* - otherwise:
|
||||||
|
* - MUST NOT send the `announcement_signatures` message.
|
||||||
|
*/
|
||||||
|
if (!(peer->channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL))
|
||||||
|
return;
|
||||||
|
|
||||||
/* BOLT #7:
|
/* BOLT #7:
|
||||||
*
|
*
|
||||||
* - MUST NOT send `announcement_signatures` messages until
|
* - MUST NOT send `announcement_signatures` messages until
|
||||||
|
|
|
@ -361,14 +361,17 @@ class LightningRpc(UnixDomainSocketRpc):
|
||||||
}
|
}
|
||||||
return self.call("listpeers", payload)
|
return self.call("listpeers", payload)
|
||||||
|
|
||||||
def fundchannel(self, node_id, satoshi, feerate=None):
|
def fundchannel(self, node_id, satoshi, feerate=None, announce=True):
|
||||||
"""
|
"""
|
||||||
Fund channel with {id} using {satoshi} satoshis"
|
Fund channel with {id} using {satoshi} satoshis
|
||||||
|
with feerate of {feerate} (uses default feerate if unset).
|
||||||
|
If {announce} is False, don't send channel announcements.
|
||||||
"""
|
"""
|
||||||
payload = {
|
payload = {
|
||||||
"id": node_id,
|
"id": node_id,
|
||||||
"satoshi": satoshi,
|
"satoshi": satoshi,
|
||||||
"feerate": feerate
|
"feerate": feerate,
|
||||||
|
"announce": announce
|
||||||
}
|
}
|
||||||
return self.call("fundchannel", payload)
|
return self.call("fundchannel", payload)
|
||||||
|
|
||||||
|
|
|
@ -770,6 +770,7 @@ static void json_fund_channel(struct command *cmd,
|
||||||
struct peer *peer;
|
struct peer *peer;
|
||||||
struct channel *channel;
|
struct channel *channel;
|
||||||
u32 *feerate_per_kw;
|
u32 *feerate_per_kw;
|
||||||
|
bool *announce_channel;
|
||||||
u8 *msg;
|
u8 *msg;
|
||||||
u64 max_funding_satoshi = get_chainparams(cmd->ld)->max_funding_satoshi;
|
u64 max_funding_satoshi = get_chainparams(cmd->ld)->max_funding_satoshi;
|
||||||
|
|
||||||
|
@ -780,6 +781,7 @@ static void json_fund_channel(struct command *cmd,
|
||||||
p_req("id", json_tok_pubkey, &id),
|
p_req("id", json_tok_pubkey, &id),
|
||||||
p_req("satoshi", json_tok_tok, &sattok),
|
p_req("satoshi", json_tok_tok, &sattok),
|
||||||
p_opt("feerate", json_tok_feerate, &feerate_per_kw),
|
p_opt("feerate", json_tok_feerate, &feerate_per_kw),
|
||||||
|
p_opt_def("announce", json_tok_bool, &announce_channel, true),
|
||||||
NULL))
|
NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -826,6 +828,11 @@ static void json_fund_channel(struct command *cmd,
|
||||||
/* FIXME: Support push_msat? */
|
/* FIXME: Support push_msat? */
|
||||||
fc->push_msat = 0;
|
fc->push_msat = 0;
|
||||||
fc->channel_flags = OUR_CHANNEL_FLAGS;
|
fc->channel_flags = OUR_CHANNEL_FLAGS;
|
||||||
|
if (!*announce_channel) {
|
||||||
|
fc->channel_flags &= ~CHANNEL_FLAGS_ANNOUNCE_CHANNEL;
|
||||||
|
log_info(peer->ld->log, "Will open private channel with node %s",
|
||||||
|
type_to_string(fc, struct pubkey, id));
|
||||||
|
}
|
||||||
|
|
||||||
if (!wtx_select_utxos(&fc->wtx, *feerate_per_kw,
|
if (!wtx_select_utxos(&fc->wtx, *feerate_per_kw,
|
||||||
BITCOIN_SCRIPTPUBKEY_P2WSH_LEN))
|
BITCOIN_SCRIPTPUBKEY_P2WSH_LEN))
|
||||||
|
|
|
@ -791,6 +791,21 @@ def test_channel_persistence(node_factory, bitcoind, executor):
|
||||||
l1.daemon.wait_for_log(' to ONCHAIN')
|
l1.daemon.wait_for_log(' to ONCHAIN')
|
||||||
|
|
||||||
|
|
||||||
|
def test_private_channel(node_factory):
|
||||||
|
l1, l2 = node_factory.line_graph(2, announce_channels=False, wait_for_announce=False)
|
||||||
|
l3, l4 = node_factory.line_graph(2, announce_channels=True, wait_for_announce=True)
|
||||||
|
|
||||||
|
assert l1.daemon.is_in_log('Will open private channel with node {}'.format(l2.info['id']))
|
||||||
|
assert not l2.daemon.is_in_log('Will open private channel with node {}'.format(l1.info['id']))
|
||||||
|
assert not l3.daemon.is_in_log('Will open private channel with node {}'.format(l4.info['id']))
|
||||||
|
|
||||||
|
l3.daemon.wait_for_log('Received node_announcement for node {}'.format(l4.info['id']))
|
||||||
|
l4.daemon.wait_for_log('Received node_announcement for node {}'.format(l3.info['id']))
|
||||||
|
|
||||||
|
assert not l1.daemon.is_in_log('Received node_announcement for node {}'.format(l2.info['id']))
|
||||||
|
assert not l2.daemon.is_in_log('Received node_announcement for node {}'.format(l1.info['id']))
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for --dev-broadcast-interval")
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for --dev-broadcast-interval")
|
||||||
def test_channel_reenable(node_factory):
|
def test_channel_reenable(node_factory):
|
||||||
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True}, fundchannel=True, wait_for_announce=True)
|
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True}, fundchannel=True, wait_for_announce=True)
|
||||||
|
|
|
@ -788,9 +788,10 @@ class NodeFactory(object):
|
||||||
raise
|
raise
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def line_graph(self, num_nodes, fundchannel=True, fundamount=10**6, wait_for_announce=False, opts=None):
|
def line_graph(self, num_nodes, fundchannel=True, fundamount=10**6, wait_for_announce=False, opts=None, announce_channels=True):
|
||||||
""" Create nodes, connect them and optionally fund channels.
|
""" Create nodes, connect them and optionally fund channels.
|
||||||
"""
|
"""
|
||||||
|
assert not (wait_for_announce and not announce_channels), "You've asked to wait for an announcement that's not coming. (wait_for_announce=True,announce_channels=False)"
|
||||||
nodes = self.get_nodes(num_nodes, opts=opts)
|
nodes = self.get_nodes(num_nodes, opts=opts)
|
||||||
bitcoin = nodes[0].bitcoin
|
bitcoin = nodes[0].bitcoin
|
||||||
connections = [(nodes[i], nodes[i + 1]) for i in range(0, num_nodes - 1)]
|
connections = [(nodes[i], nodes[i + 1]) for i in range(0, num_nodes - 1)]
|
||||||
|
@ -813,7 +814,7 @@ class NodeFactory(object):
|
||||||
bitcoin.generate_block(1)
|
bitcoin.generate_block(1)
|
||||||
for src, dst in connections:
|
for src, dst in connections:
|
||||||
wait_for(lambda: len(src.rpc.listfunds()['outputs']) > 0)
|
wait_for(lambda: len(src.rpc.listfunds()['outputs']) > 0)
|
||||||
tx = src.rpc.fundchannel(dst.info['id'], fundamount)
|
tx = src.rpc.fundchannel(dst.info['id'], fundamount, announce=announce_channels)
|
||||||
wait_for(lambda: tx['txid'] in bitcoin.rpc.getrawmempool())
|
wait_for(lambda: tx['txid'] in bitcoin.rpc.getrawmempool())
|
||||||
|
|
||||||
# Confirm all channels and wait for them to become usable
|
# Confirm all channels and wait for them to become usable
|
||||||
|
|
Loading…
Add table
Reference in a new issue