core-lightning/gossipd/gossip_generation.c
Rusty Russell 0aad222c2d gossipd: rewrite update generation, remove local_chan.
local_chan was mainly around so we could "soft" disable channels (and
really disable them once we used the channel_update in an error
message).

Instead we introduce the idea of a "deferred_update": it's either
deferred indefinitely (a peer goes offline, if we need to send it in
an error we'll apply it immediatly), or simply delayed to avoid
spamming everyone.

The resulting rewrite is much clearer, IMHO.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
2021-12-30 09:50:40 +10:30

835 lines
25 KiB
C

/* Routines to make our own gossip messages. Not as in "we're the gossip
* generation, man!" */
#include "config.h"
#include <ccan/cast/cast.h>
#include <ccan/mem/mem.h>
#include <common/features.h>
#include <common/memleak.h>
#include <common/status.h>
#include <common/timeout.h>
#include <common/type_to_string.h>
#include <common/wireaddr.h>
#include <errno.h>
#include <gossipd/gossip_generation.h>
#include <gossipd/gossip_store.h>
#include <gossipd/gossip_store_wiregen.h>
#include <gossipd/gossipd.h>
#include <gossipd/gossipd_peerd_wiregen.h>
#include <hsmd/hsmd_wiregen.h>
#include <wire/wire_sync.h>
/* Create a node_announcement with the given signature. It may be NULL in the
* case we need to create a provisional announcement for the HSM to sign.
* This is called twice: once with the dummy signature to get it signed and a
* second time to build the full packet with the signature. The timestamp is
* handed in rather than using time_now() internally, since that could change
* between the dummy creation and the call with a signature. */
static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
const secp256k1_ecdsa_signature *sig,
u32 timestamp,
const struct lease_rates *rates)
{
u8 *addresses = tal_arr(tmpctx, u8, 0);
u8 *announcement;
struct tlv_node_ann_tlvs *na_tlv;
size_t i;
if (!sig)
sig = talz(tmpctx, secp256k1_ecdsa_signature);
for (i = 0; i < tal_count(daemon->announcable); i++)
towire_wireaddr(&addresses, &daemon->announcable[i]);
na_tlv = tlv_node_ann_tlvs_new(tmpctx);
na_tlv->option_will_fund = cast_const(struct lease_rates *, rates);
announcement =
towire_node_announcement(ctx, sig,
daemon->our_features->bits
[NODE_ANNOUNCE_FEATURE],
timestamp,
&daemon->id, daemon->rgb, daemon->alias,
addresses,
na_tlv);
return announcement;
}
/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */
void get_cupdate_parts(const u8 *channel_update,
const u8 *parts[2],
size_t sizes[2])
{
/* BOLT #7:
*
* 1. type: 258 (`channel_update`)
* 2. data:
* * [`signature`:`signature`]
* * [`chain_hash`:`chain_hash`]
* * [`short_channel_id`:`short_channel_id`]
* * [`u32`:`timestamp`]
*...
*/
/* Note: 2 bytes for `type` field */
/* We already checked it's valid before accepting */
assert(tal_count(channel_update) > 2 + 64 + 32 + 8 + 4);
parts[0] = channel_update + 2 + 64;
sizes[0] = 32 + 8;
parts[1] = channel_update + 2 + 64 + 32 + 8 + 4;
sizes[1] = tal_count(channel_update) - (64 + 2 + 32 + 8 + 4);
}
/* Is this channel_update different from prev (not sigs and timestamps)? */
bool cupdate_different(struct gossip_store *gs,
const struct half_chan *hc,
const u8 *cupdate)
{
const u8 *oparts[2], *nparts[2];
size_t osizes[2], nsizes[2];
const u8 *orig;
/* Get last one we have. */
orig = gossip_store_get(tmpctx, gs, hc->bcast.index);
get_cupdate_parts(orig, oparts, osizes);
get_cupdate_parts(cupdate, nparts, nsizes);
return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0])
|| !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]);
}
/* Get non-signature, non-timestamp parts of (valid!) node_announcement,
* with TLV broken out separately */
static void get_nannounce_parts(const u8 *node_announcement,
const u8 *parts[3],
size_t sizes[3])
{
size_t len, ad_len;
const u8 *flen, *ad_start;
/* BOLT #7:
*
* 1. type: 257 (`node_announcement`)
* 2. data:
* * [`signature`:`signature`]
* * [`u16`:`flen`]
* * [`flen*byte`:`features`]
* * [`u32`:`timestamp`]
*...
*/
/* Note: 2 bytes for `type` field */
/* We already checked it's valid before accepting */
assert(tal_count(node_announcement) > 2 + 64);
parts[0] = node_announcement + 2 + 64;
/* Read flen to get size */
flen = parts[0];
len = tal_count(node_announcement) - (2 + 64);
sizes[0] = 2 + fromwire_u16(&flen, &len);
assert(flen != NULL && len >= 4);
/* BOLT-0fe3485a5320efaa2be8cfa0e570ad4d0259cec3 #7:
*
* * [`u32`:`timestamp`]
* * [`point`:`node_id`]
* * [`3*byte`:`rgb_color`]
* * [`32*byte`:`alias`]
* * [`u16`:`addrlen`]
* * [`addrlen*byte`:`addresses`]
* * [`node_ann_tlvs`:`tlvs`]
*/
parts[1] = node_announcement + 2 + 64 + sizes[0] + 4;
/* Find the end of the addresses */
ad_start = parts[1] + 33 + 3 + 32;
len = tal_count(node_announcement)
- (2 + 64 + sizes[0] + 4 + 33 + 3 + 32);
ad_len = fromwire_u16(&ad_start, &len);
assert(ad_start != NULL && len >= ad_len);
sizes[1] = 33 + 3 + 32 + 2 + ad_len;
/* Is there a TLV ? */
sizes[2] = len - ad_len;
if (sizes[2] != 0)
parts[2] = parts[1] + sizes[1];
else
parts[2] = NULL;
}
/* Is this node_announcement different from prev (not sigs and timestamps)? */
bool nannounce_different(struct gossip_store *gs,
const struct node *node,
const u8 *nannounce,
bool *only_missing_tlv)
{
const u8 *oparts[3], *nparts[3];
size_t osizes[3], nsizes[3];
const u8 *orig;
/* Get last one we have. */
orig = gossip_store_get(tmpctx, gs, node->bcast.index);
get_nannounce_parts(orig, oparts, osizes);
get_nannounce_parts(nannounce, nparts, nsizes);
if (only_missing_tlv)
*only_missing_tlv = memeq(oparts[0], osizes[0], nparts[0], nsizes[0])
&& memeq(oparts[1], osizes[1], nparts[1], nsizes[1])
&& !memeq(oparts[2], osizes[2], nparts[2], nsizes[2]);
return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0])
|| !memeq(oparts[1], osizes[1], nparts[1], nsizes[1])
|| !memeq(oparts[2], osizes[2], nparts[2], nsizes[2]);
}
static void sign_and_send_nannounce(struct daemon *daemon,
u8 *nannounce,
u32 timestamp)
{
secp256k1_ecdsa_signature sig;
u8 *msg, *err;
/* Ask hsmd to sign it (synchronous) */
if (!wire_sync_write(HSM_FD, take(towire_hsmd_node_announcement_sig_req(NULL, nannounce))))
status_failed(STATUS_FAIL_MASTER_IO, "Could not write to HSM: %s", strerror(errno));
msg = wire_sync_read(tmpctx, HSM_FD);
if (!fromwire_hsmd_node_announcement_sig_reply(msg, &sig))
status_failed(STATUS_FAIL_MASTER_IO, "HSM returned an invalid node_announcement sig");
/* We got the signature for our provisional node_announcement back
* from the HSM, create the real announcement and forward it to
* gossipd so it can take care of forwarding it. */
nannounce = create_node_announcement(NULL, daemon, &sig,
timestamp, daemon->rates);
/* This injects it into the routing code in routing.c; it should not
* reject it! */
err = handle_node_announcement(daemon->rstate, take(nannounce),
NULL, NULL);
if (err)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"rejected own node announcement: %s",
tal_hex(tmpctx, err));
}
/* Mutual recursion via timer */
static void update_own_node_announcement_after_startup(struct daemon *daemon);
/* This routine created a `node_announcement` for our node, and hands it to
* the routing.c code like any other `node_announcement`. Such announcements
* are only accepted if there is an announced channel associated with that node
* (to prevent spam), so we only call this once we've announced a channel. */
static void update_own_node_announcement(struct daemon *daemon, bool startup)
{
u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec;
u8 *nannounce;
struct node *self = get_node(daemon->rstate, &daemon->id);
/* Discard existing timer. */
daemon->node_announce_timer = tal_free(daemon->node_announce_timer);
/* If we ever use set-based propagation, ensuring the toggle the lower
* bit in consecutive timestamps makes it more robust. */
if (self && self->bcast.index
&& (timestamp & 1) == (self->bcast.timestamp & 1))
timestamp++;
/* Make unsigned announcement. */
nannounce = create_node_announcement(tmpctx, daemon, NULL,
timestamp,
daemon->rates);
/* If it's the same as the previous, nothing to do. */
if (self && self->bcast.index) {
u32 next;
bool only_missing_tlv;
if (!nannounce_different(daemon->rstate->gs, self, nannounce,
&only_missing_tlv))
return;
/* Missing liquidity_ad, maybe we'll get plugin callback */
if (startup && only_missing_tlv) {
u32 delay = GOSSIP_NANN_STARTUP_DELAY(daemon->rstate->dev_fast_gossip);
status_debug("node_announcement: delaying"
" %u secs at start", delay);
daemon->node_announce_timer
= new_reltimer(&daemon->timers,
daemon,
time_from_sec(delay),
update_own_node_announcement_after_startup,
daemon);
return;
}
/* BOLT #7:
*
* The origin node:
* - MUST set `timestamp` to be greater than that of any
* previous `node_announcement` it has previously created.
*/
/* We do better: never send them within more than 5 minutes. */
next = self->bcast.timestamp
+ GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip);
if (timestamp < next) {
status_debug("node_announcement: delaying %u secs",
next - timestamp);
daemon->node_announce_timer
= new_reltimer(&daemon->timers,
daemon,
time_from_sec(next - timestamp),
update_own_node_announcement_after_startup,
daemon);
return;
}
}
sign_and_send_nannounce(daemon, nannounce, timestamp);
}
static void update_own_node_announcement_after_startup(struct daemon *daemon)
{
update_own_node_announcement(daemon, false);
}
/* Should we announce our own node? Called at strategic places. */
void maybe_send_own_node_announce(struct daemon *daemon, bool startup)
{
/* We keep an internal flag in the routing code to say we've announced
* a local channel. The alternative would be to have it make a
* callback, but when we start up we don't want to make multiple
* announcments, so we use this approach for now. */
if (!daemon->rstate->local_channel_announced)
return;
update_own_node_announcement(daemon, startup);
}
/* Fast accessors for channel_update fields */
static u8 *channel_flags_access(const u8 *channel_update)
{
/* BOLT #7:
* 1. type: 258 (`channel_update`)
* 2. data:
* * [`signature`:`signature`]
* * [`chain_hash`:`chain_hash`]
* * [`short_channel_id`:`short_channel_id`]
* * [`u32`:`timestamp`]
* * [`byte`:`message_flags`]
* * [`byte`:`channel_flags`]
*/
/* Note: 2 bytes for `type` field */
return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8 + 4 + 1]);
}
static u8 *timestamp_access(const u8 *channel_update)
{
/* BOLT #7:
* 1. type: 258 (`channel_update`)
* 2. data:
* * [`signature`:`signature`]
* * [`chain_hash`:`chain_hash`]
* * [`short_channel_id`:`short_channel_id`]
* * [`u32`:`timestamp`]
* * [`byte`:`message_flags`]
* * [`byte`:`channel_flags`]
*/
/* Note: 2 bytes for `type` field */
return cast_const(u8 *, &channel_update[2 + 64 + 32 + 8]);
}
static bool is_disabled(const u8 *channel_update)
{
return *channel_flags_access(channel_update) & ROUTING_FLAGS_DISABLED;
}
static bool is_enabled(const u8 *channel_update)
{
return !is_disabled(channel_update);
}
static u32 timestamp_for_update(struct daemon *daemon,
const u32 *prev_timestamp,
bool disable)
{
u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec;
/* Create an unsigned channel_update: we backdate enables, so
* we can always send a disable in an emergency. */
if (!disable)
timestamp -= GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip);
if (prev_timestamp) {
/* Timestamps can't go backwards! */
if (timestamp < *prev_timestamp)
timestamp = *prev_timestamp + 1;
/* If we ever use set-based propagation, ensuring the toggle
* the lower bit in consecutive timestamps makes it more
* robust. */
if ((timestamp & 1) == (*prev_timestamp & 1))
timestamp++;
}
return timestamp;
}
static u8 *sign_and_timestamp_update(const tal_t *ctx,
struct daemon *daemon,
const struct chan *chan,
int direction,
u8 *unsigned_update TAKES)
{
u8 *msg, *update;
be32 timestamp;
const u32 *prev_timestamp;
const struct half_chan *hc = &chan->half[direction];
if (is_halfchan_defined(hc))
prev_timestamp = &hc->bcast.timestamp;
else
prev_timestamp = NULL;
/* Get an appropriate timestamp */
timestamp = cpu_to_be32(timestamp_for_update(daemon,
prev_timestamp,
is_disabled(unsigned_update)));
memcpy(timestamp_access(unsigned_update), &timestamp, sizeof(timestamp));
/* Note that we treat the hsmd as synchronous. This is simple (no
* callback hell)!, but may need to change to async if we ever want
* remote HSMs */
if (!wire_sync_write(HSM_FD,
towire_hsmd_cupdate_sig_req(tmpctx, unsigned_update))) {
status_failed(STATUS_FAIL_HSM_IO, "Writing cupdate_sig_req: %s",
strerror(errno));
}
msg = wire_sync_read(tmpctx, HSM_FD);
if (!msg || !fromwire_hsmd_cupdate_sig_reply(ctx, msg, &update)) {
status_failed(STATUS_FAIL_HSM_IO,
"Reading cupdate_sig_req: %s",
strerror(errno));
}
if (taken(unsigned_update))
tal_free(unsigned_update);
return update;
}
static u8 *create_unsigned_update(const tal_t *ctx,
const struct short_channel_id *scid,
int direction,
bool disable,
u16 cltv_expiry_delta,
struct amount_msat htlc_minimum,
struct amount_msat htlc_maximum,
u32 fee_base_msat,
u32 fee_proportional_millionths)
{
secp256k1_ecdsa_signature dummy_sig;
u8 message_flags, channel_flags;
/* So valgrind doesn't complain */
memset(&dummy_sig, 0, sizeof(dummy_sig));
/* BOLT #7:
*
* The `channel_flags` bitfield is used to indicate the direction of
* the channel: it identifies the node that this update originated
* from and signals various options concerning the channel. The
* following table specifies the meaning of its individual bits:
*
* | Bit Position | Name | Meaning |
* | ------------- | ----------- | -------------------------------- |
* | 0 | `direction` | Direction this update refers to. |
* | 1 | `disable` | Disable the channel. |
*/
channel_flags = direction;
if (disable)
channel_flags |= ROUTING_FLAGS_DISABLED;
/* BOLT #7:
*
* The `message_flags` bitfield is used to indicate the presence of
* optional fields in the `channel_update` message:
*
*| Bit Position | Name | Field |
*...
*| 0 | `option_channel_htlc_max` | `htlc_maximum_msat` |
*/
message_flags = 0 | ROUTING_OPT_HTLC_MAX_MSAT;
/* We create an update with a dummy signature and timestamp. */
return towire_channel_update_option_channel_htlc_max(ctx,
&dummy_sig, /* sig set later */
&chainparams->genesis_blockhash,
scid,
0, /* timestamp set later */
message_flags, channel_flags,
cltv_expiry_delta,
htlc_minimum,
fee_base_msat,
fee_proportional_millionths,
htlc_maximum);
}
static void apply_update(struct daemon *daemon,
const struct chan *chan,
int direction,
u8 *update TAKES)
{
u8 *msg;
struct peer *peer = find_peer(daemon, &chan->nodes[!direction]->id);
if (!is_chan_public(chan)) {
/* Save and restore taken state, for handle_channel_update */
bool update_taken = taken(update);
/* handle_channel_update will not put private updates in the
* broadcast list, but we send it direct to the peer (if we
* have one connected) now */
if (peer)
queue_peer_msg(peer, update);
if (update_taken)
take(update);
}
msg = handle_channel_update(daemon->rstate, update, peer, NULL, true);
if (msg)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"%s: rejected local channel update %s: %s",
__func__,
/* Normally we must not touch something taken()
* but we're in deep trouble anyway, and
* handle_channel_update only tal_steals onto
* tmpctx, so it's actually OK. */
tal_hex(tmpctx, update),
tal_hex(tmpctx, msg));
}
static void sign_timestamp_and_apply_update(struct daemon *daemon,
const struct chan *chan,
int direction,
u8 *update TAKES)
{
update = sign_and_timestamp_update(NULL, daemon, chan, direction,
update);
apply_update(daemon, chan, direction, take(update));
}
/* We don't want to thrash the gossip network, so we often defer sending an
* update. We track them here. */
struct deferred_update {
struct daemon *daemon;
/* Off daemon->deferred_updates */
struct list_node list;
/* Channel it's for (and owner) */
const struct chan *chan;
int direction;
/* Timer which will fire when it's time to apply. */
struct oneshot *channel_update_timer;
/* The actual `update_channel` to apply */
u8 *update;
};
static struct deferred_update *find_deferred_update(struct daemon *daemon,
const struct chan *chan)
{
struct deferred_update *du;
list_for_each(&daemon->deferred_updates, du, list) {
if (du->chan == chan)
return du;
}
return NULL;
}
static void destroy_deferred_update(struct deferred_update *du)
{
list_del(&du->list);
}
static void apply_deferred_update(struct deferred_update *du)
{
apply_update(du->daemon, du->chan, du->direction, take(du->update));
tal_free(du);
}
static void defer_update(struct daemon *daemon,
u32 delay,
const struct chan *chan,
int direction,
u8 *unsigned_update TAKES)
{
struct deferred_update *du;
/* Override any existing one */
tal_free(find_deferred_update(daemon, chan));
/* If chan is gone, so are we. */
du = tal(chan, struct deferred_update);
du->daemon = daemon;
du->chan = chan;
du->direction = direction;
du->update = sign_and_timestamp_update(du, daemon, chan, direction,
unsigned_update);
if (delay != 0xFFFFFFFF)
du->channel_update_timer = new_reltimer(&daemon->timers, du,
time_from_sec(delay),
apply_deferred_update,
du);
else
du->channel_update_timer = NULL;
list_add_tail(&daemon->deferred_updates, &du->list);
tal_add_destructor(du, destroy_deferred_update);
}
/* If there is a pending update for this local channel, apply immediately. */
bool local_channel_update_latest(struct daemon *daemon, struct chan *chan)
{
struct deferred_update *du;
du = find_deferred_update(daemon, chan);
if (!du)
return false;
/* Frees itself */
apply_deferred_update(du);
return true;
}
/* Get previous update. */
static u8 *prev_update(const tal_t *ctx,
struct daemon *daemon, const struct chan *chan, int direction)
{
u8 *prev;
if (!is_halfchan_defined(&chan->half[direction]))
return NULL;
prev = cast_const(u8 *,
gossip_store_get(tmpctx, daemon->rstate->gs,
chan->half[direction].bcast.index));
/* If it's a private update, unwrap */
if (!fromwire_gossip_store_private_update(ctx, prev, &prev))
tal_steal(ctx, prev);
return prev;
}
/* This is a refresh of a local channel (after 13 days). */
void refresh_local_channel(struct daemon *daemon,
struct chan *chan, int direction)
{
u16 cltv_expiry_delta;
struct amount_msat htlc_minimum, htlc_maximum;
u32 fee_base_msat, fee_proportional_millionths, timestamp;
u8 *prev, *update;
u8 message_flags, channel_flags;
secp256k1_ecdsa_signature signature;
struct bitcoin_blkid chain_hash;
struct short_channel_id short_channel_id;
/* If there's a pending update, apply it and we're done. */
if (local_channel_update_latest(daemon, chan))
return;
prev = prev_update(tmpctx, daemon, chan, direction);
if (!prev)
return;
if (!fromwire_channel_update_option_channel_htlc_max(prev,
&signature, &chain_hash,
&short_channel_id, &timestamp,
&message_flags, &channel_flags,
&cltv_expiry_delta,
&htlc_minimum,
&fee_base_msat,
&fee_proportional_millionths,
&htlc_maximum)) {
status_broken("Could not decode local channel_update %s!",
tal_hex(tmpctx, prev));
return;
}
/* BOLT #7:
*
* The `channel_flags` bitfield is used to indicate the direction of
* the channel: it identifies the node that this update originated
* from and signals various options concerning the channel. The
* following table specifies the meaning of its individual bits:
*
* | Bit Position | Name | Meaning |
* | ------------- | ----------- | -------------------------------- |
* | 0 | `direction` | Direction this update refers to. |
* | 1 | `disable` | Disable the channel. |
*/
if (direction != (channel_flags & ROUTING_FLAGS_DIRECTION)) {
status_broken("Wrong channel direction %s!",
tal_hex(tmpctx, prev));
return;
}
/* Don't refresh disabled channels. */
if (channel_flags & ROUTING_FLAGS_DISABLED)
return;
update = create_unsigned_update(NULL, &short_channel_id, direction,
false, cltv_expiry_delta,
htlc_minimum, htlc_maximum,
fee_base_msat,
fee_proportional_millionths);
sign_timestamp_and_apply_update(daemon, chan, direction, take(update));
}
/* channeld asks us to update the local channel. */
bool handle_local_channel_update(struct daemon *daemon,
const struct node_id *src,
const u8 *msg)
{
struct short_channel_id scid;
bool disable;
u16 cltv_expiry_delta;
struct amount_msat htlc_minimum, htlc_maximum;
u32 fee_base_msat, fee_proportional_millionths;
struct chan *chan;
int direction;
u8 *unsigned_update;
const struct half_chan *hc;
/* FIXME: We should get scid from lightningd when setting up the
* connection, so no per-peer daemon can mess with channels other than
* its own! */
if (!fromwire_gossipd_local_channel_update(msg,
&scid,
&disable,
&cltv_expiry_delta,
&htlc_minimum,
&fee_base_msat,
&fee_proportional_millionths,
&htlc_maximum)) {
status_peer_broken(src, "bad local_channel_update %s",
tal_hex(tmpctx, msg));
return false;
}
chan = get_channel(daemon->rstate, &scid);
/* Can theoretically happen if channel just closed. */
if (!chan) {
status_peer_debug(src, "local_channel_update for unknown %s",
type_to_string(tmpctx, struct short_channel_id,
&scid));
return true;
}
if (!local_direction(daemon->rstate, chan, &direction)) {
status_peer_broken(src, "bad local_channel_update chan %s",
type_to_string(tmpctx,
struct short_channel_id,
&scid));
return false;
}
unsigned_update = create_unsigned_update(tmpctx, &scid, direction,
disable, cltv_expiry_delta,
htlc_minimum, htlc_maximum,
fee_base_msat,
fee_proportional_millionths);
hc = &chan->half[direction];
/* Ignore duplicates. */
if (is_halfchan_defined(hc)
&& !cupdate_different(daemon->rstate->gs, hc, unsigned_update))
return true;
/* Too early? Defer (don't worry if it's unannounced). */
if (hc && is_chan_public(chan)) {
u32 now = time_now().ts.tv_sec;
u32 next_time = hc->bcast.timestamp
+ GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip);
if (now < next_time) {
defer_update(daemon, next_time - now,
chan, direction, take(unsigned_update));
return true;
}
}
sign_timestamp_and_apply_update(daemon, chan, direction,
take(unsigned_update));
return true;
}
/* Take update, set/unset disabled flag (and update timestamp).
*/
static void set_disable_flag(u8 *channel_update, bool disable)
{
u8 *channel_flags = channel_flags_access(channel_update);
if (disable)
*channel_flags |= ROUTING_FLAGS_DISABLED;
else
*channel_flags &= ~ROUTING_FLAGS_DISABLED;
}
/* We don't immediately disable, to avoid flapping. */
void local_disable_chan(struct daemon *daemon, const struct chan *chan, int direction)
{
struct deferred_update *du;
u8 *update = prev_update(tmpctx, daemon, chan, direction);
if (!update)
return;
du = find_deferred_update(daemon, chan);
/* Will a deferred update disable it already? OK, nothing to do. */
if (du && is_disabled(du->update))
return;
/* OK, we definitely don't want deferred update to re-enable! */
tal_free(du);
/* Is it already disabled? */
if (is_disabled(update))
return;
/* This is deferred indefinitely (flushed if needed though) */
set_disable_flag(update, true);
defer_update(daemon, 0xFFFFFFFF, chan, direction, take(update));
}
void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction)
{
struct deferred_update *du;
u8 *update = prev_update(tmpctx, daemon, chan, direction);
if (!update)
return;
du = find_deferred_update(daemon, chan);
/* Will a deferred update enable it? If so, apply immediately. */
if (du && is_enabled(du->update)) {
apply_deferred_update(du);
return;
}
/* OK, we definitely don't want deferred update to disable! */
tal_free(du);
/* Is it already enabled? */
if (is_enabled(update))
return;
/* Apply this enabling update immediately. */
set_disable_flag(update, false);
sign_timestamp_and_apply_update(daemon, chan, direction, take(update));
}