diff --git a/lightningd/Makefile b/lightningd/Makefile index 279303765..ef331c3fc 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -143,7 +143,7 @@ check-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 -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 diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 70aa09d2a..24f5ab614 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,8 @@ #include #include #include +#include +#include #include #include #include @@ -382,6 +385,7 @@ void add_peer(struct lightningd *ld, u64 unique_id, = peer->num_revocations_received = 0; peer->next_htlc_id = 0; shachain_init(&peer->their_shachain); + peer->closing_sig_sent = peer->closing_sig_received = NULL; 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; } -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; @@ -1058,9 +1062,197 @@ static int peer_got_bad_message(struct peer *peer, const u8 *msg) 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) { struct crypto_state cs; + u8 *initmsg, *local_scriptpubkey; + u64 minfee, maxfee, startfee; /* We expect 2 fds. */ if (!fds) @@ -1083,9 +1275,63 @@ static int peer_start_closing(struct peer *peer, const u8 *msg, const int *fds) return -1; } - /* FIXME: Start closingd. */ - peer->owner = NULL; + peer->owner = new_subd(peer->ld, peer->ld, + "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); + + 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; } @@ -1125,7 +1371,7 @@ static int channel_msg(struct subd *sd, const u8 *msg, const int *fds) /* This is a permanent error. */ 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. */ case WIRE_CHANNEL_INIT: diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 8175e73aa..3251796b7 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -89,6 +89,10 @@ struct peer { /* Our key for shutdown (-1 if not chosen yet) */ 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. */ bool last_was_revoke; struct changed_htlc *last_sent_commit; diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 012290841..51018da3a 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -323,6 +323,11 @@ class LightningDTests(BaseLightningDTests): l1.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): l1,l2 = self.connect()