From c5547e2209d38567cbc7802de043548d74323276 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 31 Jan 2024 13:46:17 +1030 Subject: [PATCH] lightningd: add gossip_generation.c Routines to generate our own channel_update and channel_announcement messages. Signed-off-by: Rusty Russell --- lightningd/Makefile | 1 + lightningd/gossip_generation.c | 207 +++++++++++++++++++++++++++++++++ lightningd/gossip_generation.h | 64 ++++++++++ 3 files changed, 272 insertions(+) create mode 100644 lightningd/gossip_generation.c create mode 100644 lightningd/gossip_generation.h diff --git a/lightningd/Makefile b/lightningd/Makefile index 4126c0dc7..b320fef01 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -15,6 +15,7 @@ LIGHTNINGD_SRC := \ lightningd/feerate.c \ lightningd/forwards.c \ lightningd/gossip_control.c \ + lightningd/gossip_generation.c \ lightningd/hsm_control.c \ lightningd/htlc_end.c \ lightningd/htlc_set.c \ diff --git a/lightningd/gossip_generation.c b/lightningd/gossip_generation.c new file mode 100644 index 000000000..ef9aee72a --- /dev/null +++ b/lightningd/gossip_generation.c @@ -0,0 +1,207 @@ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Once we know which way nodes go, it's easy to construct */ +static u8 *create_channel_announcement_dir(const tal_t *ctx, + const u8 *features, + struct short_channel_id scid, + const secp256k1_ecdsa_signature node_signature[NUM_SIDES], + const secp256k1_ecdsa_signature bitcoin_signature[NUM_SIDES], + const struct node_id node_id[NUM_SIDES], + const struct pubkey funding_pubkey[NUM_SIDES]) +{ + enum side first, second; + + if (node_id_cmp(&node_id[LOCAL], &node_id[REMOTE]) < 0) + first = LOCAL; + else + first = REMOTE; + second = !first; + + return towire_channel_announcement(ctx, + &node_signature[first], + &node_signature[second], + &bitcoin_signature[first], + &bitcoin_signature[second], + features, + &chainparams->genesis_blockhash, + &scid, + &node_id[first], + &node_id[second], + &funding_pubkey[first], + &funding_pubkey[second]); +} + +static void copysig_or_zero(secp256k1_ecdsa_signature *dst, + const secp256k1_ecdsa_signature *src) +{ + if (!src) + memset(dst, 0, sizeof(*dst)); + else + *dst = *src; +} + +u8 *create_channel_announcement(const tal_t *ctx, + const struct channel *channel, + const secp256k1_ecdsa_signature *local_node_signature, + const secp256k1_ecdsa_signature *local_bitcoin_signature, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature) +{ + secp256k1_ecdsa_signature node_signature[NUM_SIDES], bitcoin_signature[NUM_SIDES]; + struct node_id node_id[NUM_SIDES]; + struct pubkey funding_pubkey[NUM_SIDES]; + u8 *features; + + features = get_agreed_channelfeatures(tmpctx, channel->peer->ld->our_features, + channel->peer->their_features); + + copysig_or_zero(&bitcoin_signature[LOCAL], local_bitcoin_signature); + copysig_or_zero(&bitcoin_signature[REMOTE], remote_bitcoin_signature); + copysig_or_zero(&node_signature[LOCAL], local_node_signature); + copysig_or_zero(&node_signature[REMOTE], remote_node_signature); + node_id[LOCAL] = channel->peer->ld->id; + node_id[REMOTE] = channel->peer->id; + funding_pubkey[LOCAL] = channel->local_funding_pubkey; + funding_pubkey[REMOTE] = channel->channel_info.remote_fundingkey; + return create_channel_announcement_dir(ctx, features, *channel->scid, + node_signature, bitcoin_signature, node_id, funding_pubkey); +} + +u8 *unsigned_channel_update(const tal_t *ctx, + const struct channel *channel, + const struct short_channel_id *scid, + const u32 *old_timestamp, + bool forwardable, + bool enabled) +{ + struct lightningd *ld = channel->peer->ld; + secp256k1_ecdsa_signature dummy_sig; + u8 message_flags, channel_flags; + u32 timestamp; + + /* hsmd fills this in */ + 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 = node_id_idx(&channel->peer->ld->id, + &channel->peer->id); + if (!enabled) + channel_flags |= ROUTING_FLAGS_DISABLED; + + /* BOLT #7: + * + * The `message_flags` bitfield is used to provide additional details + * about the message: + * + * | Bit Position | Name | + * | ------------- | ---------------| + * | 0 | `must_be_one` | + * | 1 | `dont_forward` | + */ + message_flags = 1; + if (!forwardable) + message_flags |= ROUTING_OPT_DONT_FORWARD; + + /* Make sure timestamp changes! */ + timestamp = time_now().ts.tv_sec; + if (old_timestamp && timestamp <= *old_timestamp) + timestamp = *old_timestamp + 1; + + return towire_channel_update(ctx, + &dummy_sig, + &chainparams->genesis_blockhash, + scid, + timestamp, + message_flags, + channel_flags, + ld->config.cltv_expiry_delta, + channel->htlc_minimum_msat, + channel->feerate_base, + channel->feerate_ppm, + channel->htlc_maximum_msat); +} + +/* 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); +} + +bool channel_update_same(const u8 *cupdate1, const u8 *cupdate2) +{ + const u8 *parts1[2], *parts2[2]; + size_t sizes1[2], sizes2[2]; + + get_cupdate_parts(cupdate1, parts1, sizes1); + get_cupdate_parts(cupdate2, parts2, sizes2); + + return memeq(parts1[0], sizes1[0], parts2[0], sizes2[0]) + && memeq(parts1[1], sizes1[1], parts2[1], sizes2[1]); +} + +bool channel_update_details(const u8 *channel_update, + u32 *timestamp, + bool *enabled) +{ + u16 cltv_expiry_delta; + struct amount_msat htlc_minimum, htlc_maximum; + u32 fee_base_msat, fee_proportional_millionths, tstamp; + u8 message_flags, channel_flags; + secp256k1_ecdsa_signature signature; + struct bitcoin_blkid chain_hash; + struct short_channel_id short_channel_id; + + if (!fromwire_channel_update(channel_update, + &signature, &chain_hash, + &short_channel_id, &tstamp, + &message_flags, &channel_flags, + &cltv_expiry_delta, + &htlc_minimum, + &fee_base_msat, + &fee_proportional_millionths, + &htlc_maximum)) + return false; + + if (timestamp) + *timestamp = tstamp; + if (enabled) + *enabled = !(channel_flags & ROUTING_FLAGS_DISABLED); + return true; +} diff --git a/lightningd/gossip_generation.h b/lightningd/gossip_generation.h new file mode 100644 index 000000000..675143a8d --- /dev/null +++ b/lightningd/gossip_generation.h @@ -0,0 +1,64 @@ +#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H +#define LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H +#include "config.h" +#include +#include + +struct channel; + +/** + * create_channel_announcement: create a channel_announcement message + * @ctx: the tal context to allocate return from + * @channel: the channel to announce + * @local_node_signature: optional local node signature + * @local_bitcoin_signature: optional local node signature + * @remote_node_signature: optional peer node signature + * @remote_bitcoin_signature: optional peer node signature + * + * The signatures are optional in case you're creating it to sign (or + * validate). + */ +u8 *create_channel_announcement(const tal_t *ctx, + const struct channel *channel, + const secp256k1_ecdsa_signature *local_node_signature, + const secp256k1_ecdsa_signature *local_bitcoin_signature, + const secp256k1_ecdsa_signature *remote_node_signature, + const secp256k1_ecdsa_signature *remote_bitcoin_signature); + +/** + * unsigned_channel_update: create a channel_update message with zeroed sig + * @ctx: the tal context to allocate return from + * @channel: the channel to announce + * @scid: the short_channel_id to sign + * @old_timestamp: optional timestamp of previous channel_update to replace. + * @forwardable: is this channel_update non-public? + * @enabled: sets channel_update's disabled flag + */ +u8 *unsigned_channel_update(const tal_t *ctx, + const struct channel *channel, + const struct short_channel_id *scid, + const u32 *old_timestamp, + bool forwardable, + bool enabled); + +/** + * channel_update_same: are these two channel updates the same? + * + * Ignoring timestamp and signatures. Basically, is it redundant? + */ +bool channel_update_same(const u8 *cupdate1, const u8 *cupdate2); + +/** + * channel_update_details: extract timestamp and/or enabled flag. + * @channel_update: the channel update, or NULL. + * @timestamp: where to extract the timestamp, or NULL. + * @enabled: where to extract the enabled flag, or NULL. + * + * Returns false (and doesn't touch @timestamp or @enabled) if + * channel_update NULL or invalid. + */ +bool channel_update_details(const u8 *channel_update, + u32 *timestamp, + bool *enabled); + +#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H */