mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
lightningd: add in support for closingd.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -143,7 +143,7 @@ check-makefile: check-lightningd-makefile
|
|||||||
check-lightningd-makefile:
|
check-lightningd-makefile:
|
||||||
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
|
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
|
||||||
|
|
||||||
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(WALLET_LIB_OBJS) libsecp256k1.a libsodium.a libwallycore.a
|
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(LIGHTNINGD_CLOSING_CONTROL_OBJS) $(WALLET_LIB_OBJS) libsecp256k1.a libsodium.a libwallycore.a
|
||||||
|
|
||||||
clean: lightningd-clean
|
clean: lightningd-clean
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <ccan/noerr/noerr.h>
|
#include <ccan/noerr/noerr.h>
|
||||||
#include <ccan/take/take.h>
|
#include <ccan/take/take.h>
|
||||||
#include <ccan/tal/str/str.h>
|
#include <ccan/tal/str/str.h>
|
||||||
|
#include <close_tx.h>
|
||||||
#include <daemon/chaintopology.h>
|
#include <daemon/chaintopology.h>
|
||||||
#include <daemon/dns.h>
|
#include <daemon/dns.h>
|
||||||
#include <daemon/jsonrpc.h>
|
#include <daemon/jsonrpc.h>
|
||||||
@@ -20,6 +21,8 @@
|
|||||||
#include <lightningd/build_utxos.h>
|
#include <lightningd/build_utxos.h>
|
||||||
#include <lightningd/channel.h>
|
#include <lightningd/channel.h>
|
||||||
#include <lightningd/channel/gen_channel_wire.h>
|
#include <lightningd/channel/gen_channel_wire.h>
|
||||||
|
#include <lightningd/closing/gen_closing_wire.h>
|
||||||
|
#include <lightningd/commit_tx.h>
|
||||||
#include <lightningd/funding_tx.h>
|
#include <lightningd/funding_tx.h>
|
||||||
#include <lightningd/gen_peer_state_names.h>
|
#include <lightningd/gen_peer_state_names.h>
|
||||||
#include <lightningd/gossip/gen_gossip_wire.h>
|
#include <lightningd/gossip/gen_gossip_wire.h>
|
||||||
@@ -382,6 +385,7 @@ void add_peer(struct lightningd *ld, u64 unique_id,
|
|||||||
= peer->num_revocations_received = 0;
|
= peer->num_revocations_received = 0;
|
||||||
peer->next_htlc_id = 0;
|
peer->next_htlc_id = 0;
|
||||||
shachain_init(&peer->their_shachain);
|
shachain_init(&peer->their_shachain);
|
||||||
|
peer->closing_sig_sent = peer->closing_sig_received = NULL;
|
||||||
|
|
||||||
idname = type_to_string(peer, struct pubkey, id);
|
idname = type_to_string(peer, struct pubkey, id);
|
||||||
|
|
||||||
@@ -1044,7 +1048,7 @@ static int peer_got_shutdown(struct peer *peer, const u8 *msg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int peer_got_bad_message(struct peer *peer, const u8 *msg)
|
static int channeld_got_bad_message(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
u8 *err;
|
u8 *err;
|
||||||
|
|
||||||
@@ -1058,9 +1062,197 @@ static int peer_got_bad_message(struct peer *peer, const u8 *msg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int closingd_got_bad_message(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *err;
|
||||||
|
|
||||||
|
/* Don't try to fail this (again!) when owner dies. */
|
||||||
|
peer->owner = NULL;
|
||||||
|
if (!fromwire_closing_peer_bad_message(peer, NULL, NULL, &err))
|
||||||
|
err = (u8 *)tal_strdup(peer, "Internal error after bad message");
|
||||||
|
peer_fail_permanent(peer, take(err));
|
||||||
|
|
||||||
|
/* Kill daemon (though it's dying anyway) */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int closingd_got_negotiation_error(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u8 *err;
|
||||||
|
|
||||||
|
if (!fromwire_closing_negotiation_error(peer, NULL, NULL, &err))
|
||||||
|
peer_internal_error(peer, "Bad closing_negotiation %s",
|
||||||
|
tal_hex(peer, msg));
|
||||||
|
else
|
||||||
|
peer_internal_error(peer, "%s", err);
|
||||||
|
|
||||||
|
/* Kill daemon (though it's dying anyway) */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peer_received_closing_signature(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u64 fee_satoshi;
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
|
||||||
|
if (!fromwire_closing_received_signature(msg, NULL,
|
||||||
|
&fee_satoshi, &sig)) {
|
||||||
|
peer_internal_error(peer, "Bad closing_received_signature %s",
|
||||||
|
tal_hex(peer, msg));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Make sure offer is in useful range! */
|
||||||
|
/* FIXME: Make sure signature is correct! */
|
||||||
|
/* FIXME: save to db. */
|
||||||
|
|
||||||
|
peer->closing_fee_received = fee_satoshi;
|
||||||
|
tal_free(peer->closing_sig_received);
|
||||||
|
peer->closing_sig_received
|
||||||
|
= tal_dup(peer, secp256k1_ecdsa_signature, &sig);
|
||||||
|
|
||||||
|
/* OK, you can continue now. */
|
||||||
|
subd_send_msg(peer->owner,
|
||||||
|
take(towire_closing_received_signature_reply(peer)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peer_offered_closing_signature(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
u64 fee_satoshi;
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
|
||||||
|
if (!fromwire_closing_offered_signature(msg, NULL, &fee_satoshi, &sig)) {
|
||||||
|
peer_internal_error(peer, "Bad closing_offered_signature %s",
|
||||||
|
tal_hex(peer, msg));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Make sure offer is in useful range! */
|
||||||
|
/* FIXME: Make sure signature is correct! */
|
||||||
|
/* FIXME: save to db. */
|
||||||
|
|
||||||
|
peer->closing_fee_sent = fee_satoshi;
|
||||||
|
tal_free(peer->closing_sig_sent);
|
||||||
|
peer->closing_sig_sent
|
||||||
|
= tal_dup(peer, secp256k1_ecdsa_signature, &sig);
|
||||||
|
|
||||||
|
/* OK, you can continue now. */
|
||||||
|
subd_send_msg(peer->owner,
|
||||||
|
take(towire_closing_offered_signature_reply(peer)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int peer_closing_complete(struct peer *peer, const u8 *msg)
|
||||||
|
{
|
||||||
|
struct bitcoin_tx *tx;
|
||||||
|
u8 *local_scriptpubkey;
|
||||||
|
u64 out_amounts[NUM_SIDES];
|
||||||
|
struct pubkey local_funding_pubkey;
|
||||||
|
|
||||||
|
if (!fromwire_closing_complete(msg, NULL)) {
|
||||||
|
peer_internal_error(peer, "Bad closing_complete %s",
|
||||||
|
tal_hex(peer, msg));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!peer->closing_sig_sent) {
|
||||||
|
peer_internal_error(peer,
|
||||||
|
"closing_complete without receiving sig!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!peer->closing_sig_received) {
|
||||||
|
peer_internal_error(peer,
|
||||||
|
"closing_complete without sending sig!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_scriptpubkey = p2wpkh_for_keyidx(msg, peer->ld,
|
||||||
|
peer->local_shutdown_idx);
|
||||||
|
if (!local_scriptpubkey) {
|
||||||
|
peer_internal_error(peer,
|
||||||
|
"Can't generate local shutdown scriptpubkey");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BOLT #3:
|
||||||
|
*
|
||||||
|
* The amounts for each output MUST BE rounded down to whole satoshis.
|
||||||
|
*/
|
||||||
|
out_amounts[LOCAL] = *peer->balance / 1000;
|
||||||
|
out_amounts[REMOTE] = peer->funding_satoshi - *peer->balance / 1000;
|
||||||
|
out_amounts[peer->funder] -= peer->closing_fee_received;
|
||||||
|
|
||||||
|
derive_basepoints(peer->seed, &local_funding_pubkey, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
tx = create_close_tx(msg, local_scriptpubkey,
|
||||||
|
peer->remote_shutdown_scriptpubkey,
|
||||||
|
peer->funding_txid,
|
||||||
|
peer->funding_outnum,
|
||||||
|
peer->funding_satoshi,
|
||||||
|
out_amounts[LOCAL],
|
||||||
|
out_amounts[REMOTE],
|
||||||
|
peer->our_config.dust_limit_satoshis);
|
||||||
|
|
||||||
|
tx->input[0].witness
|
||||||
|
= bitcoin_witness_2of2(tx->input,
|
||||||
|
peer->closing_sig_received,
|
||||||
|
peer->closing_sig_sent,
|
||||||
|
&peer->channel_info->remote_fundingkey,
|
||||||
|
&local_funding_pubkey);
|
||||||
|
|
||||||
|
/* Keep broadcasting until we say stop (can fail due to dup,
|
||||||
|
* if they beat us to the broadcast). */
|
||||||
|
broadcast_tx(peer->ld->topology, peer, tx, NULL);
|
||||||
|
|
||||||
|
/* FIXME: Set state. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int closing_msg(struct subd *sd, const u8 *msg, const int *fds)
|
||||||
|
{
|
||||||
|
enum closing_wire_type t = fromwire_peektype(msg);
|
||||||
|
|
||||||
|
switch (t) {
|
||||||
|
/* We let peer_owner_finished handle these as transient errors. */
|
||||||
|
case WIRE_CLOSING_BAD_COMMAND:
|
||||||
|
case WIRE_CLOSING_GOSSIP_FAILED:
|
||||||
|
case WIRE_CLOSING_INTERNAL_ERROR:
|
||||||
|
case WIRE_CLOSING_PEER_READ_FAILED:
|
||||||
|
case WIRE_CLOSING_PEER_WRITE_FAILED:
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* These are permanent errors. */
|
||||||
|
case WIRE_CLOSING_PEER_BAD_MESSAGE:
|
||||||
|
return closingd_got_bad_message(sd->peer, msg);
|
||||||
|
case WIRE_CLOSING_NEGOTIATION_ERROR:
|
||||||
|
return closingd_got_negotiation_error(sd->peer, msg);
|
||||||
|
|
||||||
|
case WIRE_CLOSING_RECEIVED_SIGNATURE:
|
||||||
|
return peer_received_closing_signature(sd->peer, msg);
|
||||||
|
|
||||||
|
case WIRE_CLOSING_OFFERED_SIGNATURE:
|
||||||
|
return peer_offered_closing_signature(sd->peer, msg);
|
||||||
|
|
||||||
|
case WIRE_CLOSING_COMPLETE:
|
||||||
|
return peer_closing_complete(sd->peer, msg);
|
||||||
|
|
||||||
|
/* We send these, not receive them */
|
||||||
|
case WIRE_CLOSING_INIT:
|
||||||
|
case WIRE_CLOSING_RECEIVED_SIGNATURE_REPLY:
|
||||||
|
case WIRE_CLOSING_OFFERED_SIGNATURE_REPLY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int peer_start_closing(struct peer *peer, const u8 *msg, const int *fds)
|
static int peer_start_closing(struct peer *peer, const u8 *msg, const int *fds)
|
||||||
{
|
{
|
||||||
struct crypto_state cs;
|
struct crypto_state cs;
|
||||||
|
u8 *initmsg, *local_scriptpubkey;
|
||||||
|
u64 minfee, maxfee, startfee;
|
||||||
|
|
||||||
/* We expect 2 fds. */
|
/* We expect 2 fds. */
|
||||||
if (!fds)
|
if (!fds)
|
||||||
@@ -1083,9 +1275,63 @@ static int peer_start_closing(struct peer *peer, const u8 *msg, const int *fds)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Start closingd. */
|
peer->owner = new_subd(peer->ld, peer->ld,
|
||||||
peer->owner = NULL;
|
"lightningd_closing", peer,
|
||||||
|
closing_wire_type_name,
|
||||||
|
closing_msg,
|
||||||
|
peer_owner_finished,
|
||||||
|
take(&fds[0]),
|
||||||
|
take(&fds[1]), NULL);
|
||||||
|
if (!peer->owner) {
|
||||||
|
log_unusual(peer->log, "Could not subdaemon closing: %s",
|
||||||
|
strerror(errno));
|
||||||
|
peer_fail_transient(peer, "Failed to subdaemon closing");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
peer_set_condition(peer, CHANNELD_SHUTTING_DOWN, CLOSINGD_SIGEXCHANGE);
|
peer_set_condition(peer, CHANNELD_SHUTTING_DOWN, CLOSINGD_SIGEXCHANGE);
|
||||||
|
|
||||||
|
local_scriptpubkey = p2wpkh_for_keyidx(msg, peer->ld,
|
||||||
|
peer->local_shutdown_idx);
|
||||||
|
if (!local_scriptpubkey) {
|
||||||
|
peer_internal_error(peer,
|
||||||
|
"Can't generate local shutdown scriptpubkey");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Real fees! */
|
||||||
|
maxfee = commit_tx_base_fee(get_feerate(peer->ld->topology), 0);
|
||||||
|
minfee = maxfee / 2;
|
||||||
|
if (peer->closing_sig_sent)
|
||||||
|
startfee = peer->closing_fee_sent;
|
||||||
|
else
|
||||||
|
startfee = (maxfee + minfee)/2;
|
||||||
|
|
||||||
|
/* BOLT #3:
|
||||||
|
*
|
||||||
|
* The amounts for each output MUST BE rounded down to whole satoshis.
|
||||||
|
*/
|
||||||
|
initmsg = towire_closing_init(peer,
|
||||||
|
&cs,
|
||||||
|
peer->seed,
|
||||||
|
peer->funding_txid,
|
||||||
|
peer->funding_outnum,
|
||||||
|
peer->funding_satoshi,
|
||||||
|
&peer->channel_info->remote_fundingkey,
|
||||||
|
peer->funder,
|
||||||
|
*peer->balance / 1000,
|
||||||
|
peer->funding_satoshi
|
||||||
|
- *peer->balance / 1000,
|
||||||
|
peer->our_config.dust_limit_satoshis,
|
||||||
|
minfee, maxfee, startfee,
|
||||||
|
local_scriptpubkey,
|
||||||
|
peer->remote_shutdown_scriptpubkey);
|
||||||
|
|
||||||
|
/* We don't expect a response: it will give us feedback on
|
||||||
|
* signatures sent and received, then closing_complete. */
|
||||||
|
subd_send_msg(peer->owner, take(initmsg));
|
||||||
|
|
||||||
|
/* Close the channeld */
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1125,7 +1371,7 @@ static int channel_msg(struct subd *sd, const u8 *msg, const int *fds)
|
|||||||
|
|
||||||
/* This is a permanent error. */
|
/* This is a permanent error. */
|
||||||
case WIRE_CHANNEL_PEER_BAD_MESSAGE:
|
case WIRE_CHANNEL_PEER_BAD_MESSAGE:
|
||||||
return peer_got_bad_message(sd->peer, msg);
|
return channeld_got_bad_message(sd->peer, msg);
|
||||||
|
|
||||||
/* And we never get these from channeld. */
|
/* And we never get these from channeld. */
|
||||||
case WIRE_CHANNEL_INIT:
|
case WIRE_CHANNEL_INIT:
|
||||||
|
|||||||
@@ -89,6 +89,10 @@ struct peer {
|
|||||||
/* Our key for shutdown (-1 if not chosen yet) */
|
/* Our key for shutdown (-1 if not chosen yet) */
|
||||||
s64 local_shutdown_idx;
|
s64 local_shutdown_idx;
|
||||||
|
|
||||||
|
/* Closing stuff. */
|
||||||
|
u64 closing_fee_received, closing_fee_sent;
|
||||||
|
secp256k1_ecdsa_signature *closing_sig_sent, *closing_sig_received;
|
||||||
|
|
||||||
/* Reestablishment stuff: last sent commit and revocation details. */
|
/* Reestablishment stuff: last sent commit and revocation details. */
|
||||||
bool last_was_revoke;
|
bool last_was_revoke;
|
||||||
struct changed_htlc *last_sent_commit;
|
struct changed_htlc *last_sent_commit;
|
||||||
|
|||||||
@@ -323,6 +323,11 @@ class LightningDTests(BaseLightningDTests):
|
|||||||
l1.daemon.wait_for_log('-> CLOSINGD_SIGEXCHANGE')
|
l1.daemon.wait_for_log('-> CLOSINGD_SIGEXCHANGE')
|
||||||
l2.daemon.wait_for_log('-> CLOSINGD_SIGEXCHANGE')
|
l2.daemon.wait_for_log('-> CLOSINGD_SIGEXCHANGE')
|
||||||
|
|
||||||
|
# And should put closing into mempool.
|
||||||
|
l1.daemon.wait_for_log('sendrawtx exit 0')
|
||||||
|
l2.daemon.wait_for_log('sendrawtx exit 0')
|
||||||
|
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
|
||||||
|
|
||||||
def test_gossip_jsonrpc(self):
|
def test_gossip_jsonrpc(self):
|
||||||
l1,l2 = self.connect()
|
l1,l2 = self.connect()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user