channeld: keep local copy of latest channel_update for errors.

Now we don't ask gossipd, but lightningd keeps channeld up-to-date.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2022-01-25 06:32:52 +10:30
parent 5065bd6fc2
commit e8554c862a
10 changed files with 69 additions and 120 deletions

View File

@ -191,6 +191,9 @@ struct peer {
/* We allow a 'tx-sigs' message between reconnect + funding_locked */
bool tx_sigs_allowed;
/* Most recent channel_update message. */
u8 *channel_update;
};
static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer);
@ -414,28 +417,6 @@ static void send_channel_update(struct peer *peer, int disable_flag)
wire_sync_write(peer->pps->gossip_fd, take(msg));
}
/* Get the latest channel update for this channel from gossipd */
static const u8 *get_local_channel_update(const tal_t *ctx, struct peer *peer)
{
const u8 *msg;
msg = towire_gossipd_get_update(NULL, &peer->short_channel_ids[LOCAL]);
wire_sync_write(peer->pps->gossip_fd, take(msg));
/* Wait for reply to come back; handle other gossipd msgs meanwhile */
while ((msg = wire_sync_read(tmpctx, peer->pps->gossip_fd)) != NULL) {
u8 *update;
if (fromwire_gossipd_get_update_reply(ctx, msg, &update))
return update;
handle_gossip_msg(peer->pps, take(msg));
}
/* Gossipd hangs up on us to kill us when a new
* connection comes in. */
peer_failed_connection_lost();
}
/**
* Add a channel locally and send a channel update to the peer
*
@ -3312,6 +3293,15 @@ static void handle_funding_depth(struct peer *peer, const u8 *msg)
billboard_update(peer);
}
static const u8 *get_cupdate(const struct peer *peer)
{
/* Technically we only need to tell it the first time (unless it's
* changed). But it's not that common. */
wire_sync_write(MASTER_FD,
take(towire_channeld_used_channel_update(NULL)));
return peer->channel_update;
}
static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
{
u8 *msg;
@ -3373,7 +3363,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
peer->htlc_id++;
return;
case CHANNEL_ERR_INVALID_EXPIRY:
failwiremsg = towire_incorrect_cltv_expiry(inmsg, cltv_expiry, get_local_channel_update(tmpctx, peer));
failwiremsg = towire_incorrect_cltv_expiry(inmsg, cltv_expiry, get_cupdate(peer));
failstr = tal_fmt(inmsg, "Invalid cltv_expiry %u", cltv_expiry);
goto failed;
case CHANNEL_ERR_DUPLICATE:
@ -3387,18 +3377,18 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
goto failed;
/* FIXME: Fuzz the boundaries a bit to avoid probing? */
case CHANNEL_ERR_CHANNEL_CAPACITY_EXCEEDED:
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer));
failstr = tal_fmt(inmsg, "Capacity exceeded - HTLC fee: %s", fmt_amount_sat(inmsg, htlc_fee));
goto failed;
case CHANNEL_ERR_HTLC_BELOW_MINIMUM:
failwiremsg = towire_amount_below_minimum(inmsg, amount, get_local_channel_update(inmsg, peer));
failwiremsg = towire_amount_below_minimum(inmsg, amount, get_cupdate(peer));
failstr = tal_fmt(inmsg, "HTLC too small (%s minimum)",
type_to_string(tmpctx,
struct amount_msat,
&peer->channel->config[REMOTE].htlc_minimum));
goto failed;
case CHANNEL_ERR_TOO_MANY_HTLCS:
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer));
failstr = "Too many HTLCs";
goto failed;
case CHANNEL_ERR_DUST_FAILURE:
@ -3408,7 +3398,7 @@ static void handle_offer_htlc(struct peer *peer, const u8 *inmsg)
* - SHOULD NOT send this HTLC
* - SHOULD fail this HTLC if it's forwarded
*/
failwiremsg = towire_temporary_channel_failure(inmsg, get_local_channel_update(inmsg, peer));
failwiremsg = towire_temporary_channel_failure(inmsg, get_cupdate(peer));
failstr = "HTLC too dusty, allowed dust limit reached";
goto failed;
}
@ -3591,6 +3581,14 @@ static void handle_shutdown_cmd(struct peer *peer, const u8 *inmsg)
start_commit_timer(peer);
}
/* Lightningd tells us when channel_update has changed. */
static void handle_channel_update(struct peer *peer, const u8 *msg)
{
peer->channel_update = tal_free(peer->channel_update);
if (!fromwire_channeld_channel_update(peer, msg, &peer->channel_update))
master_badmsg(WIRE_CHANNELD_CHANNEL_UPDATE, msg);
}
static void handle_send_error(struct peer *peer, const u8 *msg)
{
char *reason;
@ -3757,6 +3755,9 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_PING:
handle_send_ping(peer, msg);
return;
case WIRE_CHANNELD_CHANNEL_UPDATE:
handle_channel_update(peer, msg);
return;
#if DEVELOPER
case WIRE_CHANNELD_DEV_REENABLE_COMMIT:
handle_dev_reenable_commit(peer);
@ -3793,6 +3794,7 @@ static void req_in(struct peer *peer, const u8 *msg)
case WIRE_CHANNELD_DEV_QUIESCE_REPLY:
case WIRE_CHANNELD_UPGRADED:
case WIRE_CHANNELD_PING_REPLY:
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
break;
}
@ -3898,7 +3900,8 @@ static void init_channel(struct peer *peer)
&dev_fail_process_onionpacket,
&dev_disable_commit,
&pbases,
&reestablish_only)) {
&reestablish_only,
&peer->channel_update)) {
master_badmsg(WIRE_CHANNELD_INIT, msg);
}

