From 689dd28dddb062f0366aa3f1addb5602602c68a7 Mon Sep 17 00:00:00 2001 From: lisa neigut Date: Fri, 20 Dec 2019 23:53:12 -0600 Subject: [PATCH] funding: enable push_msat it's that time of year (merry xmas!) enables the ability to push_msat on fundchannel Changelog-Added: RPC: `fundchannel` and `fundchannel_start` can now accept an optional parameter, `push_msat`, which will gift that amount of satoshis to the peer at channel open. --- contrib/pyln-client/pyln/client/lightning.py | 5 ++-- doc/lightning-fundchannel.7 | 8 +++++- doc/lightning-fundchannel.7.md | 7 ++++- doc/lightning-fundchannel_start.7 | 8 +++++- doc/lightning-fundchannel_start.7.md | 7 ++++- lightningd/opening_control.c | 13 +++++++-- plugins/fundchannel.c | 6 ++++ tests/test_connection.py | 29 ++++++++++++++++++++ 8 files changed, 75 insertions(+), 8 deletions(-) diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index a10d28886..7c0d49687 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -548,14 +548,15 @@ class LightningRpc(UnixDomainSocketRpc): if 'satoshi' in kwargs: return self._deprecated_fundchannel(node_id, *args, **kwargs) - def _fundchannel(node_id, amount, feerate=None, announce=True, minconf=None, utxos=None): + def _fundchannel(node_id, amount, feerate=None, announce=True, minconf=None, utxos=None, push_msat=None): payload = { "id": node_id, "amount": amount, "feerate": feerate, "announce": announce, "minconf": minconf, - "utxos": utxos + "utxos": utxos, + "push_msat": push_msat } return self.call("fundchannel", payload) diff --git a/doc/lightning-fundchannel.7 b/doc/lightning-fundchannel.7 index 78b48ffbf..f072c8d7d 100644 --- a/doc/lightning-fundchannel.7 +++ b/doc/lightning-fundchannel.7 @@ -4,7 +4,7 @@ lightning-fundchannel - Command for establishing a lightning channel .SH SYNOPSIS \fBfundchannel\fR \fIid\fR \fIamount\fR [\fIfeerate\fR \fIannounce\fR] [\fIminconf\fR] -[\fIutxos\fR] +[\fIutxos\fR] [\fIpush_msat\fR] .SH DESCRIPTION @@ -54,6 +54,12 @@ outputs should have\. Default is 1\. \fIutxos\fR specifies the utxos to be used to fund the channel, as an array of "txid:vout"\. + +\fIpush_msat\fR is the amount of millisatoshis to push to the channel peer at +open\. Note that this is a gift to the peer -- these satoshis are +added to the initial balance of the peer at channel start and are largely +unrecoverable once pushed\. + .SH RETURN VALUE On success, the \fItx\fR and \fItxid\fR of the transaction is returned, as well diff --git a/doc/lightning-fundchannel.7.md b/doc/lightning-fundchannel.7.md index cf921eb32..8b87ca674 100644 --- a/doc/lightning-fundchannel.7.md +++ b/doc/lightning-fundchannel.7.md @@ -5,7 +5,7 @@ SYNOPSIS -------- **fundchannel** *id* *amount* \[*feerate* *announce*\] \[*minconf*\] -\[*utxos*\] +\[*utxos*\] \[*push_msat*\] DESCRIPTION ----------- @@ -49,6 +49,11 @@ outputs should have. Default is 1. *utxos* specifies the utxos to be used to fund the channel, as an array of "txid:vout". +*push_msat* is the amount of millisatoshis to push to the channel peer at +open. Note that this is a gift to the peer -- these satoshis are +added to the initial balance of the peer at channel start and are largely +unrecoverable once pushed. + RETURN VALUE ------------ diff --git a/doc/lightning-fundchannel_start.7 b/doc/lightning-fundchannel_start.7 index ab870d10c..365ef24d5 100644 --- a/doc/lightning-fundchannel_start.7 +++ b/doc/lightning-fundchannel_start.7 @@ -3,7 +3,7 @@ lightning-fundchannel_start - Command for initiating channel establishment for a lightning channel .SH SYNOPSIS -\fBfundchannel_start\fR \fIid\fR \fIamount\fR [\fIfeerate\fR \fIannounce\fR \fIclose_to\fR] +\fBfundchannel_start\fR \fIid\fR \fIamount\fR [\fIfeerate\fR \fIannounce\fR \fIclose_to\fR \fIpush_msat\fR] .SH DESCRIPTION @@ -31,6 +31,12 @@ on close\. Only valid if both peers have negotiated \fBoption_upfront_shutdown_s Returns \fBclose_to\fR set to closing script iff is negotiated\. +\fIpush_msat\fR is the amount of millisatoshis to push to the channel peer at +open\. Note that this is a gift to the peer -- these satoshis are +added to the initial balance of the peer at channel start and are largely +unrecoverable once pushed\. + + Note that the funding transaction MUST NOT be broadcast until after channel establishment has been successfully completed by running \fBfundchannel_complete\fR, as the commitment transactions for this channel diff --git a/doc/lightning-fundchannel_start.7.md b/doc/lightning-fundchannel_start.7.md index 3c7b52a83..b0f8b1790 100644 --- a/doc/lightning-fundchannel_start.7.md +++ b/doc/lightning-fundchannel_start.7.md @@ -4,7 +4,7 @@ lightning-fundchannel\_start -- Command for initiating channel establishment for SYNOPSIS -------- -**fundchannel\_start** *id* *amount* \[*feerate* *announce* *close_to*\] +**fundchannel\_start** *id* *amount* \[*feerate* *announce* *close_to* *push_msat*\] DESCRIPTION ----------- @@ -27,6 +27,11 @@ commitment transactions: see **fundchannel**. on close. Only valid if both peers have negotiated `option_upfront_shutdown_script`. Returns `close_to` set to closing script iff is negotiated. +*push_msat* is the amount of millisatoshis to push to the channel peer at +open. Note that this is a gift to the peer -- these satoshis are +added to the initial balance of the peer at channel start and are largely +unrecoverable once pushed. + Note that the funding transaction MUST NOT be broadcast until after channel establishment has been successfully completed by running `fundchannel_complete`, as the commitment transactions for this channel diff --git a/lightningd/opening_control.c b/lightningd/opening_control.c index 21a33de06..fed0ded1e 100644 --- a/lightningd/opening_control.c +++ b/lightningd/opening_control.c @@ -1105,6 +1105,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, u8 *msg = NULL; struct amount_sat *amount; + struct amount_msat *push_msat; fc->cmd = cmd; fc->cancels = tal_arr(fc, struct command *, 0); @@ -1119,6 +1120,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, p_opt("feerate", param_feerate, &feerate_per_kw), p_opt_def("announce", param_bool, &announce_channel, true), p_opt("close_to", param_bitcoin_address, &fc->our_upfront_shutdown_script), + p_opt("push_msat", param_msat, &push_msat), NULL)) return command_param_failed(); } else { @@ -1132,6 +1134,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, p_opt("satoshi", param_sat, &satoshi), p_opt("feerate", param_feerate, &feerate_per_kw), p_opt_def("announce", param_bool, &announce_channel, true), + p_opt("push_msat", param_msat, &push_msat), NULL)) return command_param_failed(); @@ -1153,6 +1156,13 @@ static struct command_result *json_fund_channel_start(struct command *cmd, type_to_string(tmpctx, struct amount_sat, &chainparams->max_funding)); + if (push_msat && amount_msat_greater_sat(*push_msat, *amount)) + return command_fail(cmd, FUND_CANNOT_AFFORD, + "Requested to push_msat of %s is greater than " + "available funding amount %s", + type_to_string(tmpctx, struct amount_msat, push_msat), + type_to_string(tmpctx, struct amount_sat, amount)); + fc->funding = *amount; if (!feerate_per_kw) { feerate_per_kw = tal(cmd, u32); @@ -1192,8 +1202,7 @@ static struct command_result *json_fund_channel_start(struct command *cmd, return command_fail(cmd, LIGHTNINGD, "Already funding channel"); } - /* FIXME: Support push_msat? */ - fc->push = AMOUNT_MSAT(0); + fc->push = push_msat ? *push_msat : AMOUNT_MSAT(0); fc->channel_flags = OUR_CHANNEL_FLAGS; if (!*announce_channel) { fc->channel_flags &= ~CHANNEL_FLAGS_ANNOUNCE_CHANNEL; diff --git a/plugins/fundchannel.c b/plugins/fundchannel.c index 539b59ead..ea59e9033 100644 --- a/plugins/fundchannel.c +++ b/plugins/fundchannel.c @@ -22,6 +22,7 @@ struct funding_req { const char *funding_str; const char *utxo_str; bool funding_all; + struct amount_msat *push_msat; bool *announce_channel; u32 *minconf; @@ -322,6 +323,9 @@ static struct command_result *fundchannel_start(struct command *cmd, json_out_addstr(ret, "feerate", fr->feerate_str); if (fr->announce_channel) json_out_addbool(ret, "announce", *fr->announce_channel); + if (fr->push_msat) + json_out_addstr(ret, "push_msat", + type_to_string(tmpctx, struct amount_msat, fr->push_msat)); json_out_end(ret, '}'); json_out_finished(ret); @@ -450,6 +454,7 @@ static struct command_result *json_fundchannel(struct command *cmd, p_opt_def("announce", param_bool, &fr->announce_channel, true), p_opt_def("minconf", param_number, &fr->minconf, 1), p_opt("utxos", param_string, &fr->utxo_str), + p_opt("push_msat", param_msat, &fr->push_msat), NULL)) return command_param_failed(); } else { @@ -462,6 +467,7 @@ static struct command_result *json_fundchannel(struct command *cmd, p_opt_def("announce", param_bool, &fr->announce_channel, true), p_opt_def("minconf", param_number, &fr->minconf, 1), p_opt("utxos", param_string, &fr->utxo_str), + p_opt("push_msat", param_msat, &fr->push_msat), NULL)) return command_param_failed(); diff --git a/tests/test_connection.py b/tests/test_connection.py index d1ac78595..7316e1298 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -911,6 +911,35 @@ def test_funding_toolarge(node_factory, bitcoind): l1.rpc.fundchannel(l2.info['id'], amount) +def test_funding_push(node_factory, bitcoind): + """ Try to push peer some sats """ + l1 = node_factory.get_node() + l2 = node_factory.get_node() + + l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + + # Send funds. + amount = 2**24 + push_sat = 20000 + bitcoind.rpc.sendtoaddress(l1.rpc.newaddr()['bech32'], amount / 10**8 + 0.01) + bitcoind.generate_block(1) + + # Wait for it to arrive. + wait_for(lambda: len(l1.rpc.listfunds()['outputs']) > 0) + + # Fail to open (try to push too much) + with pytest.raises(RpcError, match=r'Requested to push_msat of 20000000msat is greater than available funding amount 10000sat'): + l1.rpc.fundchannel(l2.info['id'], 10000, push_msat=push_sat * 1000) + + # This should work. + amount = amount - 1 + l1.rpc.fundchannel(l2.info['id'], amount, push_msat=push_sat * 1000) + bitcoind.generate_block(1) + sync_blockheight(bitcoind, [l1]) + funds = only_one(l1.rpc.listfunds()['channels']) + assert funds['channel_sat'] + push_sat == funds['channel_total_sat'] + + def test_funding_by_utxos(node_factory, bitcoind): """Fund a channel with specific utxos""" l1, l2, l3 = node_factory.line_graph(3, fundchannel=False)