Skip to content

Commit

Permalink
lightningd: add routines to generate node_announcement.
Browse files Browse the repository at this point in the history
This is currently still done in gossipd, but we should generate it.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Jan 31, 2024
1 parent 3508331 commit 48b9b6a
Show file tree
Hide file tree
Showing 8 changed files with 278 additions and 0 deletions.
65 changes: 65 additions & 0 deletions lightningd/channel_gossip.c
Original file line number Diff line number Diff line change
Expand Up @@ -982,3 +982,68 @@ const struct peer_update *channel_gossip_get_remote_update(const struct channel
return NULL;
return cg->peer_update;
}

static bool has_announced_channels(struct lightningd *ld)
{
struct peer *peer;
struct peer_node_id_map_iter it;

for (peer = peer_node_id_map_first(ld->peers, &it);
peer;
peer = peer_node_id_map_next(ld->peers, &it)) {
struct channel *channel;
list_for_each(&peer->channels, channel, list) {
/* Ignore unsaved channels */
if (!channel->channel_gossip)
continue;
if (channel->channel_gossip->state == CGOSSIP_ANNOUNCED)
return true;
}
}
return false;
}

static void node_announce_addgossip_reply(struct subd *gossipd,
const u8 *reply,
const int *fds UNUSED,
void *unused)
{
char *err;

if (!fromwire_gossipd_addgossip_reply(reply, reply, &err))
fatal("Reading node_announce_addgossip_reply: %s",
tal_hex(tmpctx, reply));

if (strlen(err))
log_broken(gossipd->ld->log,
"gossipd rejected our node announcement: %s", err);
}

void channel_gossip_node_announce(struct lightningd *ld)
{
u8 *nannounce;
const u8 *msg;
secp256k1_ecdsa_signature sig;

/* Everyone will ignore our node_announcement unless we have
* announced a channel. */
if (!has_announced_channels(ld))
return;

nannounce = unsigned_node_announcement(tmpctx, ld);

/* Ask hsmd to sign it (synchronous) */
msg = hsm_sync_req(tmpctx, ld,
take(towire_hsmd_node_announcement_sig_req(NULL,
nannounce)));
if (!fromwire_hsmd_node_announcement_sig_reply(msg, &sig))
fatal("Reading hsmd_node_announcement_sig_reply: %s",
tal_hex(tmpctx, msg));

add_node_announcement_sig(nannounce, &sig);

/* Tell gossipd. */
subd_req(ld->gossip, ld->gossip,
take(towire_gossipd_addgossip(NULL, nannounce)),
-1, 0, node_announce_addgossip_reply, NULL);
}
3 changes: 3 additions & 0 deletions lightningd/channel_gossip.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ void channel_gossip_got_announcement_sigs(struct channel *channel,
const secp256k1_ecdsa_signature *node_sig,
const secp256k1_ecdsa_signature *bitcoin_sig);

/* If node_announcement has changed, send a new one. */
void channel_gossip_node_announce(struct lightningd *ld);

