diff --git a/closingd/closingd.c b/closingd/closingd.c index 9e76842aa..80bb3a053 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -32,6 +32,20 @@ #define REQ_FD STDIN_FILENO #define HSM_FD 6 +static void notify(enum log_level level, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + wire_sync_write(REQ_FD, + take(towire_closingd_notification(NULL, + level, + tal_vfmt(tmpctx, fmt, + ap)))); + + va_end(ap); +} + static struct bitcoin_tx *close_tx(const tal_t *ctx, const struct chainparams *chainparams, struct per_peer_state *pps, @@ -192,6 +206,10 @@ static void send_offer(struct per_peer_state *pps, close_tlvs->fee_range = cast_const(struct tlv_closing_signed_tlvs_fee_range *, tlv_fees); + notify(LOG_INFORM, "Sending closing fee offer %s, with range %s-%s", + type_to_string(tmpctx, struct amount_sat, &fee_to_offer), + type_to_string(tmpctx, struct amount_sat, &tlv_fees->min_fee_satoshis), + type_to_string(tmpctx, struct amount_sat, &tlv_fees->max_fee_satoshis)); } else close_tlvs = NULL; @@ -345,10 +363,23 @@ receive_offer(struct per_peer_state *pps, type_to_string(tmpctx, struct amount_sat, &received_fee)); if (tlv_fees) { - if (close_tlvs) + if (close_tlvs) { *tlv_fees = tal_steal(tlv_fees, close_tlvs->fee_range); - else + } else { *tlv_fees = NULL; + } + } + + if (close_tlvs && close_tlvs->fee_range) { + notify(LOG_INFORM, "Received closing fee offer %s, with range %s-%s", + type_to_string(tmpctx, struct amount_sat, &received_fee), + type_to_string(tmpctx, struct amount_sat, + &close_tlvs->fee_range->min_fee_satoshis), + type_to_string(tmpctx, struct amount_sat, + &close_tlvs->fee_range->max_fee_satoshis)); + } else { + notify(LOG_INFORM, "Received closing fee offer %s, without range", + type_to_string(tmpctx, struct amount_sat, &received_fee)); } /* Master sorts out what is best offer, we just tell it any above min */ @@ -1080,4 +1111,5 @@ exit_thru_the_giftshop: daemon_shutdown(); return 0; + } diff --git a/closingd/closingd_wire.csv b/closingd/closingd_wire.csv index b1e5ea8d4..b6555a056 100644 --- a/closingd/closingd_wire.csv +++ b/closingd/closingd_wire.csv @@ -3,6 +3,7 @@ #include #include #include +#include # Begin! (passes peer fd, gossipd-client fd) msgtype,closingd_init,2001 msgdata,closingd_init,chainparams,chainparams, @@ -31,6 +32,11 @@ msgdata,closingd_init,use_quickclose,bool, msgdata,closingd_init,dev_fast_gossip,bool, msgdata,closingd_init,shutdown_wrong_funding,?bitcoin_outpoint, +# Message for any commands waiting. +msgtype,closingd_notification,2003 +msgdata,closingd_notification,level,enum log_level, +msgdata,closingd_notification,message,wirestring, + # We received an offer, save signature. msgtype,closingd_received_signature,2002 msgdata,closingd_received_signature,signature,bitcoin_signature, diff --git a/closingd/closingd_wiregen.c b/closingd/closingd_wiregen.c index 9412bba5f..1a4da8c6d 100644 --- a/closingd/closingd_wiregen.c +++ b/closingd/closingd_wiregen.c @@ -21,6 +21,7 @@ const char *closingd_wire_name(int e) switch ((enum closingd_wire)e) { case WIRE_CLOSINGD_INIT: return "WIRE_CLOSINGD_INIT"; + case WIRE_CLOSINGD_NOTIFICATION: return "WIRE_CLOSINGD_NOTIFICATION"; case WIRE_CLOSINGD_RECEIVED_SIGNATURE: return "WIRE_CLOSINGD_RECEIVED_SIGNATURE"; case WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY: return "WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY"; case WIRE_CLOSINGD_COMPLETE: return "WIRE_CLOSINGD_COMPLETE"; @@ -34,6 +35,7 @@ bool closingd_wire_is_defined(u16 type) { switch ((enum closingd_wire)type) { case WIRE_CLOSINGD_INIT:; + case WIRE_CLOSINGD_NOTIFICATION:; case WIRE_CLOSINGD_RECEIVED_SIGNATURE:; case WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY:; case WIRE_CLOSINGD_COMPLETE:; @@ -145,6 +147,30 @@ bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainp return cursor != NULL; } +/* WIRE: CLOSINGD_NOTIFICATION */ +/* Message for any commands waiting. */ +u8 *towire_closingd_notification(const tal_t *ctx, enum log_level level, const wirestring *message) +{ + u8 *p = tal_arr(ctx, u8, 0); + + towire_u16(&p, WIRE_CLOSINGD_NOTIFICATION); + towire_log_level(&p, level); + towire_wirestring(&p, message); + + return memcheck(p, tal_count(p)); +} +bool fromwire_closingd_notification(const tal_t *ctx, const void *p, enum log_level *level, wirestring **message) +{ + const u8 *cursor = p; + size_t plen = tal_count(p); + + if (fromwire_u16(&cursor, &plen) != WIRE_CLOSINGD_NOTIFICATION) + return false; + *level = fromwire_log_level(&cursor, &plen); + *message = fromwire_wirestring(ctx, &cursor, &plen); + return cursor != NULL; +} + /* WIRE: CLOSINGD_RECEIVED_SIGNATURE */ /* We received an offer */ u8 *towire_closingd_received_signature(const tal_t *ctx, const struct bitcoin_signature *signature, const struct bitcoin_tx *tx) @@ -209,4 +235,4 @@ bool fromwire_closingd_complete(const void *p) return false; return cursor != NULL; } -// SHA256STAMP:0d0d56c4ec5230461ead5cfac728e57e75db7bff1b53b1b0aaef20b82ce76362 +// SHA256STAMP:0602a002b81e43b45a8c40a15cb4af6c5e7ea66d6f95b7ba89f386b2fe73bd0e diff --git a/closingd/closingd_wiregen.h b/closingd/closingd_wiregen.h index e4162fa3f..b950ed68b 100644 --- a/closingd/closingd_wiregen.h +++ b/closingd/closingd_wiregen.h @@ -12,10 +12,13 @@ #include #include #include +#include enum closingd_wire { /* Begin! (passes peer fd */ WIRE_CLOSINGD_INIT = 2001, + /* Message for any commands waiting. */ + WIRE_CLOSINGD_NOTIFICATION = 2003, /* We received an offer */ WIRE_CLOSINGD_RECEIVED_SIGNATURE = 2002, WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY = 2102, @@ -40,6 +43,11 @@ bool closingd_wire_is_defined(u16 type); u8 *towire_closingd_init(const tal_t *ctx, const struct chainparams *chainparams, const struct per_peer_state *pps, const struct channel_id *channel_id, const struct bitcoin_txid *funding_txid, u16 funding_txout, struct amount_sat funding_satoshi, const struct pubkey *local_fundingkey, const struct pubkey *remote_fundingkey, enum side opener, struct amount_sat local_sat, struct amount_sat remote_sat, struct amount_sat our_dust_limit, u32 min_feerate_perksipa, u32 preferred_feerate_perksipa, u32 *max_feerate_perksipa, struct amount_sat fee_limit_satoshi, const u8 *local_scriptpubkey, const u8 *remote_scriptpubkey, u64 fee_negotiation_step, u8 fee_negotiation_step_unit, bool use_quickclose, bool dev_fast_gossip, const struct bitcoin_outpoint *shutdown_wrong_funding); bool fromwire_closingd_init(const tal_t *ctx, const void *p, const struct chainparams **chainparams, struct per_peer_state **pps, struct channel_id *channel_id, struct bitcoin_txid *funding_txid, u16 *funding_txout, struct amount_sat *funding_satoshi, struct pubkey *local_fundingkey, struct pubkey *remote_fundingkey, enum side *opener, struct amount_sat *local_sat, struct amount_sat *remote_sat, struct amount_sat *our_dust_limit, u32 *min_feerate_perksipa, u32 *preferred_feerate_perksipa, u32 **max_feerate_perksipa, struct amount_sat *fee_limit_satoshi, u8 **local_scriptpubkey, u8 **remote_scriptpubkey, u64 *fee_negotiation_step, u8 *fee_negotiation_step_unit, bool *use_quickclose, bool *dev_fast_gossip, struct bitcoin_outpoint **shutdown_wrong_funding); +/* WIRE: CLOSINGD_NOTIFICATION */ +/* Message for any commands waiting. */ +u8 *towire_closingd_notification(const tal_t *ctx, enum log_level level, const wirestring *message); +bool fromwire_closingd_notification(const tal_t *ctx, const void *p, enum log_level *level, wirestring **message); + /* WIRE: CLOSINGD_RECEIVED_SIGNATURE */ /* We received an offer */ u8 *towire_closingd_received_signature(const tal_t *ctx, const struct bitcoin_signature *signature, const struct bitcoin_tx *tx); @@ -56,4 +64,4 @@ bool fromwire_closingd_complete(const void *p); #endif /* LIGHTNING_CLOSINGD_CLOSINGD_WIREGEN_H */ -// SHA256STAMP:0d0d56c4ec5230461ead5cfac728e57e75db7bff1b53b1b0aaef20b82ce76362 +// SHA256STAMP:0602a002b81e43b45a8c40a15cb4af6c5e7ea66d6f95b7ba89f386b2fe73bd0e diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index f36f9c0ef..26f09a856 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -283,6 +283,25 @@ static void peer_closing_complete(struct channel *channel, const u8 *msg) "Closing complete"); } +static void peer_closing_notify(struct channel *channel, const u8 *msg) +{ + char *message; + struct close_command *i; + enum log_level level; + + if (!fromwire_closingd_notification(msg, msg, &level, &message)) { + channel_internal_error(channel, "Bad closing_notify %s", + tal_hex(msg, msg)); + return; + } + + list_for_each(&channel->peer->ld->close_commands, i, list) { + if (i->channel != channel) + continue; + json_notify_fmt(i->cmd, level, "%s", message); + } +} + static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSED) { enum closingd_wire t = fromwire_peektype(msg); @@ -296,6 +315,10 @@ static unsigned closing_msg(struct subd *sd, const u8 *msg, const int *fds UNUSE peer_closing_complete(sd->channel, msg); break; + case WIRE_CLOSINGD_NOTIFICATION: + peer_closing_notify(sd->channel, msg); + break; + /* We send these, not receive them */ case WIRE_CLOSINGD_INIT: case WIRE_CLOSINGD_RECEIVED_SIGNATURE_REPLY: diff --git a/tests/test_closing.py b/tests/test_closing.py index cc1ce6be8..35ae4690d 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -3318,8 +3318,14 @@ def test_close_feerate_range(node_factory, bitcoind, chainparams): """Test the quick-close fee range negotiation""" l1, l2 = node_factory.line_graph(2) + notifications = [] + + def save_notifications(message, progress, request, **kwargs): + notifications.append(message) + # Lowball the range here. - l1.rpc.close(l2.info['id'], feerange=['253perkw', 'normal']) + with l1.rpc.notify(save_notifications): + l1.rpc.close(l2.info['id'], feerange=['253perkw', 'normal']) if not chainparams['elements']: l1_range = [138, 4110] @@ -3335,6 +3341,16 @@ def test_close_feerate_range(node_factory, bitcoind, chainparams): overlap = [max(l1_range[0], l2_range[0]), min(l1_range[1], l2_range[1])] l1.daemon.wait_for_log('performing quickclose in range {}sat-{}sat'.format(overlap[0], overlap[1])) + log = l1.daemon.is_in_log('Their actual closing tx fee is .*sat') + rate = re.match('.*Their actual closing tx fee is ([0-9]*sat).*', log).group(1) + + assert notifications == ['Sending closing fee offer {}, with range {}sat-{}sat'.format(rate, + l1_range[0], + l1_range[1]), + 'Received closing fee offer {}, with range {}sat-{}sat'.format(rate, + l2_range[0], + l2_range[1])] + def test_close_twice(node_factory, executor): # First feerate is too low, second fixes it.