gossipd: pass remote private channel update to ld

and stash in the database.

Rusty: I added the bad gossip message so we would see unknown updates in CI, and made sure we don't send our own generated updates to lightningd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Alex Myers 2023-12-07 06:44:05 +10:30 committed by Rusty Russell
parent c1beb4b745
commit 8e897746e2
14 changed files with 198 additions and 12 deletions

View file

@ -600,7 +600,7 @@ static void apply_update(struct daemon *daemon,
take(update);
}
msg = handle_channel_update(daemon->rstate, update, &chan->nodes[direction]->id, NULL, true);
msg = handle_channel_update(daemon->rstate, update, NULL, NULL, true);
if (msg)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"%s: rejected local channel update %s: %s",

View file

@ -1206,6 +1206,7 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY:
case WIRE_GOSSIPD_GET_ADDRS_REPLY:
case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE:
case WIRE_GOSSIPD_REMOTE_CHANNEL_UPDATE:
break;
}

View file

@ -136,3 +136,16 @@ msgdata,gossipd_used_local_channel_update,scid,short_channel_id,
# Tell gossipd we have verified a new public IP by the remote_addr feature
msgtype,gossipd_discovered_ip,3009
msgdata,gossipd_discovered_ip,discovered_ip,wireaddr,
subtype,remote_priv_update
subtypedata,remote_priv_update,source_node,node_id,
subtypedata,remote_priv_update,scid,short_channel_id,
subtypedata,remote_priv_update,fee_base,u32,
subtypedata,remote_priv_update,fee_ppm,u32,
subtypedata,remote_priv_update,cltv_delta,u16,
subtypedata,remote_priv_update,htlc_minimum_msat,amount_msat,
subtypedata,remote_priv_update,htlc_maximum_msat,amount_msat,
# Tell lightningd we received channel update info for a local channel
msgtype,gossipd_remote_channel_update,3010
msgdata,gossipd_remote_channel_update,update,remote_priv_update,

1 #include <common/cryptomsg.h>
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

View file

@ -3,6 +3,7 @@
#include <bitcoin/script.h>
#include <ccan/array_size/array_size.h>
#include <ccan/tal/str/str.h>
#include <common/daemon_conn.h>
#include <common/gossip_store.h>
#include <common/memleak.h>
#include <common/pseudorand.h>
@ -1347,9 +1348,32 @@ static bool is_chan_dying(struct routing_state *rstate,
return false;
}
static void tell_lightningd_private_update(struct routing_state *rstate,
const struct node_id *source_peer,
struct short_channel_id scid,
u32 fee_base_msat,
u32 fee_ppm,
u16 cltv_delta,
struct amount_msat htlc_minimum,
struct amount_msat htlc_maximum)
{
struct remote_priv_update remote_update;
u8* msg;
remote_update.source_node = *source_peer;
remote_update.scid = scid;
remote_update.fee_base = fee_base_msat;
remote_update.fee_ppm = fee_ppm;
remote_update.cltv_delta = cltv_delta;
remote_update.htlc_minimum_msat = htlc_minimum;
remote_update.htlc_maximum_msat = htlc_maximum;
msg = towire_gossipd_remote_channel_update(NULL, &remote_update);
daemon_conn_send(rstate->daemon->master, take(msg));
}
bool routing_add_channel_update(struct routing_state *rstate,
const u8 *update TAKES,
u32 index,
/* NULL if it's us */
const struct node_id *source_peer,
bool ignore_timestamp,
bool force_spam_flag,
@ -1398,6 +1422,16 @@ bool routing_add_channel_update(struct routing_state *rstate,
/* Maybe announcement was waiting for this update? */
uc = get_unupdated_channel(rstate, &short_channel_id);
if (!uc) {
if (index)
return false;
/* Allow ld to process a private channel update */
if (source_peer) {
tell_lightningd_private_update(rstate, source_peer,
short_channel_id, fee_base_msat,
fee_proportional_millionths,
expiry, htlc_minimum,
htlc_maximum);
}
return false;
}
sat = uc->sat;
@ -1535,6 +1569,14 @@ bool routing_add_channel_update(struct routing_state *rstate,
hc->bcast.index = index;
hc->rgraph.index = index;
}
if (source_peer) {
/* give lightningd the channel's inbound info to store to db */
tell_lightningd_private_update(rstate, source_peer,
short_channel_id, fee_base_msat,
fee_proportional_millionths,
expiry, htlc_minimum,
htlc_maximum);
}
return true;
}
@ -2340,4 +2382,3 @@ void routing_channel_spent(struct routing_state *rstate,
type_to_string(msg, struct short_channel_id, &chan->scid));
remember_chan_dying(rstate, &chan->scid, deadline, index);
}

