mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-02-22 14:42:40 +01:00
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>
This commit is contained in:
parent
8e37eb0028
commit
0aad222c2d
7 changed files with 527 additions and 339 deletions
|
@ -307,48 +307,136 @@ void maybe_send_own_node_announce(struct daemon *daemon, bool startup)
|
|||
update_own_node_announcement(daemon, startup);
|
||||
}
|
||||
|
||||
/* Our timer callbacks take a single argument, so we marshall everything
|
||||
* we need into this structure: */
|
||||
struct local_cupdate {
|
||||
struct daemon *daemon;
|
||||
struct local_chan *local_chan;
|
||||
|
||||
bool disable;
|
||||
bool even_if_identical;
|
||||
bool even_if_too_soon;
|
||||
|
||||
u16 cltv_expiry_delta;
|
||||
struct amount_msat htlc_minimum, htlc_maximum;
|
||||
u32 fee_base_msat, fee_proportional_millionths;
|
||||
};
|
||||
|
||||
/* This generates a `channel_update` message for one of our channels. We do
|
||||
* this here, rather than in `channeld` because we (may) need to do it
|
||||
* ourselves anyway if channeld dies, or when we refresh it once a week,
|
||||
* and so we can avoid creating redundant ones. */
|
||||
static void update_local_channel(struct local_cupdate *lc /* frees! */)
|
||||
/* Fast accessors for channel_update fields */
|
||||
static u8 *channel_flags_access(const u8 *channel_update)
|
||||
{
|
||||
struct daemon *daemon = lc->daemon;
|
||||
secp256k1_ecdsa_signature dummy_sig;
|
||||
u8 *update, *msg;
|
||||
u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec, next;
|
||||
u8 message_flags, channel_flags;
|
||||
struct chan *chan = lc->local_chan->chan;
|
||||
struct half_chan *hc;
|
||||
const int direction = lc->local_chan->direction;
|
||||
/* 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]);
|
||||
}
|
||||
|
||||
/* Discard existing timer. */
|
||||
lc->local_chan->channel_update_timer
|
||||
= tal_free(lc->local_chan->channel_update_timer);
|
||||
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]);
|
||||
}
|
||||
|
||||
/* So valgrind doesn't complain */
|
||||
memset(&dummy_sig, 0, sizeof(dummy_sig));
|
||||
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 (!lc->disable)
|
||||
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), ×tamp, 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
|
||||
|
@ -362,7 +450,7 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */)
|
|||
* | 1 | `disable` | Disable the channel. |
|
||||
*/
|
||||
channel_flags = direction;
|
||||
if (lc->disable)
|
||||
if (disable)
|
||||
channel_flags |= ROUTING_FLAGS_DISABLED;
|
||||
|
||||
/* BOLT #7:
|
||||
|
@ -376,101 +464,43 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */)
|
|||
*/
|
||||
message_flags = 0 | ROUTING_OPT_HTLC_MAX_MSAT;
|
||||
|
||||
/* Convenience variable. */
|
||||
hc = &chan->half[direction];
|
||||
|
||||
/* If we ever use set-based propagation, ensuring the toggle
|
||||
* the lower bit in consecutive timestamps makes it more
|
||||
* robust. */
|
||||
if (is_halfchan_defined(hc)
|
||||
&& (timestamp & 1) == (hc->bcast.timestamp & 1))
|
||||
timestamp++;
|
||||
|
||||
/* We create an update with a dummy signature, and hand to hsmd to get
|
||||
* it signed. */
|
||||
update = towire_channel_update_option_channel_htlc_max(tmpctx, &dummy_sig,
|
||||
/* 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,
|
||||
&chan->scid,
|
||||
timestamp,
|
||||
scid,
|
||||
0, /* timestamp set later */
|
||||
message_flags, channel_flags,
|
||||
lc->cltv_expiry_delta,
|
||||
lc->htlc_minimum,
|
||||
lc->fee_base_msat,
|
||||
lc->fee_proportional_millionths,
|
||||
lc->htlc_maximum);
|
||||
cltv_expiry_delta,
|
||||
htlc_minimum,
|
||||
fee_base_msat,
|
||||
fee_proportional_millionths,
|
||||
htlc_maximum);
|
||||
}
|
||||
|
||||
if (is_halfchan_defined(hc)) {
|
||||
/* Suppress duplicates. */
|
||||
if (!lc->even_if_identical
|
||||
&& !cupdate_different(daemon->rstate->gs, hc, update)) {
|
||||
tal_free(lc);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
|
||||
/* Is it too soon to send another update? */
|
||||
next = hc->bcast.timestamp
|
||||
+ GOSSIP_MIN_INTERVAL(daemon->rstate->dev_fast_gossip);
|
||||
|
||||
if (timestamp < next && !lc->even_if_too_soon) {
|
||||
status_debug("channel_update %s/%u: delaying %u secs",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
&chan->scid),
|
||||
direction,
|
||||
next - timestamp);
|
||||
lc->local_chan->channel_update_timer
|
||||
= new_reltimer(&daemon->timers, lc,
|
||||
time_from_sec(next - timestamp),
|
||||
update_local_channel,
|
||||
lc);
|
||||
/* If local chan vanishes, so does update, and timer. */
|
||||
notleak(tal_steal(lc->local_chan, lc));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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, 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(tmpctx, msg, &update)) {
|
||||
status_failed(STATUS_FAIL_HSM_IO,
|
||||
"Reading cupdate_sig_req: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* The origin node:
|
||||
*...
|
||||
* - MAY create a `channel_update` to communicate the channel parameters to the
|
||||
* channel peer, even though the channel has not yet been announced (i.e. the
|
||||
* `announce_channel` bit was not set).
|
||||
*/
|
||||
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 */
|
||||
struct peer *peer = find_peer(daemon,
|
||||
&chan->nodes[!direction]->id);
|
||||
if (peer)
|
||||
queue_peer_msg(peer, update);
|
||||
|
||||
if (update_taken)
|
||||
take(update);
|
||||
}
|
||||
|
||||
/* We feed it into routing.c like any other channel_update; it may
|
||||
* discard it (eg. non-public channel), but it should not complain
|
||||
* about it being invalid! __func__ is a magic C constant which
|
||||
* expands to this function name. */
|
||||
msg = handle_channel_update(daemon->rstate, update,
|
||||
find_peer(daemon,
|
||||
&chan->nodes[!direction]->id),
|
||||
NULL, true);
|
||||
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",
|
||||
|
@ -481,72 +511,181 @@ static void update_local_channel(struct local_cupdate *lc /* frees! */)
|
|||
* tmpctx, so it's actually OK. */
|
||||
tal_hex(tmpctx, update),
|
||||
tal_hex(tmpctx, msg));
|
||||
|
||||
tal_free(lc);
|
||||
}
|
||||
|
||||
/* This is a refresh of a local channel: sends an update if one is needed. */
|
||||
void refresh_local_channel(struct daemon *daemon,
|
||||
struct local_chan *local_chan,
|
||||
bool even_if_identical)
|
||||
static void sign_timestamp_and_apply_update(struct daemon *daemon,
|
||||
const struct chan *chan,
|
||||
int direction,
|
||||
u8 *update TAKES)
|
||||
{
|
||||
const struct half_chan *hc;
|
||||
struct local_cupdate *lc;
|
||||
u8 *prev;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
struct bitcoin_blkid chain_hash;
|
||||
struct short_channel_id short_channel_id;
|
||||
u32 timestamp;
|
||||
u8 message_flags, channel_flags;
|
||||
update = sign_and_timestamp_update(NULL, daemon, chan, direction,
|
||||
update);
|
||||
apply_update(daemon, chan, direction, take(update));
|
||||
}
|
||||
|
||||
hc = &local_chan->chan->half[local_chan->direction];
|
||||
/* 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;
|
||||
};
|
||||
|
||||
/* Don't generate a channel_update for an uninitialized channel. */
|
||||
if (!is_halfchan_defined(hc))
|
||||
return;
|
||||
static struct deferred_update *find_deferred_update(struct daemon *daemon,
|
||||
const struct chan *chan)
|
||||
{
|
||||
struct deferred_update *du;
|
||||
|
||||
/* If there's an update pending already, force it to apply now. */
|
||||
if (local_chan->channel_update_timer) {
|
||||
lc = reltimer_arg(local_chan->channel_update_timer);
|
||||
lc->even_if_too_soon = true;
|
||||
update_local_channel(lc);
|
||||
/* Free timer */
|
||||
local_chan->channel_update_timer
|
||||
= tal_free(local_chan->channel_update_timer);
|
||||
list_for_each(&daemon->deferred_updates, du, list) {
|
||||
if (du->chan == chan)
|
||||
return du;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lc = tal(NULL, struct local_cupdate);
|
||||
lc->daemon = daemon;
|
||||
lc->local_chan = local_chan;
|
||||
lc->even_if_identical = even_if_identical;
|
||||
lc->even_if_too_soon = false;
|
||||
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,
|
||||
local_chan->chan->half[local_chan->direction]
|
||||
.bcast.index));
|
||||
chan->half[direction].bcast.index));
|
||||
|
||||
/* If it's a private update, unwrap */
|
||||
fromwire_gossip_store_private_update(tmpctx, prev, &prev);
|
||||
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, ×tamp,
|
||||
&message_flags, &channel_flags,
|
||||
&lc->cltv_expiry_delta,
|
||||
&lc->htlc_minimum,
|
||||
&lc->fee_base_msat,
|
||||
&lc->fee_proportional_millionths,
|
||||
&lc->htlc_maximum)) {
|
||||
&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));
|
||||
tal_free(lc);
|
||||
return;
|
||||
}
|
||||
|
||||
lc->disable = (channel_flags & ROUTING_FLAGS_DISABLED)
|
||||
|| local_chan->local_disabled;
|
||||
update_local_channel(lc);
|
||||
/* 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. */
|
||||
|
@ -555,43 +694,141 @@ bool handle_local_channel_update(struct daemon *daemon,
|
|||
const u8 *msg)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
struct local_cupdate *lc = tal(tmpctx, struct local_cupdate);
|
||||
|
||||
lc->daemon = daemon;
|
||||
lc->even_if_identical = false;
|
||||
lc->even_if_too_soon = false;
|
||||
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,
|
||||
&lc->disable,
|
||||
&lc->cltv_expiry_delta,
|
||||
&lc->htlc_minimum,
|
||||
&lc->fee_base_msat,
|
||||
&lc->fee_proportional_millionths,
|
||||
&lc->htlc_maximum)) {
|
||||
&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;
|
||||
}
|
||||
|
||||
lc->local_chan = local_chan_map_get(&daemon->rstate->local_chan_map,
|
||||
&scid);
|
||||
chan = get_channel(daemon->rstate, &scid);
|
||||
/* Can theoretically happen if channel just closed. */
|
||||
if (!lc->local_chan) {
|
||||
if (!chan) {
|
||||
status_peer_debug(src, "local_channel_update for unknown %s",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&scid));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Remove soft local_disabled flag, if they're marking it enabled. */
|
||||
if (!lc->disable)
|
||||
local_enable_chan(daemon->rstate, lc->local_chan->chan);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Apply the update they told us */
|
||||
update_local_channel(tal_steal(NULL, lc));
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -35,10 +35,18 @@ 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);
|
||||
|
||||
/* This is a refresh of a local channel: sends an update if one is needed. */
|
||||
/* 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);
|
||||
|
||||
/* Re-enable this local channel */
|
||||
void local_enable_chan(struct daemon *daemon, const struct chan *chan, int direction);
|
||||
|
||||
/* This is a refresh of a local channel which is > 13 days old. */
|
||||
void refresh_local_channel(struct daemon *daemon,
|
||||
struct local_chan *local_chan,
|
||||
bool even_if_identical);
|
||||
struct chan *chan, int direction);
|
||||
|
||||
/* channeld asks us to update the local channel. */
|
||||
bool handle_local_channel_update(struct daemon *daemon,
|
||||
|
|
|
@ -44,15 +44,32 @@
|
|||
* whole-channel flag which indicates it's not available; we use this when a
|
||||
* peer disconnects, and generate a `channel_update` to tell the world lazily
|
||||
* when someone asks. */
|
||||
static void peer_disable_channels(struct daemon *daemon, struct node *node)
|
||||
static void peer_disable_channels(struct daemon *daemon, const struct node *node)
|
||||
{
|
||||
/* If this peer had a channel with us, mark it disabled. */
|
||||
struct chan_map_iter i;
|
||||
struct chan *c;
|
||||
const struct chan *c;
|
||||
|
||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||
if (node_id_eq(&other_node(node, c)->id, &daemon->id))
|
||||
local_disable_chan(daemon->rstate, c);
|
||||
int direction;
|
||||
if (!local_direction(daemon->rstate, c, &direction))
|
||||
continue;
|
||||
local_disable_chan(daemon, c, direction);
|
||||
}
|
||||
}
|
||||
|
||||
/*~ This cancels the soft-disables when the peer reconnects. */
|
||||
static void peer_enable_channels(struct daemon *daemon, const struct node *node)
|
||||
{
|
||||
/* If this peer had a channel with us, mark it disabled. */
|
||||
struct chan_map_iter i;
|
||||
const struct chan *c;
|
||||
|
||||
for (c = first_chan(node, &i); c; c = next_chan(node, &i)) {
|
||||
int direction;
|
||||
if (!local_direction(daemon->rstate, c, &direction))
|
||||
continue;
|
||||
local_enable_chan(daemon, c, direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,10 +284,10 @@ static u8 *handle_channel_update_msg(struct peer *peer, const u8 *msg)
|
|||
static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
struct local_chan *local_chan;
|
||||
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",
|
||||
|
@ -280,8 +297,8 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg)
|
|||
}
|
||||
|
||||
/* It's possible that the channel has just closed (though v. unlikely) */
|
||||
local_chan = local_chan_map_get(&rstate->local_chan_map, &scid);
|
||||
if (!local_chan) {
|
||||
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,
|
||||
|
@ -290,18 +307,24 @@ static bool handle_get_local_channel_update(struct peer *peer, const u8 *msg)
|
|||
goto out;
|
||||
}
|
||||
|
||||
chan = local_chan->chan;
|
||||
|
||||
/* Since we're going to send it out, make sure it's up-to-date. */
|
||||
refresh_local_channel(peer->daemon, local_chan, false);
|
||||
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[local_chan->direction]))
|
||||
if (!is_halfchan_defined(&chan->half[direction]))
|
||||
update = NULL;
|
||||
else
|
||||
update = gossip_store_get(tmpctx, rstate->gs,
|
||||
chan->half[local_chan->direction].bcast.index);
|
||||
chan->half[direction].bcast.index);
|
||||
out:
|
||||
status_peer_debug(&peer->id, "schanid %s: %s update",
|
||||
type_to_string(tmpctx, struct short_channel_id, &scid),
|
||||
|
@ -808,6 +831,7 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
|
|||
const u8 *msg)
|
||||
{
|
||||
struct peer *peer = tal(conn, struct peer);
|
||||
struct node *node;
|
||||
int fds[2];
|
||||
int gossip_store_fd;
|
||||
struct gossip_state *gs;
|
||||
|
@ -869,6 +893,10 @@ static struct io_plan *connectd_new_peer(struct io_conn *conn,
|
|||
/* Free peer if conn closed (destroy_peer closes conn if peer freed) */
|
||||
tal_steal(peer->dc, peer);
|
||||
|
||||
node = get_node(daemon->rstate, &peer->id);
|
||||
if (node)
|
||||
peer_enable_channels(daemon, node);
|
||||
|
||||
/* This sends the initial timestamp filter. */
|
||||
seeker_setup_peer_gossip(daemon->seeker, peer);
|
||||
|
||||
|
@ -967,23 +995,6 @@ static struct io_plan *connectd_req(struct io_conn *conn,
|
|||
return io_close(conn);
|
||||
}
|
||||
|
||||
/*~ This is our 13-day timer callback for refreshing our channels. This
|
||||
* was added to the spec because people abandoned their channels without
|
||||
* closing them. */
|
||||
static void gossip_send_keepalive_update(struct daemon *daemon,
|
||||
struct local_chan *local_chan)
|
||||
{
|
||||
status_debug("Sending keepalive channel_update for %s/%u",
|
||||
type_to_string(tmpctx, struct short_channel_id,
|
||||
&local_chan->chan->scid),
|
||||
local_chan->direction);
|
||||
|
||||
/* As a side-effect, this will create an update which matches the
|
||||
* local_disabled state */
|
||||
refresh_local_channel(daemon, local_chan, true);
|
||||
}
|
||||
|
||||
|
||||
/* BOLT #7:
|
||||
*
|
||||
* A node:
|
||||
|
@ -1016,11 +1027,13 @@ static void gossip_refresh_network(struct daemon *daemon)
|
|||
struct chan *c;
|
||||
|
||||
for (c = first_chan(n, &i); c; c = next_chan(n, &i)) {
|
||||
struct local_chan *local_chan;
|
||||
struct half_chan *hc;
|
||||
int direction;
|
||||
|
||||
local_chan = is_local_chan(daemon->rstate, c);
|
||||
hc = &c->half[local_chan->direction];
|
||||
if (!local_direction(daemon->rstate, c, &direction))
|
||||
continue;
|
||||
|
||||
hc = &c->half[direction];
|
||||
|
||||
if (!is_halfchan_defined(hc)) {
|
||||
/* Connection is not announced yet, so don't even
|
||||
|
@ -1033,12 +1046,12 @@ static void gossip_refresh_network(struct daemon *daemon)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (is_chan_local_disabled(daemon->rstate, c)) {
|
||||
/* Only send keepalives for active connections */
|
||||
continue;
|
||||
}
|
||||
|
||||
gossip_send_keepalive_update(daemon, local_chan);
|
||||
status_debug("Sending keepalive channel_update"
|
||||
" for %s/%u",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
&c->scid), direction);
|
||||
refresh_local_channel(daemon, c, direction);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1060,7 +1073,7 @@ static void gossip_disable_local_channels(struct daemon *daemon)
|
|||
return;
|
||||
|
||||
for (c = first_chan(local_node, &i); c; c = next_chan(local_node, &i))
|
||||
local_disable_chan(daemon->rstate, c);
|
||||
local_disable_chan(daemon, c, half_chan_idx(local_node, c));
|
||||
}
|
||||
|
||||
struct peer *random_peer(struct daemon *daemon,
|
||||
|
@ -1244,24 +1257,34 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn,
|
|||
struct daemon *daemon, const u8 *msg)
|
||||
{
|
||||
struct short_channel_id scid;
|
||||
struct local_chan *local_chan;
|
||||
struct chan *chan;
|
||||
const u8 *stripped_update;
|
||||
|
||||
if (!fromwire_gossipd_get_stripped_cupdate(msg, &scid))
|
||||
master_badmsg(WIRE_GOSSIPD_GET_STRIPPED_CUPDATE, msg);
|
||||
|
||||
local_chan = local_chan_map_get(&daemon->rstate->local_chan_map, &scid);
|
||||
if (!local_chan) {
|
||||
chan = get_channel(daemon->rstate, &scid);
|
||||
if (!chan) {
|
||||
status_debug("Failed to resolve local channel %s",
|
||||
type_to_string(tmpctx, struct short_channel_id, &scid));
|
||||
stripped_update = NULL;
|
||||
} else {
|
||||
int direction;
|
||||
const struct half_chan *hc;
|
||||
|
||||
/* Since we're going to use it, make sure it's up-to-date. */
|
||||
refresh_local_channel(daemon, local_chan, false);
|
||||
if (!local_direction(daemon->rstate, chan, &direction)) {
|
||||
status_broken("%s is a non-local channel!",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
&scid));
|
||||
stripped_update = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
hc = &local_chan->chan->half[local_chan->direction];
|
||||
/* Since we're going to use it, make sure it's up-to-date. */
|
||||
local_channel_update_latest(daemon, chan);
|
||||
|
||||
hc = &chan->half[direction];
|
||||
if (is_halfchan_defined(hc)) {
|
||||
const u8 *update;
|
||||
|
||||
|
@ -1272,6 +1295,8 @@ static struct io_plan *get_stripped_cupdate(struct io_conn *conn,
|
|||
} else
|
||||
stripped_update = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
daemon_conn_send(daemon->master,
|
||||
take(towire_gossipd_get_stripped_cupdate_reply(NULL,
|
||||
stripped_update)));
|
||||
|
@ -1423,8 +1448,18 @@ static struct io_plan *handle_local_channel_close(struct io_conn *conn,
|
|||
master_badmsg(WIRE_GOSSIPD_LOCAL_CHANNEL_CLOSE, msg);
|
||||
|
||||
chan = get_channel(rstate, &scid);
|
||||
if (chan)
|
||||
local_disable_chan(rstate, chan);
|
||||
if (chan) {
|
||||
int direction;
|
||||
|
||||
if (!local_direction(rstate, chan, &direction)) {
|
||||
status_broken("Non-local channel close %s",
|
||||
type_to_string(tmpctx,
|
||||
struct short_channel_id,
|
||||
&scid));
|
||||
} else {
|
||||
local_disable_chan(daemon, chan, direction);
|
||||
}
|
||||
}
|
||||
return daemon_conn_read_next(conn, daemon->master);
|
||||
}
|
||||
|
||||
|
@ -1522,6 +1557,7 @@ int main(int argc, char *argv[])
|
|||
daemon->node_announce_timer = NULL;
|
||||
daemon->current_blockheight = 0; /* i.e. unknown */
|
||||
daemon->rates = NULL;
|
||||
list_head_init(&daemon->deferred_updates);
|
||||
|
||||
/* Tell the ecdh() function how to talk to hsmd */
|
||||
ecdh_hsmd_setup(HSM_FD, status_failed);
|
||||
|
|
|
@ -60,6 +60,9 @@ struct daemon {
|
|||
|
||||
/* The channel lease rates we're advertising */
|
||||
const struct lease_rates *rates;
|
||||
|
||||
/* Any of our channel_updates we're deferring. */
|
||||
struct list_head deferred_updates;
|
||||
};
|
||||
|
||||
struct range_query_reply {
|
||||
|
|
|
@ -198,7 +198,6 @@ static void destroy_routing_state(struct routing_state *rstate)
|
|||
|
||||
/* Free up our htables */
|
||||
pending_cannouncement_map_clear(&rstate->pending_cannouncements);
|
||||
local_chan_map_clear(&rstate->local_chan_map);
|
||||
}
|
||||
|
||||
/* We don't check this when loading from the gossip_store: that would break
|
||||
|
@ -226,7 +225,6 @@ static void memleak_help_routing_tables(struct htable *memtable,
|
|||
memleak_remove_htable(memtable, &rstate->nodes->raw);
|
||||
memleak_remove_htable(memtable, &rstate->pending_node_map->raw);
|
||||
memleak_remove_htable(memtable, &rstate->pending_cannouncements.raw);
|
||||
memleak_remove_htable(memtable, &rstate->local_chan_map.raw);
|
||||
memleak_remove_uintmap(memtable, &rstate->unupdated_chanmap);
|
||||
|
||||
for (n = node_map_first(rstate->nodes, &nit);
|
||||
|
@ -295,7 +293,6 @@ struct routing_state *new_routing_state(const tal_t *ctx,
|
|||
|
||||
uintmap_init(&rstate->chanmap);
|
||||
uintmap_init(&rstate->unupdated_chanmap);
|
||||
local_chan_map_init(&rstate->local_chan_map);
|
||||
rstate->num_txout_failures = 0;
|
||||
uintmap_init(&rstate->txout_failures);
|
||||
uintmap_init(&rstate->txout_failures_old);
|
||||
|
@ -524,36 +521,6 @@ static void bad_gossip_order(const u8 *msg,
|
|||
details);
|
||||
}
|
||||
|
||||
static void destroy_local_chan(struct local_chan *local_chan,
|
||||
struct routing_state *rstate)
|
||||
{
|
||||
if (!local_chan_map_del(&rstate->local_chan_map, local_chan))
|
||||
abort();
|
||||
}
|
||||
|
||||
static void maybe_add_local_chan(struct routing_state *rstate,
|
||||
struct chan *chan)
|
||||
{
|
||||
int direction;
|
||||
struct local_chan *local_chan;
|
||||
|
||||
if (node_id_eq(&chan->nodes[0]->id, &rstate->local_id))
|
||||
direction = 0;
|
||||
else if (node_id_eq(&chan->nodes[1]->id, &rstate->local_id))
|
||||
direction = 1;
|
||||
else
|
||||
return;
|
||||
|
||||
local_chan = tal(chan, struct local_chan);
|
||||
local_chan->chan = chan;
|
||||
local_chan->direction = direction;
|
||||
local_chan->local_disabled = false;
|
||||
local_chan->channel_update_timer = NULL;
|
||||
|
||||
local_chan_map_add(&rstate->local_chan_map, local_chan);
|
||||
tal_add_destructor2(local_chan, destroy_local_chan, rstate);
|
||||
}
|
||||
|
||||
struct chan *new_chan(struct routing_state *rstate,
|
||||
const struct short_channel_id *scid,
|
||||
const struct node_id *id1,
|
||||
|
@ -595,8 +562,6 @@ struct chan *new_chan(struct routing_state *rstate,
|
|||
|
||||
uintmap_add(&rstate->chanmap, scid->u64, chan);
|
||||
|
||||
/* Initialize shadow structure if it's local */
|
||||
maybe_add_local_chan(rstate, chan);
|
||||
return chan;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,22 +94,6 @@ static inline bool chan_eq_scid(const struct chan *c,
|
|||
|
||||
HTABLE_DEFINE_TYPE(struct chan, chan_map_scid, hash_scid, chan_eq_scid, chan_map);
|
||||
|
||||
/* Container for local channel pointers. */
|
||||
static inline const struct short_channel_id *local_chan_map_scid(const struct local_chan *local_chan)
|
||||
{
|
||||
return &local_chan->chan->scid;
|
||||
}
|
||||
|
||||
static inline bool local_chan_eq_scid(const struct local_chan *local_chan,
|
||||
const struct short_channel_id *scid)
|
||||
{
|
||||
return short_channel_id_eq(scid, &local_chan->chan->scid);
|
||||
}
|
||||
|
||||
HTABLE_DEFINE_TYPE(struct local_chan,
|
||||
local_chan_map_scid, hash_scid, local_chan_eq_scid,
|
||||
local_chan_map);
|
||||
|
||||
/* For a small number of channels (by far the most common) we use a simple
|
||||
* array, with empty buckets NULL. For larger, we use a proper hash table,
|
||||
* with the extra allocation that implies. */
|
||||
|
@ -191,33 +175,13 @@ HTABLE_DEFINE_TYPE(struct pending_cannouncement, panding_cannouncement_map_scid,
|
|||
struct pending_node_map;
|
||||
struct unupdated_channel;
|
||||
|
||||
/* Fast versions: if you know n is one end of the channel */
|
||||
static inline struct node *other_node(const struct node *n,
|
||||
const struct chan *chan)
|
||||
/* If you know n is one end of the channel, get index of src == n */
|
||||
static inline int half_chan_idx(const struct node *n, const struct chan *chan)
|
||||
{
|
||||
int idx = (chan->nodes[1] == n);
|
||||
|
||||
assert(chan->nodes[0] == n || chan->nodes[1] == n);
|
||||
return chan->nodes[!idx];
|
||||
}
|
||||
|
||||
/* If you know n is one end of the channel, get connection src == n */
|
||||
static inline struct half_chan *half_chan_from(const struct node *n,
|
||||
struct chan *chan)
|
||||
{
|
||||
int idx = (chan->nodes[1] == n);
|
||||
|
||||
assert(chan->nodes[0] == n || chan->nodes[1] == n);
|
||||
return &chan->half[idx];
|
||||
}
|
||||
|
||||
/* If you know n is one end of the channel, get index dst == n */
|
||||
static inline int half_chan_to(const struct node *n, const struct chan *chan)
|
||||
{
|
||||
int idx = (chan->nodes[1] == n);
|
||||
|
||||
assert(chan->nodes[0] == n || chan->nodes[1] == n);
|
||||
return !idx;
|
||||
return idx;
|
||||
}
|
||||
|
||||
struct routing_state {
|
||||
|
@ -255,9 +219,6 @@ struct routing_state {
|
|||
UINTMAP(bool) txout_failures, txout_failures_old;
|
||||
struct oneshot *txout_failure_timer;
|
||||
|
||||
/* A map of local channels by short_channel_ids */
|
||||
struct local_chan_map local_chan_map;
|
||||
|
||||
/* Highest timestamp of gossip we accepted (before now) */
|
||||
u32 last_timestamp;
|
||||
|
||||
|
@ -427,41 +388,11 @@ bool routing_add_private_channel(struct routing_state *rstate,
|
|||
*/
|
||||
struct timeabs gossip_time_now(const struct routing_state *rstate);
|
||||
|
||||
static inline struct local_chan *is_local_chan(struct routing_state *rstate,
|
||||
const struct chan *chan)
|
||||
{
|
||||
return local_chan_map_get(&rstate->local_chan_map, &chan->scid);
|
||||
}
|
||||
|
||||
/* Would we ratelimit a channel_update with this timestamp? */
|
||||
bool would_ratelimit_cupdate(struct routing_state *rstate,
|
||||
const struct half_chan *hc,
|
||||
u32 timestamp);
|
||||
|
||||
/* Because we can have millions of channels, and we only want a local_disable
|
||||
* flag on ones connected to us, we keep a separate hashtable for that flag.
|
||||
*/
|
||||
static inline bool is_chan_local_disabled(struct routing_state *rstate,
|
||||
const struct chan *chan)
|
||||
{
|
||||
struct local_chan *local_chan = is_local_chan(rstate, chan);
|
||||
return local_chan && local_chan->local_disabled;
|
||||
}
|
||||
|
||||
static inline void local_disable_chan(struct routing_state *rstate,
|
||||
const struct chan *chan)
|
||||
{
|
||||
struct local_chan *local_chan = is_local_chan(rstate, chan);
|
||||
local_chan->local_disabled = true;
|
||||
}
|
||||
|
||||
static inline void local_enable_chan(struct routing_state *rstate,
|
||||
const struct chan *chan)
|
||||
{
|
||||
struct local_chan *local_chan = is_local_chan(rstate, chan);
|
||||
local_chan->local_disabled = false;
|
||||
}
|
||||
|
||||
/* Remove channel from store: announcement and any updates. */
|
||||
void remove_channel_from_store(struct routing_state *rstate,
|
||||
struct chan *chan);
|
||||
|
|
|
@ -203,6 +203,15 @@ 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(); }
|
||||
/* Generated stub for local_enable_chan */
|
||||
void local_enable_chan(struct daemon *daemon UNNEEDED, const struct chan *chan UNNEEDED, int direction UNNEEDED)
|
||||
{ fprintf(stderr, "local_enable_chan called!\n"); abort(); }
|
||||
/* Generated stub for master_badmsg */
|
||||
void master_badmsg(u32 type_expected UNNEEDED, const u8 *msg)
|
||||
{ fprintf(stderr, "master_badmsg called!\n"); abort(); }
|
||||
|
@ -258,8 +267,7 @@ void query_unknown_node(struct seeker *seeker UNNEEDED, struct peer *peer UNNEED
|
|||
{ fprintf(stderr, "query_unknown_node called!\n"); abort(); }
|
||||
/* Generated stub for refresh_local_channel */
|
||||
void refresh_local_channel(struct daemon *daemon UNNEEDED,
|
||||
struct local_chan *local_chan UNNEEDED,
|
||||
bool even_if_identical UNNEEDED)
|
||||
struct chan *chan UNNEEDED, int direction UNNEEDED)
|
||||
{ fprintf(stderr, "refresh_local_channel called!\n"); abort(); }
|
||||
/* Generated stub for remove_channel_from_store */
|
||||
void remove_channel_from_store(struct routing_state *rstate UNNEEDED,
|
||||
|
|
Loading…
Add table
Reference in a new issue