mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-23 00:54:20 +01:00
gossipd: simplify duplicate node_announcement check.
Write helpers to split it into non-timestamp, non-signature parts, and simply compare those. We extract a helper to do channel_update, too. This is more generic than our previous approach, and simpler. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -480,11 +480,86 @@ static u8 *create_node_announcement(const tal_t *ctx, struct daemon *daemon,
|
|||||||
return announcement;
|
return announcement;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Helper to get non-signature, non-timestamp parts of (valid!) channel_update */
|
||||||
|
static 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get non-signature, non-timestamp parts of (valid!) node_announcement */
|
||||||
|
static void get_nannounce_parts(const u8 *node_announcement,
|
||||||
|
const u8 *parts[2],
|
||||||
|
size_t sizes[2])
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
const u8 *flen;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
parts[1] = node_announcement + 2 + 64 + sizes[0] + 4;
|
||||||
|
sizes[1] = tal_count(node_announcement) - (2 + 64 + sizes[0] + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*~ Is this node_announcement different from prev (not sigs and timestamps)? */
|
||||||
|
static bool nannounce_different(struct gossip_store *gs,
|
||||||
|
const struct node *node,
|
||||||
|
const u8 *nannounce)
|
||||||
|
{
|
||||||
|
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, node->bcast.index);
|
||||||
|
get_nannounce_parts(orig, oparts, osizes);
|
||||||
|
get_nannounce_parts(nannounce, nparts, nsizes);
|
||||||
|
|
||||||
|
return !memeq(oparts[0], osizes[0], nparts[0], nsizes[0])
|
||||||
|
|| !memeq(oparts[1], osizes[1], nparts[1], nsizes[1]);
|
||||||
|
}
|
||||||
|
|
||||||
/*~ This routine created a `node_announcement` for our node, and hands it to
|
/*~ This routine created a `node_announcement` for our node, and hands it to
|
||||||
* the routing.c code like any other `node_announcement`. Such announcements
|
* the routing.c code like any other `node_announcement`. Such announcements
|
||||||
* are only accepted if there is an announced channel associated with that node
|
* 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. */
|
* (to prevent spam), so we only call this once we've announced a channel. */
|
||||||
static void send_node_announcement(struct daemon *daemon)
|
static void update_own_node_announcement(struct daemon *daemon)
|
||||||
{
|
{
|
||||||
u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec;
|
u32 timestamp = gossip_time_now(daemon->rstate).ts.tv_sec;
|
||||||
secp256k1_ecdsa_signature sig;
|
secp256k1_ecdsa_signature sig;
|
||||||
@@ -500,9 +575,15 @@ static void send_node_announcement(struct daemon *daemon)
|
|||||||
if (self && self->bcast.index && timestamp <= self->bcast.timestamp)
|
if (self && self->bcast.index && timestamp <= self->bcast.timestamp)
|
||||||
timestamp = self->bcast.timestamp + 1;
|
timestamp = self->bcast.timestamp + 1;
|
||||||
|
|
||||||
/* Get an unsigned one. */
|
/* Make unsigned announcement. */
|
||||||
nannounce = create_node_announcement(tmpctx, daemon, NULL, timestamp);
|
nannounce = create_node_announcement(tmpctx, daemon, NULL, timestamp);
|
||||||
|
|
||||||
|
/* If it's the same as the previous, nothing to do. */
|
||||||
|
if (self && self->bcast.index) {
|
||||||
|
if (!nannounce_different(daemon->rstate->gs, self, nannounce))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ask hsmd to sign it (synchronous) */
|
/* Ask hsmd to sign it (synchronous) */
|
||||||
if (!wire_sync_write(HSM_FD, take(towire_hsm_node_announcement_sig_req(NULL, nannounce))))
|
if (!wire_sync_write(HSM_FD, take(towire_hsm_node_announcement_sig_req(NULL, nannounce))))
|
||||||
status_failed(STATUS_FAIL_MASTER_IO, "Could not write to HSM: %s", strerror(errno));
|
status_failed(STATUS_FAIL_MASTER_IO, "Could not write to HSM: %s", strerror(errno));
|
||||||
@@ -592,44 +673,6 @@ static bool get_node_announcement_by_id(const tal_t *ctx,
|
|||||||
features, wireaddrs);
|
features, wireaddrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return true if the only change would be the timestamp. */
|
|
||||||
static bool node_announcement_redundant(struct daemon *daemon)
|
|
||||||
{
|
|
||||||
u8 rgb_color[3];
|
|
||||||
u8 alias[32];
|
|
||||||
u8 *features;
|
|
||||||
struct wireaddr *wireaddrs;
|
|
||||||
|
|
||||||
if (!get_node_announcement_by_id(tmpctx, daemon, &daemon->id,
|
|
||||||
rgb_color, alias, &features,
|
|
||||||
&wireaddrs))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (tal_count(wireaddrs) != tal_count(daemon->announcable))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < tal_count(wireaddrs); i++)
|
|
||||||
if (!wireaddr_eq(&wireaddrs[i], &daemon->announcable[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BUILD_ASSERT(ARRAY_SIZE(daemon->alias) == ARRAY_SIZE(alias));
|
|
||||||
if (!memeq(daemon->alias, ARRAY_SIZE(daemon->alias),
|
|
||||||
alias, ARRAY_SIZE(alias)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BUILD_ASSERT(ARRAY_SIZE(daemon->rgb) == ARRAY_SIZE(rgb_color));
|
|
||||||
if (!memeq(daemon->rgb, ARRAY_SIZE(daemon->rgb),
|
|
||||||
rgb_color, ARRAY_SIZE(rgb_color)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!memeq(daemon->globalfeatures, tal_count(daemon->globalfeatures),
|
|
||||||
features, tal_count(features)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Should we announce our own node? Called at strategic places. */
|
/* Should we announce our own node? Called at strategic places. */
|
||||||
static void maybe_send_own_node_announce(struct daemon *daemon)
|
static void maybe_send_own_node_announce(struct daemon *daemon)
|
||||||
{
|
{
|
||||||
@@ -640,10 +683,7 @@ static void maybe_send_own_node_announce(struct daemon *daemon)
|
|||||||
if (!daemon->rstate->local_channel_announced)
|
if (!daemon->rstate->local_channel_announced)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (node_announcement_redundant(daemon))
|
update_own_node_announcement(daemon);
|
||||||
return;
|
|
||||||
|
|
||||||
send_node_announcement(daemon);
|
|
||||||
daemon->rstate->local_channel_announced = false;
|
daemon->rstate->local_channel_announced = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -981,23 +1021,14 @@ enum query_option_flags {
|
|||||||
static u32 crc32_of_update(const u8 *channel_update)
|
static u32 crc32_of_update(const u8 *channel_update)
|
||||||
{
|
{
|
||||||
u32 sum;
|
u32 sum;
|
||||||
|
const u8 *parts[2];
|
||||||
|
size_t sizes[ARRAY_SIZE(parts)];
|
||||||
|
|
||||||
/* BOLT #7:
|
get_cupdate_parts(channel_update, parts, sizes);
|
||||||
*
|
|
||||||
* 1. type: 258 (`channel_update`)
|
sum = 0;
|
||||||
* 2. data:
|
for (size_t i = 0; i < ARRAY_SIZE(parts); i++)
|
||||||
* * [`signature`:`signature`]
|
sum = crc32c(sum, parts[i], sizes[i]);
|
||||||
* * [`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);
|
|
||||||
sum = crc32c(0, channel_update + 2 + 64, 32 + 8);
|
|
||||||
sum = crc32c(sum, channel_update + 2 + 64 + 32 + 8 + 4,
|
|
||||||
tal_count(channel_update) - (64 + 2 + 32 + 8 + 4));
|
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user