View file

@ -59,6 +59,9 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED,
const struct half_chan *hc UNNEEDED,
const u8 *cupdate UNNEEDED)
{ fprintf(stderr, "cupdate_different called!\n"); abort(); }
/* Generated stub for daemon_conn_send */
void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED)
{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); }
/* Generated stub for gossip_store_add */
u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED,
u32 timestamp UNNEEDED, bool zombie UNNEEDED, bool spam UNNEEDED, bool dying UNNEEDED,
@ -133,6 +136,9 @@ void status_fmt(enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_gossipd_remote_channel_update */
u8 *towire_gossipd_remote_channel_update(const tal_t *ctx UNNEEDED, const struct remote_priv_update *update UNNEEDED)
{ fprintf(stderr, "towire_gossipd_remote_channel_update called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
int main(int argc, char *argv[])

View file

@ -30,6 +30,9 @@ bool cupdate_different(struct gossip_store *gs UNNEEDED,
const struct half_chan *hc UNNEEDED,
const u8 *cupdate UNNEEDED)
{ fprintf(stderr, "cupdate_different called!\n"); abort(); }
/* Generated stub for daemon_conn_send */
void daemon_conn_send(struct daemon_conn *dc UNNEEDED, const u8 *msg UNNEEDED)
{ fprintf(stderr, "daemon_conn_send called!\n"); abort(); }
/* Generated stub for gossip_store_add */
u64 gossip_store_add(struct gossip_store *gs UNNEEDED, const u8 *gossip_msg UNNEEDED,
u32 timestamp UNNEEDED, bool zombie UNNEEDED, bool spam UNNEEDED, bool dying UNNEEDED,
@ -99,6 +102,9 @@ void status_fmt(enum log_level level UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_gossipd_remote_channel_update */
u8 *towire_gossipd_remote_channel_update(const tal_t *ctx UNNEEDED, const struct remote_priv_update *update UNNEEDED)
{ fprintf(stderr, "towire_gossipd_remote_channel_update called!\n"); abort(); }
/* Generated stub for towire_warningfmt */
u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,

View file

@ -264,6 +264,7 @@ struct channel *new_unsaved_channel(struct peer *peer,
= CLOSING_FEE_NEGOTIATION_STEP_UNIT_PERCENTAGE;
channel->shutdown_wrong_funding = NULL;
channel->closing_feerate_range = NULL;
channel->private_update = NULL;
channel->channel_update = NULL;
channel->alias[LOCAL] = channel->alias[REMOTE] = NULL;
@ -427,7 +428,9 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
u16 lease_chan_max_ppt,
struct amount_msat htlc_minimum_msat,
struct amount_msat htlc_maximum_msat,
bool ignore_fee_limits)
bool ignore_fee_limits,
/* NULL or stolen */
struct remote_priv_update *private_update STEALS)
{
struct channel *channel = tal(peer->ld, struct channel);
struct amount_msat htlc_min, htlc_max;
@ -553,6 +556,7 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
channel->lease_commit_sig = tal_steal(channel, lease_commit_sig);
channel->lease_chan_max_msat = lease_chan_max_msat;
channel->lease_chan_max_ppt = lease_chan_max_ppt;
channel->private_update = tal_steal(channel, private_update);
channel->blockheight_states = dup_height_states(channel, height_states);
channel->channel_update = NULL;

View file

@ -8,6 +8,7 @@
#include <common/scb_wiregen.h>
#include <common/tx_roles.h>
#include <common/utils.h>
#include <gossipd/gossipd_wiregen.h>
#include <lightningd/channel_state.h>
#include <wallet/wallet.h>
@ -297,6 +298,10 @@ struct channel {
/* Lease commited max part per thousandth channel fee (ppm * 1000) */
u16 lease_chan_max_ppt;
/* Private channel incoming fee rates, cltv delta min/max htlc from
* peer. Used to generate route hints, blinded paths. */
struct remote_priv_update *private_update;
/* Latest channel_update, for use in error messages. */
u8 *channel_update;
@ -383,7 +388,9 @@ struct channel *new_channel(struct peer *peer, u64 dbid,
u16 lease_chan_max_ppt,
struct amount_msat htlc_minimum_msat,
struct amount_msat htlc_maximum_msat,
bool ignore_fee_limits);
bool ignore_fee_limits,
/* NULL or stolen */
struct remote_priv_update *private_update STEALS);
/* new_inflight - Create a new channel_inflight for a channel */
struct channel_inflight *new_inflight(struct channel *channel,

View file

@ -5,6 +5,7 @@
#include <common/json_command.h>
#include <common/json_param.h>
#include <common/json_stream.h>
#include <common/node_id.h>
#include <common/type_to_string.h>
#include <gossipd/gossipd_wiregen.h>
#include <hsmd/permissions.h>
@ -172,6 +173,57 @@ const u8 *get_channel_update(struct channel *channel)
return channel->channel_update;
}
static void set_channel_remote_update(struct lightningd *ld,
struct channel *channel,
struct remote_priv_update* update TAKES)
{
struct short_channel_id *scid;
scid = channel->scid;
if (!scid)
scid = channel->alias[LOCAL];
if (!node_id_eq(&update->source_node, &channel->peer->id)) {
log_unusual(ld->log, "Bad gossip order: %s sent us a channel update for a "
"channel owned by %s (%s)",
type_to_string(tmpctx, struct node_id,
&update->source_node),
type_to_string(tmpctx, struct node_id,
&channel->peer->id),
type_to_string(tmpctx, struct short_channel_id, scid));
if (taken(update))
tal_free(update);
return;
}
log_debug(ld->log, "updating channel %s with private inbound settings",
type_to_string(tmpctx, struct short_channel_id, scid));
tal_free(channel->private_update);
channel->private_update = tal_dup(channel,
struct remote_priv_update, update);
if (taken(update))
tal_free(update);
wallet_channel_save(ld->wallet, channel);
}
static void handle_private_update_data(struct lightningd *ld, const u8 *msg)
{
struct channel *channel;
struct remote_priv_update *update;
update = tal(tmpctx, struct remote_priv_update);
if (!fromwire_gossipd_remote_channel_update(msg, update))
fatal("Gossip gave bad GOSSIPD_REMOTE_CHANNEL_UPDATE %s",
tal_hex(msg, msg));
channel = any_channel_by_scid(ld, &update->scid, true);
if (!channel) {
log_unusual(ld->log, "could not find channel for peer's "
"private channel update");
return;
}
set_channel_remote_update(ld, channel, update);
}
static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
{
enum gossipd_wire t = fromwire_peektype(msg);
@ -213,6 +265,11 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_GOT_LOCAL_CHANNEL_UPDATE:
handle_local_channel_update(gossip->ld, msg);
break;
case WIRE_GOSSIPD_REMOTE_CHANNEL_UPDATE:
/* Please stash in database for us! */
handle_private_update_data(gossip->ld, msg);
tal_free(msg);
break;
}
return 0;
}

View file

@ -232,7 +232,8 @@ wallet_commit_channel(struct lightningd *ld,
0, NULL, 0, 0, /* No leases on v1s */
ld->config.htlc_minimum_msat,
ld->config.htlc_maximum_msat,
ld->config.ignore_fee_limits);
ld->config.ignore_fee_limits,
NULL);
/* Now we finally put it in the database. */
wallet_channel_insert(ld->wallet, channel);
@ -1486,7 +1487,8 @@ static struct channel *stub_chan(struct command *cmd,
0, NULL, 0, 0, /* No leases on v1s */
ld->config.htlc_minimum_msat,
ld->config.htlc_maximum_msat,
false);
false,
NULL);
return channel;
}

View file

@ -198,7 +198,7 @@ plugins/commando: $(PLUGIN_COMMANDO_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJ
# Topology wants to decode node_announcement, and peer_wiregen which
# pulls in some of bitcoin/.
plugins/topology: common/route.o common/dijkstra.o common/gossmap.o common/fp16.o wire/peer_wiregen.o wire/channel_type_wiregen.o bitcoin/block.o bitcoin/preimage.o $(PLUGIN_TOPOLOGY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
plugins/topology: common/route.o common/dijkstra.o common/gossmap.o common/fp16.o wire/peer_wiregen.o wire/channel_type_wiregen.o bitcoin/block.o bitcoin/preimage.o common/gossmods_listpeerchannels.o $(PLUGIN_TOPOLOGY_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)
plugins/txprepare: $(PLUGIN_TXPREPARE_OBJS) $(PLUGIN_LIB_OBJS) $(PLUGIN_COMMON_OBJS) $(JSMN_OBJS)

View file

@ -176,7 +176,9 @@ struct channel *new_channel(struct peer *peer UNNEEDED, u64 dbid UNNEEDED,
u16 lease_chan_max_ppt UNNEEDED,
struct amount_msat htlc_minimum_msat UNNEEDED,
struct amount_msat htlc_maximum_msat UNNEEDED,
bool ignore_fee_limits UNNEEDED)
bool ignore_fee_limits UNNEEDED,
/* NULL or stolen */
struct remote_priv_update* remote_update STEALS UNNEEDED)
{ fprintf(stderr, "new_channel called!\n"); abort(); }
/* Generated stub for new_coin_wallet_deposit */
struct chain_coin_mvt *new_coin_wallet_deposit(const tal_t *ctx UNNEEDED,

View file

@ -1904,7 +1904,8 @@ static bool test_channel_inflight_crud(struct lightningd *ld, const tal_t *ctx)
7777, 22,
AMOUNT_MSAT(0),
AMOUNT_MSAT(-1ULL),
false);
false,
NULL);
db_begin_transaction(w->db);
CHECK(!wallet_err);
wallet_channel_insert(w, chan);

View file

@ -1514,6 +1514,7 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm
u32 lease_chan_max_msat;
u16 lease_chan_max_ppt;
bool ignore_fee_limits;
struct remote_priv_update *remote_update;
peer_dbid = db_col_u64(stmt, "peer_id");
peer = find_peer_by_dbid(w->ld, peer_dbid);
@ -1678,6 +1679,27 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm
last_sig = NULL;
}
if (!db_col_is_null(stmt, "remote_cltv_expiry_delta")) {
remote_update = tal(NULL, struct remote_priv_update);
remote_update->source_node = peer->id;
if (scid)
remote_update->scid = *scid;
else
remote_update->scid = *alias[LOCAL];
remote_update->fee_base = db_col_int(stmt, "remote_feerate_base");
remote_update->fee_ppm = db_col_int(stmt, "remote_feerate_ppm");
remote_update->cltv_delta = db_col_int(stmt, "remote_cltv_expiry_delta");
remote_update->htlc_minimum_msat = db_col_amount_msat(stmt, "remote_htlc_minimum_msat");
remote_update->htlc_maximum_msat = db_col_amount_msat(stmt, "remote_htlc_maximum_msat");
} else {
remote_update = NULL;
db_col_ignore(stmt, "remote_feerate_base");
db_col_ignore(stmt, "remote_feerate_ppm");
db_col_ignore(stmt, "remote_cltv_expiry_delta");
db_col_ignore(stmt, "remote_htlc_minimum_msat");
db_col_ignore(stmt, "remote_htlc_maximum_msat");
}
chan = new_channel(peer, db_col_u64(stmt, "id"),
&wshachain,
channel_state_in_db(db_col_int(stmt, "state")),
@ -1737,7 +1759,8 @@ static struct channel *wallet_stmt2channel(struct wallet *w, struct db_stmt *stm
lease_chan_max_ppt,
htlc_minimum_msat,
htlc_maximum_msat,
ignore_fee_limits);
ignore_fee_limits,
remote_update);
if (!wallet_channel_load_inflights(w, chan)) {
tal_free(chan);
@ -1925,6 +1948,11 @@ static bool wallet_channels_load_active(struct wallet *w)
", alias_local"
", alias_remote"
", ignore_fee_limits"
", remote_feerate_base"
", remote_feerate_ppm"
", remote_cltv_expiry_delta"
", remote_htlc_minimum_msat"
", remote_htlc_maximum_msat"
" FROM channels"
" WHERE state != ?;")); //? 0
db_bind_int(stmt, CLOSED);
@ -2238,8 +2266,13 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
" htlc_maximum_msat=?," // 43
" alias_local=?," // 44
" alias_remote=?," // 45
" ignore_fee_limits=?" // 46
" WHERE id=?")); // 47
" ignore_fee_limits=?," // 46
" remote_feerate_base=?," // 47
" remote_feerate_ppm=?," // 48
" remote_cltv_expiry_delta=?," // 49
" remote_htlc_minimum_msat=?," // 50
" remote_htlc_maximum_msat=?" // 51
" WHERE id=?")); // 52
db_bind_u64(stmt, chan->their_shachain.id);
if (chan->scid)
db_bind_short_channel_id(stmt, chan->scid);
@ -2321,6 +2354,19 @@ void wallet_channel_save(struct wallet *w, struct channel *chan)
db_bind_null(stmt);
db_bind_int(stmt, chan->ignore_fee_limits);
if (chan->private_update) {
db_bind_int(stmt, chan->private_update->fee_base);
db_bind_int(stmt, chan->private_update->fee_ppm);
db_bind_int(stmt, chan->private_update->cltv_delta);
db_bind_amount_msat(stmt, &chan->private_update->htlc_minimum_msat);
db_bind_amount_msat(stmt, &chan->private_update->htlc_maximum_msat);
} else {
db_bind_null(stmt);
db_bind_null(stmt);
db_bind_null(stmt);
db_bind_null(stmt);
db_bind_null(stmt);
}
db_bind_u64(stmt, chan->dbid);
db_exec_prepared_v2(take(stmt));