View File

@ -77,6 +77,8 @@ msgdata,channeld_init,num_penalty_bases,u32,
msgdata,channeld_init,pbases,penalty_base,num_penalty_bases
msgdata,channeld_init,reestablish_only_len,u16,
msgdata,channeld_init,reestablish_only,u8,reestablish_only_len
msgdata,channeld_init,channel_update_len,u16,
msgdata,channeld_init,channel_update,u8,channel_update_len
# master->channeld funding hit new depth(funding locked if >= lock depth)
msgtype,channeld_funding_depth,1002
@ -224,6 +226,14 @@ msgdata,channeld_send_error,reason,wirestring,
# Tell master channeld has sent the error message.
msgtype,channeld_send_error_reply,1108
# Tell channeld about the latest channel_update
msgtype,channeld_channel_update,1001
msgdata,channeld_channel_update,len,u16,
msgdata,channeld_channel_update,msg,u8,len
# Tell lightningd we used the latest channel_update for an error.
msgtype,channeld_used_channel_update,1102
# Ask channeld to quiesce.
msgtype,channeld_dev_quiesce,1009
msgtype,channeld_dev_quiesce_reply,1109

Can't render this file because it has a wrong number of fields in line 13.

View File

@ -598,7 +598,7 @@ static void defer_update(struct daemon *daemon,
}
/* If there is a pending update for this local channel, apply immediately. */
bool local_channel_update_latest(struct daemon *daemon, struct chan *chan)
static bool local_channel_update_latest(struct daemon *daemon, struct chan *chan)
{
struct deferred_update *du;

View File

@ -35,9 +35,6 @@ bool nannounce_different(struct gossip_store *gs,
/* Should we announce our own node? Called at strategic places. */
void maybe_send_own_node_announce(struct daemon *daemon, bool startup);
/* Flush any pending changes to this channel. */
bool local_channel_update_latest(struct daemon *daemon, struct chan *chan);
/* Disable this local channel (lazily) */
void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction);

View File

@ -277,65 +277,6 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg)
return NULL;
}
/*~ This is when channeld asks us for a channel_update for a local channel.
* It does that to fill in the error field when lightningd fails an HTLC and
* sets the UPDATE bit in the error type. lightningd is too important to
* fetch this itself, so channeld does it (channeld has to talk to us for
* other things anyway, so why not?). */
static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg)
{
struct short_channel_id scid;
struct chan *chan;
const u8 *update;
struct routing_state *rstate = peer->daemon->rstate;
int direction;
if (!fromwire_gossipd_get_update(msg, &scid)) {
status_broken("peer %s sent bad gossip_get_update %s",
type_to_string(tmpctx, struct node_id, &peer->id),
tal_hex(tmpctx, msg));
return false;
}
/* It's possible that the channel has just closed (though v. unlikely) */
chan = get_channel(rstate, &scid);
if (!chan) {
status_unusual("peer %s scid %s: unknown channel",
type_to_string(tmpctx, struct node_id, &peer->id),
type_to_string(tmpctx, struct short_channel_id,
&scid));
update = NULL;
goto out;
}
/* Since we're going to send it out, make sure it's up-to-date. */
local_channel_update_latest(peer->daemon, chan);
if (!local_direction(rstate, chan, &direction)) {
status_peer_broken(&peer->id, "Chan %s is not local?",
type_to_string(tmpctx, struct short_channel_id,
&scid));
update = NULL;
goto out;
}
/* It's possible this is zero, if we've never sent a channel_update
* for that channel. */
if (!is_halfchan_defined(&chan->half[direction]))
update = NULL;
else
update = gossip_store_get(tmpctx, rstate->gs,
chan->half[direction].bcast.index);
out:
status_peer_debug(&peer->id, "schanid %s: %s update",
type_to_string(tmpctx, struct short_channel_id, &scid),
update ? "got" : "no");
msg = towire_gossipd_get_update_reply(NULL, update);
daemon_conn_send(peer->dc, take(msg));
return true;
}
static u8 *handle_node_announce(struct peer *peer, const u8 *msg)
{
bool was_unknown = false;
@ -781,19 +722,12 @@ static struct io_plan *peer_msg_in(struct io_conn *conn,
/* Must be a gossipd_peerd_wire_type asking us to do something. */
switch ((enum gossipd_peerd_wire)fromwire_peektype(msg)) {
case WIRE_GOSSIPD_GET_UPDATE:
ok = handle_get_local_channel_update(peer, msg);
goto handled_cmd;
case WIRE_GOSSIPD_LOCAL_CHANNEL_UPDATE:
ok = handle_local_channel_update(peer->daemon, &peer->id, msg);
goto handled_cmd;
case WIRE_GOSSIPD_LOCAL_CHANNEL_ANNOUNCEMENT:
ok = handle_local_channel_announcement(peer->daemon, peer, msg);
goto handled_cmd;
/* These are the ones we send, not them */
case WIRE_GOSSIPD_GET_UPDATE_REPLY:
break;
}
if (fromwire_peektype(msg) == WIRE_GOSSIP_STORE_PRIVATE_CHANNEL) {

View File

@ -2,16 +2,6 @@
#include <bitcoin/short_channel_id.h>
#include <common/amount.h>
# Channel daemon can ask for updates for a specific channel, for sending
# errors.
msgtype,gossipd_get_update,3501
msgdata,gossipd_get_update,short_channel_id,short_channel_id,
# If channel isn't known, update will be empty.
msgtype,gossipd_get_update_reply,3601
msgdata,gossipd_get_update_reply,len,u16,
msgdata,gossipd_get_update_reply,update,u8,len
# Send this channel_update.
msgtype,gossipd_local_channel_update,3504
msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id,

1 # These must be distinct from WIRE_CHANNEL_ANNOUNCEMENT etc. gossip msgs!
2 #include <bitcoin/short_channel_id.h>
3 #include <common/amount.h>
4 # Channel daemon can ask for updates for a specific channel, for sending # Send this channel_update.
# errors.
msgtype,gossipd_get_update,3501
msgdata,gossipd_get_update,short_channel_id,short_channel_id,
# If channel isn't known, update will be empty.
msgtype,gossipd_get_update_reply,3601
msgdata,gossipd_get_update_reply,len,u16,
msgdata,gossipd_get_update_reply,update,u8,len
# Send this channel_update.
msgtype,gossipd_local_channel_update,3504
msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id,
5 msgdata,gossipd_local_channel_update,disable,bool, msgtype,gossipd_local_channel_update,3504
6 msgdata,gossipd_local_channel_update,cltv_expiry_delta,u16, msgdata,gossipd_local_channel_update,short_channel_id,short_channel_id,
7 msgdata,gossipd_local_channel_update,htlc_minimum_msat,amount_msat, msgdata,gossipd_local_channel_update,disable,bool,

View File

@ -88,9 +88,6 @@ bool fromwire_gossipd_get_addrs(const void *p UNNEEDED, struct node_id *id UNNEE
/* Generated stub for fromwire_gossipd_get_txout_reply */
bool fromwire_gossipd_get_txout_reply(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED, struct amount_sat *satoshis UNNEEDED, u8 **outscript UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_get_txout_reply called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_get_update */
bool fromwire_gossipd_get_update(const void *p UNNEEDED, struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_get_update called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_init */
bool fromwire_gossipd_init(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, const struct chainparams **chainparams UNNEEDED, struct feature_set **our_features UNNEEDED, struct node_id *id UNNEEDED, u8 rgb[3] UNNEEDED, u8 alias[32] UNNEEDED, struct wireaddr **announcable UNNEEDED, u32 **dev_gossip_time UNNEEDED, bool *dev_fast_gossip UNNEEDED, bool *dev_fast_gossip_prune UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_init called!\n"); abort(); }
@ -199,9 +196,6 @@ void json_object_end(struct json_stream *js UNNEEDED)
/* Generated stub for json_object_start */
void json_object_start(struct json_stream *ks UNNEEDED, const char *fieldname UNNEEDED)
{ fprintf(stderr, "json_object_start called!\n"); abort(); }
/* Generated stub for local_channel_update_latest */
bool local_channel_update_latest(struct daemon *daemon UNNEEDED, struct chan *chan UNNEEDED)
{ fprintf(stderr, "local_channel_update_latest called!\n"); abort(); }
/* Generated stub for local_disable_chan */
void local_disable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED)
{ fprintf(stderr, "local_disable_chan called!\n"); abort(); }
@ -323,9 +317,6 @@ u8 *towire_gossipd_get_addrs_reply(const tal_t *ctx UNNEEDED, const struct wirea
/* Generated stub for towire_gossipd_get_txout */
u8 *towire_gossipd_get_txout(const tal_t *ctx UNNEEDED, const struct short_channel_id *short_channel_id UNNEEDED)
{ fprintf(stderr, "towire_gossipd_get_txout called!\n"); abort(); }
/* Generated stub for towire_gossipd_get_update_reply */
u8 *towire_gossipd_get_update_reply(const tal_t *ctx UNNEEDED, const u8 *update UNNEEDED)
{ fprintf(stderr, "towire_gossipd_get_update_reply called!\n"); abort(); }
/* Generated stub for towire_gossipd_got_onionmsg_to_us */
u8 *towire_gossipd_got_onionmsg_to_us(const tal_t *ctx UNNEEDED, bool obs2 UNNEEDED, const struct pubkey *node_alias UNNEEDED, const struct secret *self_id UNNEEDED, const struct pubkey *reply_blinding UNNEEDED, const struct pubkey *reply_first_node UNNEEDED, const struct onionmsg_path **reply_path UNNEEDED, const u8 *rawmsg UNNEEDED)
{ fprintf(stderr, "towire_gossipd_got_onionmsg_to_us called!\n"); abort(); }

View File

@ -504,6 +504,10 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_PING_REPLY:
ping_reply(sd, msg);
break;
case WIRE_CHANNELD_USED_CHANNEL_UPDATE:
/* This tells gossipd we used it. */
get_channel_update(sd->channel);
break;
#if EXPERIMENTAL_FEATURES
case WIRE_CHANNELD_UPGRADED:
handle_channel_upgrade(sd->channel, msg);
@ -525,6 +529,7 @@ static unsigned channel_msg(struct subd *sd, const u8 *msg, const int *fds)
case WIRE_CHANNELD_FEERATES:
case WIRE_CHANNELD_BLOCKHEIGHT:
case WIRE_CHANNELD_SPECIFIC_FEERATES:
case WIRE_CHANNELD_CHANNEL_UPDATE:
case WIRE_CHANNELD_DEV_MEMLEAK:
case WIRE_CHANNELD_DEV_QUIESCE:
/* Replies go to requests. */
@ -717,7 +722,8 @@ void peer_start_channeld(struct channel *channel,
: (u32 *)&ld->dev_disable_commit,
NULL),
pbases,
reestablish_only);
reestablish_only,
channel->channel_update);
/* We don't expect a response: we are triggered by funding_depth_cb. */
subd_send_msg(channel->owner, take(initmsg));
@ -1008,6 +1014,20 @@ struct command_result *cancel_channel_before_broadcast(struct command *cmd,
return command_still_pending(cmd);
}
void channel_replace_update(struct channel *channel, u8 *update TAKES)
{
tal_free(channel->channel_update);
channel->channel_update = tal_dup_talarr(channel, u8, update);
/* Keep channeld up-to-date */
if (!channel->owner || !streq(channel->owner->name, "channeld"))
return;
subd_send_msg(channel->owner,
take(towire_channeld_channel_update(NULL,
channel->channel_update)));
}
#if DEVELOPER
static struct command_result *json_dev_feerate(struct command *cmd,
const char *buffer,

View File

@ -39,4 +39,8 @@ void channel_record_open(struct channel *channel);
/* A channel has unrecoverably fallen behind */
void channel_fallen_behind(struct channel *channel, const u8 *msg);
/* Fresh channel_update for this channel. */
void channel_replace_update(struct channel *channel, u8 *update TAKES);
#endif /* LIGHTNING_LIGHTNINGD_CHANNEL_CONTROL_H */

View File

@ -11,6 +11,7 @@
#include <lightningd/bitcoind.h>
#include <lightningd/chaintopology.h>
#include <lightningd/channel.h>
#include <lightningd/channel_control.h>
#include <lightningd/gossip_control.h>
#include <lightningd/hsm_control.h>
#include <lightningd/jsonrpc.h>
@ -131,8 +132,7 @@ static void handle_local_channel_update(struct lightningd *ld, const u8 *msg)
return;
}
tal_free(channel->channel_update);
channel->channel_update = tal_steal(channel, update);
channel_replace_update(channel, take(update));
}
const u8 *get_channel_update(struct channel *channel)