/* Gossipd told us about a channel update on one of our channels (on loading) */
void channel_gossip_update_from_gossipd(struct channel *channel,
const u8 *channel_update TAKES);
Expand Down
5 changes: 5 additions & 0 deletions lightningd/gossip_control.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,11 @@ static struct command_result *json_setleaserates(struct command *cmd,
if (command_check_only(cmd))
return command_check_done(cmd);

/* Save them for node_announcement generation */
cmd->ld->lease_rates = tal_free(cmd->ld->lease_rates);
if (!lease_rates_empty(rates))
cmd->ld->lease_rates = tal_steal(cmd->ld, rates);

/* Call gossipd, let them know we've got new rates */
subd_send_msg(cmd->ld->gossip,
take(towire_gossipd_new_lease_rates(NULL, rates)));
Expand Down
166 changes: 166 additions & 0 deletions lightningd/gossip_generation.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "config.h"
#include <ccan/cast/cast.h>
#include <ccan/mem/mem.h>
#include <common/features.h>
#include <common/htlc.h>
Expand Down Expand Up @@ -239,3 +240,168 @@ const char *check_announce_sigs(const struct channel *channel,

return NULL;
}

/* 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 nann1 same as nann2 (not sigs and timestamps)? */
bool node_announcement_same(const u8 *nann1, const u8 *nann2)
{
const u8 *parts1[3], *parts2[3];
size_t sizes1[3], sizes2[3];

get_nannounce_parts(nann1, parts1, sizes1);
get_nannounce_parts(nann2, parts2, sizes2);

return memeq(parts1[0], sizes1[0], parts2[0], sizes2[0])
&& memeq(parts1[1], sizes1[1], parts2[1], sizes2[1])
&& memeq(parts1[2], sizes1[2], parts2[2], sizes2[2]);
}

static u8 *create_nannounce(const tal_t *ctx,
struct lightningd *ld,
const secp256k1_ecdsa_signature *sig,
const struct wireaddr *addrs,
u32 timestamp,
const struct lease_rates *rates)
{
u8 *addresses = tal_arr(tmpctx, u8, 0);
u8 *announcement;
struct tlv_node_ann_tlvs *na_tlv;

for (size_t i = 0; i < tal_count(addrs); i++)
towire_wireaddr(&addresses, &addrs[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,
ld->our_features->bits[NODE_ANNOUNCE_FEATURE],
timestamp,
&ld->id, ld->rgb, ld->alias,
addresses,
na_tlv);
return announcement;
}

/* Return an array of wireaddr to announce */
static const struct wireaddr *gather_addresses(const tal_t *ctx,
struct lightningd *ld)
{
struct wireaddr *addrs;

/* Note: If no announceable, tal_dup_talarr returns NULL! */
addrs = tal_dup_talarr(ctx, struct wireaddr, ld->announceable);
if (!addrs)
addrs = tal_arr(ctx, struct wireaddr, 0);

/* Add discovered IPs v4/v6 verified by peer `remote_addr` feature. */
/* Only do that if we don't have any addresses announced or
* `config.ip_discovery` is explicitly enabled. */
switch (ld->config.ip_discovery) {
case OPT_AUTOBOOL_FALSE:
return addrs;
case OPT_AUTOBOOL_TRUE:
break;
case OPT_AUTOBOOL_AUTO:
if (tal_count(addrs) != 0)
return addrs;
break;
}

if (ld->discovered_ip_v4)
tal_arr_expand(&addrs, *ld->discovered_ip_v4);
if (ld->discovered_ip_v6)
tal_arr_expand(&addrs, *ld->discovered_ip_v6);

return addrs;
}

u8 *unsigned_node_announcement(const tal_t *ctx,
struct lightningd *ld)
{
secp256k1_ecdsa_signature sig;
const struct wireaddr *addrs;

addrs = gather_addresses(tmpctx, ld);

memset(&sig, 0, sizeof(sig));
return create_nannounce(tmpctx, ld, &sig,
addrs, time_now().ts.tv_sec,
ld->lease_rates);
}

void add_node_announcement_sig(u8 *nannounce,
const secp256k1_ecdsa_signature *sig)
{
u8 compact[64];

secp256k1_ecdsa_signature_serialize_compact(secp256k1_ctx, compact, sig);

/* BOLT #7:
*
* 1. type: 257 (`node_announcement`)
* 2. data:
* * [`signature`:`signature`]
*/
/* First two bytes are type */
assert(tal_count(nannounce) > 2 + sizeof(compact));
memcpy(nannounce + 2, compact, sizeof(compact));
}
22 changes: 22 additions & 0 deletions lightningd/gossip_generation.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,26 @@ const char *check_announce_sigs(const struct channel *channel,
const secp256k1_ecdsa_signature *remote_node_signature,
const secp256k1_ecdsa_signature *remote_bitcoin_signature);

/**
* unsigned_node_announcement: create a current unsigned node announcement.
* @ctx: the context to allocate return from
* @ld: the lightningd struct.
*/
u8 *unsigned_node_announcement(const tal_t *ctx, struct lightningd *ld);

/**
* add_node_announcement_sig: apply the signature to the node announcement
* @nannounce: the (unsigned) node announcement
* @sig: the signature (from hsm)
*/
void add_node_announcement_sig(u8 *nannounce,
const secp256k1_ecdsa_signature *sig);

/**
* node_announcement_same: are these two node_announcements the same?
*
* Ignoring timestamp and signatures. Basically, is it redundant?
*/
bool node_announcement_same(const u8 *nann1, const u8 *nann2);

#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_GENERATION_H */
1 change: 1 addition & 0 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
* so we disable this by default for now. */
ld->announce_dns = false;

ld->lease_rates = NULL;
ld->remote_addr_v4 = NULL;
ld->remote_addr_v6 = NULL;
ld->discovered_ip_v4 = NULL;
Expand Down
3 changes: 3 additions & 0 deletions lightningd/lightningd.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ struct lightningd {
struct wireaddr_internal *binding;
struct wireaddr *announceable;

/* Lease rates to advertize, set by json_setleaserates */
struct lease_rates *lease_rates;

/* unverified remote_addr as reported by recent peers */
struct wireaddr *remote_addr_v4;
struct wireaddr *remote_addr_v6;
Expand Down
13 changes: 13 additions & 0 deletions wallet/test/run-wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ static void test_error(struct lightningd *ld, bool fatal, const char *fmt, va_li
#include <stdio.h>

/* AUTOGENERATED MOCKS START */
/* Generated stub for add_node_announcement_sig */
void add_node_announcement_sig(u8 *nannounce UNNEEDED,
const secp256k1_ecdsa_signature *sig UNNEEDED)
{ fprintf(stderr, "add_node_announcement_sig called!\n"); abort(); }
/* Generated stub for bigsize_put */
size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
{ fprintf(stderr, "bigsize_put called!\n"); abort(); }
Expand Down Expand Up @@ -311,6 +315,9 @@ bool fromwire_hsmd_init_reply_v4(const tal_t *ctx UNNEEDED, const void *p UNNEED
/* Generated stub for fromwire_hsmd_new_channel_reply */
bool fromwire_hsmd_new_channel_reply(const void *p UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_new_channel_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_node_announcement_sig_reply */
bool fromwire_hsmd_node_announcement_sig_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_node_announcement_sig_reply called!\n"); abort(); }
/* Generated stub for fromwire_hsmd_sign_any_cannouncement_reply */
bool fromwire_hsmd_sign_any_cannouncement_reply(const void *p UNNEEDED, secp256k1_ecdsa_signature *node_signature UNNEEDED, secp256k1_ecdsa_signature *bitcoin_signature UNNEEDED)
{ fprintf(stderr, "fromwire_hsmd_sign_any_cannouncement_reply called!\n"); abort(); }
Expand Down Expand Up @@ -1082,6 +1089,9 @@ u8 *towire_hsmd_init(const tal_t *ctx UNNEEDED, const struct bip32_key_version *
/* Generated stub for towire_hsmd_new_channel */
u8 *towire_hsmd_new_channel(const tal_t *ctx UNNEEDED, const struct node_id *id UNNEEDED, u64 dbid UNNEEDED)
{ fprintf(stderr, "towire_hsmd_new_channel called!\n"); abort(); }
/* Generated stub for towire_hsmd_node_announcement_sig_req */
u8 *towire_hsmd_node_announcement_sig_req(const tal_t *ctx UNNEEDED, const u8 *announcement UNNEEDED)
{ fprintf(stderr, "towire_hsmd_node_announcement_sig_req called!\n"); abort(); }
/* Generated stub for towire_hsmd_sign_any_cannouncement_req */
u8 *towire_hsmd_sign_any_cannouncement_req(const tal_t *ctx UNNEEDED, const u8 *ca UNNEEDED, const struct node_id *peerid UNNEEDED, u64 channel_dbid UNNEEDED)
{ fprintf(stderr, "towire_hsmd_sign_any_cannouncement_req called!\n"); abort(); }
Expand Down Expand Up @@ -1160,6 +1170,9 @@ u8 *unsigned_channel_update(const tal_t *ctx UNNEEDED,
bool forwardable UNNEEDED,
bool enabled UNNEEDED)
{ fprintf(stderr, "unsigned_channel_update called!\n"); abort(); }
/* Generated stub for unsigned_node_announcement */
u8 *unsigned_node_announcement(const tal_t *ctx UNNEEDED, struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "unsigned_node_announcement called!\n"); abort(); }
/* Generated stub for unwrap_onionreply */
u8 *unwrap_onionreply(const tal_t *ctx UNNEEDED,
const struct secret *shared_secrets UNNEEDED,
Expand Down

0 comments on commit 48b9b6a

Please sign in to comment.