connectd: do response to gossip queries, don't hand them to gossipd.

This basically means moving the code from gossipd to connectd to handle
these queries.

This will get connectd have finer control over ratelimiting them.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-07-09 22:45:29 +09:30
parent 531845971c
commit 4a78d17748
18 changed files with 1088 additions and 1020 deletions

View File

@ -37,6 +37,21 @@
*/
#define ANNOUNCE_MIN_DEPTH 6
/* BOLT #7:
*
* `query_option_flags` is a bitfield represented as a minimally-encoded bigsize.
* Bits have the following meaning:
*
* | Bit Position | Meaning |
* | ------------- | ----------------------- |
* | 0 | Sender wants timestamps |
* | 1 | Sender wants checksums |
*/
enum query_option_flags {
QUERY_ADD_TIMESTAMPS = 0x1,
QUERY_ADD_CHECKSUMS = 0x2,
};
/* Gossip timing constants. These can be overridden using --developer
* with --dev-fast-gossip */
#define DEV_FAST_GOSSIP(dev_fast_gossip_flag, fast, normal) \

View File

@ -7,6 +7,7 @@ CONNECTD_HEADERS := connectd/connectd_wiregen.h \
connectd/handshake.h \
connectd/gossip_store.h \
connectd/gossip_rcvd_filter.h \
connectd/queries.h \
connectd/multiplex.h \
connectd/netaddress.h \
connectd/onion_message.h \
@ -50,6 +51,7 @@ CONNECTD_COMMON_OBJS := \
common/cryptomsg.o \
common/daemon.o \
common/daemon_conn.o \
common/decode_array.o \
common/derive_basepoints.o \
common/dev_disconnect.o \
common/ecdh_hsmd.o \

View File

@ -37,6 +37,7 @@
#include <connectd/netaddress.h>
#include <connectd/onion_message.h>
#include <connectd/peer_exchange_initmsg.h>
#include <connectd/queries.h>
#include <connectd/tor.h>
#include <connectd/tor_autoservice.h>
#include <errno.h>
@ -173,6 +174,11 @@ static struct peer *new_peer(struct daemon *daemon,
peer->prio = prio;
peer->dev_writes_enabled = NULL;
peer->dev_read_enabled = true;
peer->scid_queries = NULL;
peer->scid_query_flags = NULL;
peer->scid_query_idx = 0;
peer->scid_query_nodes = NULL;
peer->scid_query_nodes_idx = 0;
peer->to_peer = conn;
@ -2192,6 +2198,12 @@ static struct io_plan *recv_req(struct io_conn *conn,
goto out;
}
/* Fall thru */
case WIRE_CONNECTD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
if (daemon->developer) {
dev_set_max_scids_encode_size(daemon, msg);
goto out;
}
/* Fall thru */
/* We send these, we don't receive them */
case WIRE_CONNECTD_INIT_REPLY:
case WIRE_CONNECTD_ACTIVATE_REPLY:

View File

@ -5,6 +5,7 @@
#include <ccan/crypto/siphash24/siphash24.h>
#include <ccan/htable/htable_type.h>
#include <ccan/timer/timer.h>
#include <common/bigsize.h>
#include <common/channel_id.h>
#include <common/crypto_state.h>
#include <common/node_id.h>
@ -110,6 +111,15 @@ struct peer {
bool dev_read_enabled;
/* If non-NULL, this counts down; 0 means disable */
u32 *dev_writes_enabled;
/* Are there outstanding responses for queries on short_channel_ids? */
const struct short_channel_id *scid_queries;
const bigsize_t *scid_query_flags;
size_t scid_query_idx;
/* Are there outstanding node_announcements from scid_queries? */
struct node_id *scid_query_nodes;
size_t scid_query_nodes_idx;
};
/*~ The HTABLE_DEFINE_TYPE() macro needs a keyof() function to extract the key:

View File

@ -168,3 +168,7 @@ msgtype,connectd_dev_suppress_gossip,2032
# master -> connect: waste all your fds.
msgtype,connectd_dev_exhaust_fds,2036
# master -> connect: set artificial maximum reply_channel_range size.
msgtype,connectd_dev_set_max_scids_encode_size,2035
msgdata,connectd_dev_set_max_scids_encode_size,max,u32,

1 #include <bitcoin/block.h>
168
169
170
171
172
173
174

View File

@ -25,6 +25,7 @@
#include <connectd/gossip_store.h>
#include <connectd/multiplex.h>
#include <connectd/onion_message.h>
#include <connectd/queries.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
@ -731,6 +732,12 @@ static bool handle_message_locally(struct peer *peer, const u8 *msg)
status_peer_io(LOG_IO_IN, &peer->id, msg);
handle_onion_message(peer->daemon, peer, msg);
return true;
} else if (type == WIRE_QUERY_CHANNEL_RANGE) {
handle_query_channel_range(peer, msg);
return true;
} else if (type == WIRE_QUERY_SHORT_CHANNEL_IDS) {
handle_query_short_channel_ids(peer, msg);
return true;
} else if (handle_custommsg(peer->daemon, peer, msg)) {
return true;
}
@ -933,8 +940,14 @@ static struct io_plan *write_to_peer(struct io_conn *peer_conn,
return io_sock_shutdown(peer_conn);
/* If they want us to send gossip, do so now. */
if (!peer->draining)
msg = maybe_from_gossip_store(NULL, peer);
if (!peer->draining) {
/* FIXME: make it return the message? */
if (maybe_send_query_responses(peer, get_gossmap(peer->daemon))) {
msg = msg_dequeue(peer->peer_outq);
} else {
msg = maybe_from_gossip_store(NULL, peer);
}
}
if (!msg) {
/* Tell them to read again, */
io_wake(&peer->subds);

765
connectd/queries.c Normal file
View File

@ -0,0 +1,765 @@
/* Routines to handle gossip query messages */
#include "config.h"
#include <bitcoin/chainparams.h>
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/crc32c/crc32c.h>
#include <common/daemon_conn.h>
#include <common/decode_array.h>
#include <common/gossmap.h>
#include <common/status.h>
#include <common/wire_error.h>
#include <connectd/connectd.h>
#include <connectd/connectd_wiregen.h>
#include <connectd/multiplex.h>
#include <connectd/queries.h>
#include <wire/peer_wire.h>
static u32 dev_max_encoding_bytes = -1U;
/* BOLT #7:
*
* There are several messages which contain a long array of
* `short_channel_id`s (called `encoded_short_ids`) so we include an encoding
* byte which allows for different encoding schemes to be defined in the future
*/
static u8 *encoding_start(const tal_t *ctx, bool prepend_encoding)
{
u8 *ret;
if (prepend_encoding) {
ret = tal_arr(ctx, u8, 1);
ret[0] = ARR_UNCOMPRESSED;
} else
ret = tal_arr(ctx, u8, 0);
return ret;
}
/* Marshal a single short_channel_id */
static void encoding_add_short_channel_id(u8 **encoded,
struct short_channel_id scid)
{
towire_short_channel_id(encoded, scid);
}
/* Marshal a single channel_update_timestamps */
static void encoding_add_timestamps(u8 **encoded,
const struct channel_update_timestamps *ts)
{
towire_channel_update_timestamps(encoded, ts);
}
static bool encoding_end(const u8 *encoded, size_t max_bytes)
{
if (tal_count(encoded) > dev_max_encoding_bytes)
return false;
return tal_count(encoded) <= max_bytes;
}
/* Convenience function to send warning to a peer */
static void warning_to_peer(struct peer *peer, const char *fmt, ...)
{
va_list ap;
u8 *msg;
va_start(ap, fmt);
msg = towire_warningfmtv(NULL, NULL, fmt, ap);
va_end(ap);
inject_peer_msg(peer, take(msg));
}
/*~ Arbitrary ordering function of pubkeys.
*
* Note that we could use memcmp() here: even if they had somehow different
* bitwise representations for the same key, we copied them all from struct
* node which should make them unique. Even if not (say, a node vanished
* and reappeared) we'd just end up sending two node_announcement for the
* same node.
*/
static int pubkey_order(const struct node_id *k1,
const struct node_id *k2,
void *unused UNUSED)
{
return node_id_cmp(k1, k2);
}
static void uniquify_node_ids(struct node_id **ids)
{
size_t dst, src;
/* BOLT #7:
* - SHOULD avoid sending duplicate `node_announcements` in
* response to a single `query_short_channel_ids`.
*/
/* ccan/asort is a typesafe qsort wrapper: like most ccan modules
* it eschews exposing 'void *' pointers and ensures that the
* callback function and its arguments match types correctly. */
asort(*ids, tal_count(*ids), pubkey_order, NULL);
/* Compact the array */
for (dst = 0, src = 0; src < tal_count(*ids); src++) {
if (dst && node_id_eq(&(*ids)[dst-1], &(*ids)[src]))
continue;
(*ids)[dst++] = (*ids)[src];
}
/* And trim to length, so tal_count() gives correct answer. */
tal_resize(ids, dst);
}
/* We are fairly careful to avoid the peer DoSing us with channel queries:
* this routine sends information about a single short_channel_id, unless
* it's finished all of them. */
bool maybe_send_query_responses(struct peer *peer, struct gossmap *gossmap)
{
size_t i, num;
bool sent = false;
const u8 *msg;
/* BOLT #7:
*
* - MUST respond to each known `short_channel_id`:
*/
/* Search for next short_channel_id we know about. */
num = tal_count(peer->scid_queries);
for (i = peer->scid_query_idx; !sent && i < num; i++) {
struct gossmap_chan *chan;
struct gossmap_node *node;
struct node_id node_id;
chan = gossmap_find_chan(gossmap, &peer->scid_queries[i]);
if (!chan)
continue;
/* BOLT #7:
* - if bit 0 of `query_flag` is set:
* - MUST reply with a `channel_announcement`
*/
if (peer->scid_query_flags[i] & SCID_QF_ANNOUNCE) {
msg = gossmap_chan_get_announce(NULL, gossmap, chan);
inject_peer_msg(peer, take(msg));
sent = true;
}
/* BOLT #7:
* - if bit 1 of `query_flag` is set and it has received a
* `channel_update` from `node_id_1`:
* - MUST reply with the latest `channel_update` for
* `node_id_1`
* - if bit 2 of `query_flag` is set and it has received a
* `channel_update` from `node_id_2`:
* - MUST reply with the latest `channel_update` for
* `node_id_2` */
if ((peer->scid_query_flags[i] & SCID_QF_UPDATE1)
&& gossmap_chan_set(chan, 0)) {
msg = gossmap_chan_get_update(NULL, gossmap, chan, 0);
inject_peer_msg(peer, take(msg));
sent = true;
}
if ((peer->scid_query_flags[i] & SCID_QF_UPDATE2)
&& gossmap_chan_set(chan, 1)) {
msg = gossmap_chan_get_update(NULL, gossmap, chan, 1);
inject_peer_msg(peer, take(msg));
sent = true;
}
/* BOLT #7:
* - if bit 3 of `query_flag` is set and it has received
* a `node_announcement` from `node_id_1`:
* - MUST reply with the latest `node_announcement` for
* `node_id_1`
* - if bit 4 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_2`:
* - MUST reply with the latest `node_announcement` for
* `node_id_2` */
/* Save node ids for later transmission of node_announcement */
if (peer->scid_query_flags[i] & SCID_QF_NODE1) {
node = gossmap_nth_node(gossmap, chan, 0);
gossmap_node_get_id(gossmap, node, &node_id);
tal_arr_expand(&peer->scid_query_nodes, node_id);
}
if (peer->scid_query_flags[i] & SCID_QF_NODE2) {
node = gossmap_nth_node(gossmap, chan, 1);
gossmap_node_get_id(gossmap, node, &node_id);
tal_arr_expand(&peer->scid_query_nodes, node_id);
}
}
/* Just finished channels? Remove duplicate nodes. */
if (peer->scid_query_idx != num && i == num)
uniquify_node_ids(&peer->scid_query_nodes);
/* Update index for next time we're called. */
peer->scid_query_idx = i;
/* BOLT #7:
*
* - if the incoming message does not include `encoded_query_flags`:
* ...
* - MUST follow with any `node_announcement`s for each
* `channel_announcement`
* - otherwise:
* ...
* - if bit 3 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_1`:
* - MUST reply with the latest `node_announcement` for
* `node_id_1`
* - if bit 4 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_2`:
* - MUST reply with the latest `node_announcement` for
* `node_id_2`
*/
/* If we haven't sent anything above, we look for the next
* node_announcement to send. */
num = tal_count(peer->scid_query_nodes);
for (i = peer->scid_query_nodes_idx; !sent && i < num; i++) {
const struct gossmap_node *n;
/* Not every node announces itself (we know it exists because
* of a channel_announcement, however) */
n = gossmap_find_node(gossmap, &peer->scid_query_nodes[i]);
if (!n || !gossmap_node_announced(n))
continue;
msg = gossmap_node_get_announce(NULL, gossmap, n);
inject_peer_msg(peer, take(msg));
sent = true;
}
peer->scid_query_nodes_idx = i;
/* All finished? */
if (peer->scid_queries
&& peer->scid_query_idx == tal_count(peer->scid_queries)
&& peer->scid_query_nodes_idx == num) {
/* BOLT #7:
*
* - MUST follow these responses with
* `reply_short_channel_ids_end`.
* - if does not maintain up-to-date channel information for
* `chain_hash`:
* - MUST set `full_information` to 0.
* - otherwise:
* - SHOULD set `full_information` to 1.
*/
/* FIXME: We consider ourselves to have complete knowledge. */
u8 *end = towire_reply_short_channel_ids_end(peer,
&chainparams->genesis_blockhash,
true);
inject_peer_msg(peer, take(end));
/* We're done! Clean up so we simply pass-through next time. */
peer->scid_queries = tal_free(peer->scid_queries);
peer->scid_query_flags = tal_free(peer->scid_query_flags);
peer->scid_query_idx = 0;
peer->scid_query_nodes = tal_free(peer->scid_query_nodes);
peer->scid_query_nodes_idx = 0;
}
return sent;
}
/* The peer can ask about an array of short channel ids: we don't assemble the
* reply immediately but process them one at a time in dump_gossip which is
* called when there's nothing more important to send. */
void handle_query_short_channel_ids(struct peer *peer, const u8 *msg)
{
struct bitcoin_blkid chain;
u8 *encoded;
struct short_channel_id *scids;
bigsize_t *flags;
struct tlv_query_short_channel_ids_tlvs *tlvs;
if (!fromwire_query_short_channel_ids(tmpctx, msg, &chain, &encoded,
&tlvs)) {
warning_to_peer(peer,
"Bad query_short_channel_ids w/tlvs %s",
tal_hex(tmpctx, msg));
return;
}
if (tlvs->query_flags) {
/* BOLT #7:
*
* The receiver:
*...
* - if the incoming message includes
* `query_short_channel_ids_tlvs`:
* - if `encoding_type` is not a known encoding type:
* - MAY send a `warning`.
* - MAY close the connection.
*/
flags = decode_scid_query_flags(tmpctx, tlvs->query_flags);
if (!flags) {
warning_to_peer(peer,
"Bad query_short_channel_ids query_flags %s",
tal_hex(tmpctx, msg));
return;
}
} else
flags = NULL;
/* BOLT #7
*
* The receiver:
* ...
* - if does not maintain up-to-date channel information for `chain_hash`:
* - MUST set `complete` to 0.
*/
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain)) {
status_peer_debug(&peer->id,
"sent query_short_channel_ids chainhash %s",
fmt_bitcoin_blkid(tmpctx, &chain));
inject_peer_msg(peer,
take(towire_reply_short_channel_ids_end(NULL, &chain, 0)));
}
/* BOLT #7:
*
* - if it has not sent `reply_short_channel_ids_end` to a
* previously received `query_short_channel_ids` from this
* sender:
* - MAY send a `warning`.
* - MAY close the connection.
*/
if (peer->scid_queries || peer->scid_query_nodes) {
warning_to_peer(peer, "Bad concurrent query_short_channel_ids");
return;
}
scids = decode_short_ids(tmpctx, encoded);
if (!scids) {
warning_to_peer(peer, "Bad query_short_channel_ids encoding %s",
tal_hex(tmpctx, encoded));
return;
}
/* BOLT #7:
*
* The receiver:
*...
* - if `encoded_query_flags` does not decode to exactly one flag per
* `short_channel_id`:
* - MAY send a `warning`.
* - MAY close the connection.
*/
if (!flags) {
/* Pretend they asked for everything. */
flags = tal_arr(tmpctx, bigsize_t, tal_count(scids));
memset(flags, 0xFF, tal_bytelen(flags));
} else {
if (tal_count(flags) != tal_count(scids)) {
warning_to_peer(peer,
"Bad query_short_channel_ids flags count %zu scids %zu",
tal_count(flags), tal_count(scids));
return;
}
}
/* BOLT #7:
*
* - MUST respond to each known `short_channel_id`:
*...
* - SHOULD NOT wait for the next outgoing gossip flush to send
* these.
*/
peer->scid_queries = tal_steal(peer, scids);
peer->scid_query_flags = tal_steal(peer, flags);
peer->scid_query_idx = 0;
peer->scid_query_nodes = tal_arr(peer, struct node_id, 0);
/* Notify the write loop to invoke maybe_send_query_responses */
io_wake(peer->peer_outq);
}
/*~ We can send multiple replies when the peer queries for all channels in
* a given range of blocks; each one indicates the range of blocks it covers. */
static void send_reply_channel_range(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
const struct short_channel_id *scids,
const struct channel_update_timestamps *tstamps,
const struct channel_update_checksums *csums,
size_t num_scids,
bool final)
{
/* BOLT #7:
*
* - MUST respond with one or more `reply_channel_range`:
* - MUST set with `chain_hash` equal to that of `query_channel_range`,
* - MUST limit `number_of_blocks` to the maximum number of blocks
* whose results could fit in `encoded_short_ids`
*/
u8 *encoded_scids = encoding_start(tmpctx, true);
u8 *encoded_timestamps = encoding_start(tmpctx, false);
struct tlv_reply_channel_range_tlvs *tlvs
= tlv_reply_channel_range_tlvs_new(tmpctx);
/* Encode them all */
for (size_t i = 0; i < num_scids; i++)
encoding_add_short_channel_id(&encoded_scids, scids[i]);
encoding_end(encoded_scids, tal_bytelen(encoded_scids));
if (tstamps) {
for (size_t i = 0; i < num_scids; i++)
encoding_add_timestamps(&encoded_timestamps, &tstamps[i]);
tlvs->timestamps_tlv = tal(tlvs, struct tlv_reply_channel_range_tlvs_timestamps_tlv);
tlvs->timestamps_tlv->encoding_type = ARR_UNCOMPRESSED;
encoding_end(encoded_timestamps,
tal_bytelen(encoded_timestamps));
tlvs->timestamps_tlv->encoded_timestamps
= tal_steal(tlvs, encoded_timestamps);
}
/* Must be a tal object! */
if (csums)
tlvs->checksums_tlv = tal_dup_arr(tlvs,
struct channel_update_checksums,
csums, num_scids, 0);
/* BOLT #7:
*
* - MUST set `sync_complete` to `false` if this is not the final
* `reply_channel_range`.
*/
u8 *msg = towire_reply_channel_range(NULL,
&chainparams->genesis_blockhash,
first_blocknum,
number_of_blocks,
final, encoded_scids, tlvs);
inject_peer_msg(peer, take(msg));
}
/* 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);
}
/* BOLT #7:
*
* The checksum of a `channel_update` is the CRC32C checksum as specified in
* [RFC3720](https://tools.ietf.org/html/rfc3720#appendix-B.4) of this
* `channel_update` without its `signature` and `timestamp` fields.
*/
static u32 crc32_of_update(const u8 *channel_update)
{
u32 sum;
const u8 *parts[2];
size_t sizes[ARRAY_SIZE(parts)];
get_cupdate_parts(channel_update, parts, sizes);
sum = 0;
for (size_t i = 0; i < ARRAY_SIZE(parts); i++)
sum = crc32c(sum, parts[i], sizes[i]);
return sum;
}
/* BOLT #7:
* Where:
* * `timestamp_node_id_1` is the timestamp of the `channel_update` for `node_id_1`, or 0 if there was no `channel_update` from that node.
* * `timestamp_node_id_2` is the timestamp of the `channel_update` for `node_id_2`, or 0 if there was no `channel_update` from that node.
*/
static u32 get_timestamp(struct gossmap *gossmap,
const struct gossmap_chan *chan,
int dir)
{
u32 timestamp;
if (!gossmap_chan_set(chan, dir))
return 0;
gossmap_chan_get_update_details(gossmap, chan, dir, &timestamp,
NULL, NULL, NULL, NULL, NULL, NULL);
return timestamp;
}
/* BOLT #7:
* Where:
* * `checksum_node_id_1` is the checksum of the `channel_update` for
* `node_id_1`, or 0 if there was no `channel_update` from that
* node.
* * `checksum_node_id_2` is the checksum of the `channel_update` for
* `node_id_2`, or 0 if there was no `channel_update` from that
* node.
*/
static u32 get_checksum(struct gossmap *gossmap,
const struct gossmap_chan *chan,
int dir)
{
u8 *cupdate;
cupdate = gossmap_chan_get_update(tmpctx, gossmap, chan, dir);
if (!cupdate)
return 0;
return crc32_of_update(cupdate);
}
/* FIXME: This assumes that the tlv type encodes into 1 byte! */
static size_t tlv_overhead(size_t num_entries, size_t size)
{
return 1 + bigsize_len(num_entries * size);
}
/* How many entries can I fit in a reply? */
static size_t max_entries(enum query_option_flags query_option_flags)
{
/* BOLT #7:
*
* 1. type: 264 (`reply_channel_range`)
* 2. data:
* * [`chain_hash`:`chain_hash`]
* * [`u32`:`first_blocknum`]
* * [`u32`:`number_of_blocks`]
* * [`byte`:`sync_complete`]
* * [`u16`:`len`]
* * [`len*byte`:`encoded_short_ids`]
*/
const size_t reply_overhead = 32 + 4 + 4 + 1 + 2;
size_t max_encoded_bytes = 65535 - 2 - reply_overhead;
size_t per_entry_size, max_num;
per_entry_size = sizeof(struct short_channel_id);
/* Upper bound to start. */
max_num = max_encoded_bytes / per_entry_size;
/* If we add timestamps, we need to encode tlv */
if (query_option_flags & QUERY_ADD_TIMESTAMPS) {
max_encoded_bytes -= tlv_overhead(max_num,
sizeof(struct channel_update_timestamps));
per_entry_size += sizeof(struct channel_update_timestamps);
}
if (query_option_flags & QUERY_ADD_CHECKSUMS) {
max_encoded_bytes -= tlv_overhead(max_num,
sizeof(struct channel_update_checksums));
per_entry_size += sizeof(struct channel_update_checksums);
}
if (max_encoded_bytes > dev_max_encoding_bytes)
max_encoded_bytes = dev_max_encoding_bytes;
/* Always let one through! */
if (max_encoded_bytes < per_entry_size)
max_encoded_bytes = per_entry_size;
return max_encoded_bytes / per_entry_size;
}
/* This gets all the scids they asked for, and optionally the timestamps and checksums */
static struct short_channel_id *gather_range(const tal_t *ctx,
struct daemon *daemon,
u32 first_blocknum, u32 number_of_blocks,
enum query_option_flags query_option_flags,
struct channel_update_timestamps **tstamps,
struct channel_update_checksums **csums)
{
struct short_channel_id *scids;
u32 end_block;
struct gossmap *gossmap = get_gossmap(daemon);
scids = tal_arr(ctx, struct short_channel_id, 0);
if (query_option_flags & QUERY_ADD_TIMESTAMPS)
*tstamps = tal_arr(ctx, struct channel_update_timestamps, 0);
else
*tstamps = NULL;
if (query_option_flags & QUERY_ADD_CHECKSUMS)
*csums = tal_arr(ctx, struct channel_update_checksums, 0);
else
*csums = NULL;
if (number_of_blocks == 0)
return NULL;
/* Fix up number_of_blocks to avoid overflow. */
end_block = first_blocknum + number_of_blocks - 1;
if (end_block < first_blocknum)
end_block = UINT_MAX;
/* We used to maintain a uintmap of channels by scid, but
* we no longer do, making this more expensive. But still
* not too bad, since it's usually in-mem */
for (size_t i = 0; i < gossmap_max_chan_idx(gossmap); i++) {
struct gossmap_chan *chan = gossmap_chan_byidx(gossmap, i);
struct short_channel_id scid;
if (!chan)
continue;
/* By policy, we don't give announcements here with no
* channel_updates */
if (!gossmap_chan_set(chan, 0) && !gossmap_chan_set(chan, 1)) {
continue;
}
scid = gossmap_chan_scid(gossmap, chan);
if (short_channel_id_blocknum(scid) < first_blocknum
|| short_channel_id_blocknum(scid) > end_block) {
continue;
}
tal_arr_expand(&scids, scid);
if (*tstamps) {
struct channel_update_timestamps ts;
ts.timestamp_node_id_1 = get_timestamp(gossmap, chan, 0);
ts.timestamp_node_id_2 = get_timestamp(gossmap, chan, 1);
tal_arr_expand(tstamps, ts);
}
if (*csums) {
struct channel_update_checksums cs;
cs.checksum_node_id_1 = get_checksum(gossmap, chan, 0);
cs.checksum_node_id_2 = get_checksum(gossmap, chan, 1);
tal_arr_expand(csums, cs);
}
}
return scids;
}
/*~ When we need to send an array of channels, it might go over our 64k packet
* size. But because we use compression, we can't actually tell how much
* we'll use. We pack them into the maximum amount for uncompressed, then
* compress afterwards.
*/
static void queue_channel_ranges(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
enum query_option_flags query_option_flags)
{
struct daemon *daemon = peer->daemon;
struct channel_update_timestamps *tstamps;
struct channel_update_checksums *csums;
struct short_channel_id *scids;
size_t off, limit;
scids = gather_range(tmpctx, daemon, first_blocknum, number_of_blocks,
query_option_flags, &tstamps, &csums);
limit = max_entries(query_option_flags);
off = 0;
/* We need to send an empty msg if we have nothing! */
do {
size_t n = tal_count(scids) - off;
u32 this_num_blocks;
if (n > limit) {
status_debug("reply_channel_range: splitting %zu-%zu of %zu",
off, off + limit, tal_count(scids));
n = limit;
/* ... and reduce to a block boundary. */
while (short_channel_id_blocknum(scids[off + n - 1])
== short_channel_id_blocknum(scids[off + limit])) {
/* We assume one block doesn't have limit #
* channels. If it does, we have to violate
* spec and send over multiple blocks. */
if (n == 0) {
status_broken("reply_channel_range: "
"could not fit %zu scids for %u!",
limit,
short_channel_id_blocknum(scids[off + n - 1]));
n = limit;
break;
}
n--;
}
/* Get *next* channel, add num blocks */
this_num_blocks
= short_channel_id_blocknum(scids[off + n])
- first_blocknum;
} else
/* Last one must end with correct total */
this_num_blocks = number_of_blocks;
send_reply_channel_range(peer, first_blocknum, this_num_blocks,
scids + off,
query_option_flags & QUERY_ADD_TIMESTAMPS
? tstamps + off : NULL,
query_option_flags & QUERY_ADD_CHECKSUMS
? csums + off : NULL,
n,
this_num_blocks == number_of_blocks);
first_blocknum += this_num_blocks;
number_of_blocks -= this_num_blocks;
off += n;
} while (number_of_blocks);
}
/*~ The peer can ask for all channels in a series of blocks. We reply with one
* or more messages containing the short_channel_ids. */
void handle_query_channel_range(struct peer *peer, const u8 *msg)
{
struct bitcoin_blkid chain_hash;
u32 first_blocknum, number_of_blocks;
enum query_option_flags query_option_flags;
struct tlv_query_channel_range_tlvs *tlvs;
if (!fromwire_query_channel_range(msg, msg, &chain_hash,
&first_blocknum, &number_of_blocks,
&tlvs)) {
warning_to_peer(peer,
"Bad query_channel_range w/tlvs %s",
tal_hex(tmpctx, msg));
return;
}
if (tlvs->query_option)
query_option_flags = *tlvs->query_option;
else
query_option_flags = 0;
/* BOLT #7
*
* The receiver of `query_channel_range`:
* ...
* - if does not maintain up-to-date channel information for `chain_hash`:
* - MUST set `complete` to 0.
*/
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) {
status_peer_debug(&peer->id,
"query_channel_range with chainhash %s",
fmt_bitcoin_blkid(tmpctx, &chain_hash));
u8 *end = towire_reply_channel_range(NULL, &chain_hash, first_blocknum,
number_of_blocks, false, NULL, NULL);
inject_peer_msg(peer, take(end));
return;
}
/* Fix up number_of_blocks to avoid overflow. */
if (first_blocknum + number_of_blocks < first_blocknum)
number_of_blocks = UINT_MAX - first_blocknum;
queue_channel_ranges(peer, first_blocknum, number_of_blocks,
query_option_flags);
}
/* This is a testing hack to allow us to artificially lower the maximum bytes
* of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */
void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg)
{
assert(daemon->developer);
if (!fromwire_connectd_dev_set_max_scids_encode_size(msg,
&dev_max_encoding_bytes))
master_badmsg(WIRE_CONNECTD_DEV_SET_MAX_SCIDS_ENCODE_SIZE, msg);
status_debug("Set max_scids_encode_bytes to %u", dev_max_encoding_bytes);
}

12
connectd/queries.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef LIGHTNING_CONNECTD_QUERIES_H
#define LIGHTNING_CONNECTD_QUERIES_H
#include "config.h"
/* See if there's a query to respond to, if so, do it and return true */
bool maybe_send_query_responses(struct peer *peer, struct gossmap *gossmap);
void handle_query_short_channel_ids(struct peer *peer, const u8 *msg);
void handle_query_channel_range(struct peer *peer, const u8 *msg);
void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg);
#endif /* LIGHTNING_CONNECTD_QUERIES_H */

View File

@ -0,0 +1,241 @@
#include "config.h"
int unused_main(int argc, char *argv[]);
#define main unused_main
#include "../queries.c"
#undef main
#include <common/blinding.h>
#include <common/channel_type.h>
#include <common/ecdh.h>
#include <common/json_stream.h>
#include <common/onionreply.h>
#include <common/setup.h>
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for amount_asset_is_main */
bool amount_asset_is_main(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_is_main called!\n"); abort(); }
/* Generated stub for amount_asset_to_sat */
struct amount_sat amount_asset_to_sat(struct amount_asset *asset UNNEEDED)
{ fprintf(stderr, "amount_asset_to_sat called!\n"); abort(); }
/* Generated stub for amount_feerate */
bool amount_feerate(u32 *feerate UNNEEDED, struct amount_sat fee UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_feerate called!\n"); abort(); }
/* Generated stub for amount_sat */
struct amount_sat amount_sat(u64 satoshis UNNEEDED)
{ fprintf(stderr, "amount_sat called!\n"); abort(); }
/* Generated stub for amount_sat_add */
bool amount_sat_add(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_add called!\n"); abort(); }
/* Generated stub for amount_sat_eq */
bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_eq called!\n"); abort(); }
/* Generated stub for amount_sat_greater_eq */
bool amount_sat_greater_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_greater_eq called!\n"); abort(); }
/* Generated stub for amount_sat_sub */
bool amount_sat_sub(struct amount_sat *val UNNEEDED,
struct amount_sat a UNNEEDED,
struct amount_sat b UNNEEDED)
{ fprintf(stderr, "amount_sat_sub called!\n"); abort(); }
/* Generated stub for amount_sat_to_asset */
struct amount_asset amount_sat_to_asset(struct amount_sat *sat UNNEEDED, const u8 *asset UNNEEDED)
{ fprintf(stderr, "amount_sat_to_asset called!\n"); abort(); }
/* Generated stub for amount_tx_fee */
struct amount_sat amount_tx_fee(u32 fee_per_kw UNNEEDED, size_t weight UNNEEDED)
{ fprintf(stderr, "amount_tx_fee called!\n"); abort(); }
/* Generated stub for bigsize_len */
size_t bigsize_len(bigsize_t v UNNEEDED)
{ fprintf(stderr, "bigsize_len called!\n"); abort(); }
/* Generated stub for decode_scid_query_flags */
bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED,
const struct tlv_query_short_channel_ids_tlvs_query_flags *qf UNNEEDED)
{ fprintf(stderr, "decode_scid_query_flags called!\n"); abort(); }
/* Generated stub for decode_short_ids */
struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED)
{ fprintf(stderr, "decode_short_ids called!\n"); abort(); }
/* Generated stub for fromwire */
const u8 *fromwire(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, void *copy UNNEEDED, size_t n UNNEEDED)
{ fprintf(stderr, "fromwire called!\n"); abort(); }
/* Generated stub for fromwire_bool */
bool fromwire_bool(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_bool called!\n"); abort(); }
/* Generated stub for fromwire_connectd_dev_set_max_scids_encode_size */
bool fromwire_connectd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_connectd_dev_set_max_scids_encode_size called!\n"); abort(); }
/* Generated stub for fromwire_fail */
void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_fail called!\n"); abort(); }
/* Generated stub for fromwire_query_channel_range */
bool fromwire_query_channel_range(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, u32 *first_blocknum UNNEEDED, u32 *number_of_blocks UNNEEDED, struct tlv_query_channel_range_tlvs **tlvs UNNEEDED)
{ fprintf(stderr, "fromwire_query_channel_range called!\n"); abort(); }
/* Generated stub for fromwire_query_short_channel_ids */
bool fromwire_query_short_channel_ids(const tal_t *ctx UNNEEDED, const void *p UNNEEDED, struct bitcoin_blkid *chain_hash UNNEEDED, u8 **encoded_short_ids UNNEEDED, struct tlv_query_short_channel_ids_tlvs **tlvs UNNEEDED)
{ fprintf(stderr, "fromwire_query_short_channel_ids called!\n"); abort(); }
/* Generated stub for fromwire_secp256k1_ecdsa_signature */
void fromwire_secp256k1_ecdsa_signature(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "fromwire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for fromwire_sha256 */
void fromwire_sha256(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "fromwire_sha256 called!\n"); abort(); }
/* Generated stub for fromwire_tal_arrn */
u8 *fromwire_tal_arrn(const tal_t *ctx UNNEEDED,
const u8 **cursor UNNEEDED, size_t *max UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_tal_arrn called!\n"); abort(); }
/* Generated stub for fromwire_u16 */
u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u16 called!\n"); abort(); }
/* Generated stub for fromwire_u32 */
u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); }
/* Generated stub for fromwire_u64 */
u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); }
/* Generated stub for fromwire_u8 */
u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED)
{ fprintf(stderr, "fromwire_u8 called!\n"); abort(); }
/* Generated stub for fromwire_u8_array */
void fromwire_u8_array(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "fromwire_u8_array called!\n"); abort(); }
/* Generated stub for get_gossmap */
struct gossmap *get_gossmap(struct daemon *daemon UNNEEDED)
{ fprintf(stderr, "get_gossmap called!\n"); abort(); }
/* Generated stub for gossmap_chan_byidx */
struct gossmap_chan *gossmap_chan_byidx(const struct gossmap *map UNNEEDED, u32 idx UNNEEDED)
{ fprintf(stderr, "gossmap_chan_byidx called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_announce */
u8 *gossmap_chan_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update */
u8 *gossmap_chan_get_update(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update_details */
void gossmap_chan_get_update_details(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED,
u32 *timestamp UNNEEDED,
u8 *message_flags UNNEEDED,
u8 *channel_flags UNNEEDED,
u32 *fee_base_msat UNNEEDED,
u32 *fee_proportional_millionths UNNEEDED,
struct amount_msat *htlc_minimum_msat UNNEEDED,
struct amount_msat *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update_details called!\n"); abort(); }
/* Generated stub for gossmap_chan_scid */
struct short_channel_id gossmap_chan_scid(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_scid called!\n"); abort(); }
/* Generated stub for gossmap_find_chan */
struct gossmap_chan *gossmap_find_chan(const struct gossmap *map UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "gossmap_find_chan called!\n"); abort(); }
/* Generated stub for gossmap_find_node */
struct gossmap_node *gossmap_find_node(const struct gossmap *map UNNEEDED,
const struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_find_node called!\n"); abort(); }
/* Generated stub for gossmap_max_chan_idx */
u32 gossmap_max_chan_idx(const struct gossmap *map UNNEEDED)
{ fprintf(stderr, "gossmap_max_chan_idx called!\n"); abort(); }
/* Generated stub for gossmap_node_get_announce */
u8 *gossmap_node_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_node *n UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_node_get_id */
void gossmap_node_get_id(const struct gossmap *map UNNEEDED,
const struct gossmap_node *node UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_id called!\n"); abort(); }
/* Generated stub for gossmap_nth_node */
struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int n UNNEEDED)
{ fprintf(stderr, "gossmap_nth_node called!\n"); abort(); }
/* Generated stub for inject_peer_msg */
void inject_peer_msg(struct peer *peer UNNEEDED, const u8 *msg TAKES UNNEEDED)
{ fprintf(stderr, "inject_peer_msg 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(); }
/* Generated stub for node_id_cmp */
int node_id_cmp(const struct node_id *a UNNEEDED, const struct node_id *b UNNEEDED)
{ fprintf(stderr, "node_id_cmp called!\n"); abort(); }
/* Generated stub for status_fmt */
void status_fmt(enum log_level level UNNEEDED,
const struct node_id *peer UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for tlv_reply_channel_range_tlvs_new */
struct tlv_reply_channel_range_tlvs *tlv_reply_channel_range_tlvs_new(const tal_t *ctx UNNEEDED)
{ fprintf(stderr, "tlv_reply_channel_range_tlvs_new called!\n"); abort(); }
/* Generated stub for towire */
void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED)
{ fprintf(stderr, "towire called!\n"); abort(); }
/* Generated stub for towire_bool */
void towire_bool(u8 **pptr UNNEEDED, bool v UNNEEDED)
{ fprintf(stderr, "towire_bool called!\n"); abort(); }
/* Generated stub for towire_channel_update_timestamps */
void towire_channel_update_timestamps(u8 **p UNNEEDED, const struct channel_update_timestamps *channel_update_timestamps UNNEEDED)
{ fprintf(stderr, "towire_channel_update_timestamps called!\n"); abort(); }
/* Generated stub for towire_reply_channel_range */
u8 *towire_reply_channel_range(const tal_t *ctx UNNEEDED, const struct bitcoin_blkid *chain_hash UNNEEDED, u32 first_blocknum UNNEEDED, u32 number_of_blocks UNNEEDED, u8 sync_complete UNNEEDED, const u8 *encoded_short_ids UNNEEDED, const struct tlv_reply_channel_range_tlvs *tlvs UNNEEDED)
{ fprintf(stderr, "towire_reply_channel_range called!\n"); abort(); }
/* Generated stub for towire_reply_short_channel_ids_end */
u8 *towire_reply_short_channel_ids_end(const tal_t *ctx UNNEEDED, const struct bitcoin_blkid *chain_hash UNNEEDED, u8 full_information UNNEEDED)
{ fprintf(stderr, "towire_reply_short_channel_ids_end called!\n"); abort(); }
/* Generated stub for towire_secp256k1_ecdsa_signature */
void towire_secp256k1_ecdsa_signature(u8 **pptr UNNEEDED,
const secp256k1_ecdsa_signature *signature UNNEEDED)
{ fprintf(stderr, "towire_secp256k1_ecdsa_signature called!\n"); abort(); }
/* Generated stub for towire_sha256 */
void towire_sha256(u8 **pptr UNNEEDED, const struct sha256 *sha256 UNNEEDED)
{ fprintf(stderr, "towire_sha256 called!\n"); abort(); }
/* Generated stub for towire_u16 */
void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED)
{ fprintf(stderr, "towire_u16 called!\n"); abort(); }
/* Generated stub for towire_u32 */
void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED)
{ fprintf(stderr, "towire_u32 called!\n"); abort(); }
/* Generated stub for towire_u64 */
void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED)
{ fprintf(stderr, "towire_u64 called!\n"); abort(); }
/* Generated stub for towire_u8 */
void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED)
{ fprintf(stderr, "towire_u8 called!\n"); abort(); }
/* Generated stub for towire_u8_array */
void towire_u8_array(u8 **pptr UNNEEDED, const u8 *arr UNNEEDED, size_t num UNNEEDED)
{ fprintf(stderr, "towire_u8_array called!\n"); abort(); }
/* Generated stub for towire_warningfmtv */
u8 *towire_warningfmtv(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED,
va_list ap UNNEEDED)
{ fprintf(stderr, "towire_warningfmtv called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
int main(int argc, char *argv[])
{
u8 *update;
common_setup(argv[0]);
update = tal_hexdata(NULL, "010276df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c8029328206226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100005d50f933000000900000000000000000000003e80000000a",
strlen("010276df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c8029328206226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100005d50f933000000900000000000000000000003e80000000a"));
assert(crc32_of_update(update) == 0x1112fa30);
tal_free(update);
update = tal_hexdata(NULL, "010206737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006d00000100005d50f935010000300000000000000000000000640000000b00000000000186a0",
strlen("010206737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006d00000100005d50f935010000300000000000000000000000640000000b00000000000186a0"));
assert(crc32_of_update(update) == 0xf32ce968);
tal_free(update);
common_shutdown();
return 0;
}

View File

@ -221,20 +221,16 @@ static void handle_recv_gossip(struct daemon *daemon, const u8 *outermsg)
daemon->gm,
msg, &source);
goto handled_msg_errmsg;
case WIRE_QUERY_CHANNEL_RANGE:
err = handle_query_channel_range(peer, msg);
goto handled_msg;
case WIRE_REPLY_CHANNEL_RANGE:
err = handle_reply_channel_range(peer, msg);
goto handled_msg;
case WIRE_QUERY_SHORT_CHANNEL_IDS:
err = handle_query_short_channel_ids(peer, msg);
goto handled_msg;
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
err = handle_reply_short_channel_ids_end(peer, msg);
goto handled_msg;
/* These are non-gossip messages (!is_msg_for_gossipd()) */
case WIRE_QUERY_SHORT_CHANNEL_IDS:
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_ERROR:
@ -444,7 +440,7 @@ static void gossip_init(struct daemon *daemon, const u8 *msg)
/* connectd is already started, and uses this fd to feed/recv gossip. */
daemon->connectd = daemon_conn_new(daemon, CONNECTD_FD,
connectd_req,
maybe_send_query_responses, daemon);
NULL, daemon);
tal_add_destructor(daemon->connectd, master_or_connectd_gone);
/* Tell it about all our local (public) channel_update messages,
@ -599,12 +595,6 @@ static struct io_plan *recv_req(struct io_conn *conn,
case WIRE_GOSSIPD_GET_ADDRS:
return handle_get_address(conn, daemon, msg);
case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
if (daemon->developer) {
dev_set_max_scids_encode_size(daemon, msg);
goto done;
}
/* fall thru */
case WIRE_GOSSIPD_DEV_MEMLEAK:
if (daemon->developer) {
dev_gossip_memleak(daemon, msg);

View File

@ -30,10 +30,6 @@ msgtype,gossipd_init_reply,3100
msgtype,gossipd_dev_set_time,3001
msgdata,gossipd_dev_set_time,dev_gossip_time,u32,
# Set artificial maximum reply_channel_range size. Master->gossipd
msgtype,gossipd_dev_set_max_scids_encode_size,3030
msgdata,gossipd_dev_set_max_scids_encode_size,max,u32,
# Gossipd->master get this tx output please.
msgtype,gossipd_get_txout,3018
msgdata,gossipd_get_txout,short_channel_id,short_channel_id,

1 #include <common/cryptomsg.h>
30 # Gossipd->master get this tx output please. # master->gossipd here is the output, or empty if none.
31 msgtype,gossipd_get_txout,3018 msgtype,gossipd_get_txout_reply,3118
32 msgdata,gossipd_get_txout,short_channel_id,short_channel_id, msgdata,gossipd_get_txout_reply,short_channel_id,short_channel_id,
# master->gossipd here is the output, or empty if none.
msgtype,gossipd_get_txout_reply,3118
msgdata,gossipd_get_txout_reply,short_channel_id,short_channel_id,
msgdata,gossipd_get_txout_reply,satoshis,amount_sat,
33 msgdata,gossipd_get_txout_reply,len,u16, msgdata,gossipd_get_txout_reply,satoshis,amount_sat,
34 msgdata,gossipd_get_txout_reply,outscript,u8,len msgdata,gossipd_get_txout_reply,len,u16,
35 # master -> gossipd: these potential funding outpoints were spent, please forget any channels msgdata,gossipd_get_txout_reply,outscript,u8,len

View File

@ -1,4 +1,4 @@
/* Routines to generate and handle gossip query messages */
/* Routines to generate gossip query messages */
#include "config.h"
#include <bitcoin/chainparams.h>
#include <ccan/array_size/array_size.h>
@ -15,8 +15,6 @@
#include <gossipd/gossmap_manage.h>
#include <gossipd/queries.h>
static u32 dev_max_encoding_bytes = -1U;
/* BOLT #7:
*
* There are several messages which contain a long array of
@ -41,13 +39,6 @@ static void encoding_add_short_channel_id(u8 **encoded,
towire_short_channel_id(encoded, scid);
}
/* Marshal a single channel_update_timestamps */
static void encoding_add_timestamps(u8 **encoded,
const struct channel_update_timestamps *ts)
{
towire_channel_update_timestamps(encoded, ts);
}
/* Marshal a single query flag (we don't query, so not currently used) */
static void encoding_add_query_flag(u8 **encoded, bigsize_t flag)
{
@ -56,8 +47,6 @@ static void encoding_add_query_flag(u8 **encoded, bigsize_t flag)
static bool encoding_end(const u8 *encoded, size_t max_bytes)
{
if (tal_count(encoded) > dev_max_encoding_bytes)
return false;
return tal_count(encoded) <= max_bytes;
}
@ -157,497 +146,6 @@ bool query_short_channel_ids(struct daemon *daemon,
return true;
}
/* The peer can ask about an array of short channel ids: we don't assemble the
* reply immediately but process them one at a time in dump_gossip which is
* called when there's nothing more important to send. */
const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg)
{
struct bitcoin_blkid chain;
u8 *encoded;
struct short_channel_id *scids;
bigsize_t *flags;
struct tlv_query_short_channel_ids_tlvs *tlvs;
if (!fromwire_query_short_channel_ids(tmpctx, msg, &chain, &encoded,
&tlvs)) {
return towire_warningfmt(peer, NULL,
"Bad query_short_channel_ids w/tlvs %s",
tal_hex(tmpctx, msg));
}
if (tlvs->query_flags) {
/* BOLT #7:
*
* The receiver:
*...
* - if the incoming message includes
* `query_short_channel_ids_tlvs`:
* - if `encoding_type` is not a known encoding type:
* - MAY send a `warning`.
* - MAY close the connection.
*/
flags = decode_scid_query_flags(tmpctx, tlvs->query_flags);
if (!flags) {
return towire_warningfmt(peer, NULL,
"Bad query_short_channel_ids query_flags %s",
tal_hex(tmpctx, msg));
}
} else
flags = NULL;
/* BOLT #7
*
* The receiver:
* ...
* - if does not maintain up-to-date channel information for `chain_hash`:
* - MUST set `complete` to 0.
*/
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain)) {
status_peer_debug(&peer->id,
"sent query_short_channel_ids chainhash %s",
fmt_bitcoin_blkid(tmpctx, &chain));
return towire_reply_short_channel_ids_end(peer, &chain, 0);
}
/* BOLT #7:
*
* - if it has not sent `reply_short_channel_ids_end` to a
* previously received `query_short_channel_ids` from this
* sender:
* - MAY send a `warning`.
* - MAY close the connection.
*/
if (peer->scid_queries || peer->scid_query_nodes) {
return towire_warningfmt(peer, NULL,
"Bad concurrent query_short_channel_ids");
}
scids = decode_short_ids(tmpctx, encoded);
if (!scids) {
return towire_warningfmt(peer, NULL,
"Bad query_short_channel_ids encoding %s",
tal_hex(tmpctx, encoded));
}
/* BOLT #7:
*
* The receiver:
*...
* - if `encoded_query_flags` does not decode to exactly one flag per
* `short_channel_id`:
* - MAY send a `warning`.
* - MAY close the connection.
*/
if (!flags) {
/* Pretend they asked for everything. */
flags = tal_arr(tmpctx, bigsize_t, tal_count(scids));
memset(flags, 0xFF, tal_bytelen(flags));
} else {
if (tal_count(flags) != tal_count(scids)) {
return towire_warningfmt(peer, NULL,
"Bad query_short_channel_ids flags count %zu scids %zu",
tal_count(flags), tal_count(scids));
}
}
/* BOLT #7:
*
* - MUST respond to each known `short_channel_id`:
*...
* - SHOULD NOT wait for the next outgoing gossip flush to send
* these.
*/
peer->scid_queries = tal_steal(peer, scids);
peer->scid_query_flags = tal_steal(peer, flags);
peer->scid_query_idx = 0;
peer->scid_query_nodes = tal_arr(peer, struct node_id, 0);
/* Notify the daemon_conn-write loop to invoke maybe_send_query_responses_peer */
daemon_conn_wake(peer->daemon->connectd);
return NULL;
}
/*~ We can send multiple replies when the peer queries for all channels in
* a given range of blocks; each one indicates the range of blocks it covers. */
static void send_reply_channel_range(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
const struct short_channel_id *scids,
const struct channel_update_timestamps *tstamps,
const struct channel_update_checksums *csums,
size_t num_scids,
bool final)
{
/* BOLT #7:
*
* - MUST respond with one or more `reply_channel_range`:
* - MUST set with `chain_hash` equal to that of `query_channel_range`,
* - MUST limit `number_of_blocks` to the maximum number of blocks
* whose results could fit in `encoded_short_ids`
*/
u8 *encoded_scids = encoding_start(tmpctx, true);
u8 *encoded_timestamps = encoding_start(tmpctx, false);
struct tlv_reply_channel_range_tlvs *tlvs
= tlv_reply_channel_range_tlvs_new(tmpctx);
/* Encode them all */
for (size_t i = 0; i < num_scids; i++)
encoding_add_short_channel_id(&encoded_scids, scids[i]);
encoding_end(encoded_scids, tal_bytelen(encoded_scids));
if (tstamps) {
for (size_t i = 0; i < num_scids; i++)
encoding_add_timestamps(&encoded_timestamps, &tstamps[i]);
tlvs->timestamps_tlv = tal(tlvs, struct tlv_reply_channel_range_tlvs_timestamps_tlv);
tlvs->timestamps_tlv->encoding_type = ARR_UNCOMPRESSED;
encoding_end(encoded_timestamps,
tal_bytelen(encoded_timestamps));
tlvs->timestamps_tlv->encoded_timestamps
= tal_steal(tlvs, encoded_timestamps);
}
/* Must be a tal object! */
if (csums)
tlvs->checksums_tlv = tal_dup_arr(tlvs,
struct channel_update_checksums,
csums, num_scids, 0);
/* BOLT #7:
*
* - MUST set `sync_complete` to `false` if this is not the final
* `reply_channel_range`.
*/
u8 *msg = towire_reply_channel_range(NULL,
&chainparams->genesis_blockhash,
first_blocknum,
number_of_blocks,
final, encoded_scids, tlvs);
queue_peer_msg(peer->daemon, &peer->id, take(msg));
}
/* 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);
}
/* BOLT #7:
*
* The checksum of a `channel_update` is the CRC32C checksum as specified in
* [RFC3720](https://tools.ietf.org/html/rfc3720#appendix-B.4) of this
* `channel_update` without its `signature` and `timestamp` fields.
*/
static u32 crc32_of_update(const u8 *channel_update)
{
u32 sum;
const u8 *parts[2];
size_t sizes[ARRAY_SIZE(parts)];
get_cupdate_parts(channel_update, parts, sizes);
sum = 0;
for (size_t i = 0; i < ARRAY_SIZE(parts); i++)
sum = crc32c(sum, parts[i], sizes[i]);
return sum;
}
/* BOLT #7:
* Where:
* * `timestamp_node_id_1` is the timestamp of the `channel_update` for `node_id_1`, or 0 if there was no `channel_update` from that node.
* * `timestamp_node_id_2` is the timestamp of the `channel_update` for `node_id_2`, or 0 if there was no `channel_update` from that node.
*/
static u32 get_timestamp(struct gossmap *gossmap,
const struct gossmap_chan *chan,
int dir)
{
u32 timestamp;
if (!gossmap_chan_set(chan, dir))
return 0;
gossmap_chan_get_update_details(gossmap, chan, dir, &timestamp,
NULL, NULL, NULL, NULL, NULL, NULL);
return timestamp;
}
/* BOLT #7:
* Where:
* * `checksum_node_id_1` is the checksum of the `channel_update` for
* `node_id_1`, or 0 if there was no `channel_update` from that
* node.
* * `checksum_node_id_2` is the checksum of the `channel_update` for
* `node_id_2`, or 0 if there was no `channel_update` from that
* node.
*/
static u32 get_checksum(struct gossmap *gossmap,
const struct gossmap_chan *chan,
int dir)
{
u8 *cupdate;
cupdate = gossmap_chan_get_update(tmpctx, gossmap, chan, dir);
if (!cupdate)
return 0;
return crc32_of_update(cupdate);
}
/* FIXME: This assumes that the tlv type encodes into 1 byte! */
static size_t tlv_overhead(size_t num_entries, size_t size)
{
return 1 + bigsize_len(num_entries * size);
}
/* How many entries can I fit in a reply? */
static size_t max_entries(enum query_option_flags query_option_flags)
{
/* BOLT #7:
*
* 1. type: 264 (`reply_channel_range`)
* 2. data:
* * [`chain_hash`:`chain_hash`]
* * [`u32`:`first_blocknum`]
* * [`u32`:`number_of_blocks`]
* * [`byte`:`sync_complete`]
* * [`u16`:`len`]
* * [`len*byte`:`encoded_short_ids`]
*/
const size_t reply_overhead = 32 + 4 + 4 + 1 + 2;
size_t max_encoded_bytes = 65535 - 2 - reply_overhead;
size_t per_entry_size, max_num;
per_entry_size = sizeof(struct short_channel_id);
/* Upper bound to start. */
max_num = max_encoded_bytes / per_entry_size;
/* If we add timestamps, we need to encode tlv */
if (query_option_flags & QUERY_ADD_TIMESTAMPS) {
max_encoded_bytes -= tlv_overhead(max_num,
sizeof(struct channel_update_timestamps));
per_entry_size += sizeof(struct channel_update_timestamps);
}
if (query_option_flags & QUERY_ADD_CHECKSUMS) {
max_encoded_bytes -= tlv_overhead(max_num,
sizeof(struct channel_update_checksums));
per_entry_size += sizeof(struct channel_update_checksums);
}
if (max_encoded_bytes > dev_max_encoding_bytes)
max_encoded_bytes = dev_max_encoding_bytes;
/* Always let one through! */
if (max_encoded_bytes < per_entry_size)
max_encoded_bytes = per_entry_size;
return max_encoded_bytes / per_entry_size;
}
/* This gets all the scids they asked for, and optionally the timestamps and checksums */
static struct short_channel_id *gather_range(const tal_t *ctx,
struct daemon *daemon,
u32 first_blocknum, u32 number_of_blocks,
enum query_option_flags query_option_flags,
struct channel_update_timestamps **tstamps,
struct channel_update_checksums **csums)
{
struct short_channel_id *scids;
u32 end_block;
struct gossmap *gossmap = gossmap_manage_get_gossmap(daemon->gm);
scids = tal_arr(ctx, struct short_channel_id, 0);
if (query_option_flags & QUERY_ADD_TIMESTAMPS)
*tstamps = tal_arr(ctx, struct channel_update_timestamps, 0);
else
*tstamps = NULL;
if (query_option_flags & QUERY_ADD_CHECKSUMS)
*csums = tal_arr(ctx, struct channel_update_checksums, 0);
else
*csums = NULL;
if (number_of_blocks == 0)
return NULL;
/* Fix up number_of_blocks to avoid overflow. */
end_block = first_blocknum + number_of_blocks - 1;
if (end_block < first_blocknum)
end_block = UINT_MAX;
/* We used to maintain a uintmap of channels by scid, but
* we no longer do, making this more expensive. But still
* not too bad, since it's usually in-mem */
for (size_t i = 0; i < gossmap_max_chan_idx(gossmap); i++) {
struct gossmap_chan *chan = gossmap_chan_byidx(gossmap, i);
struct short_channel_id scid;
if (!chan)
continue;
/* By policy, we don't give announcements here with no
* channel_updates */
if (!gossmap_chan_set(chan, 0) && !gossmap_chan_set(chan, 1)) {
continue;
}
scid = gossmap_chan_scid(gossmap, chan);
if (short_channel_id_blocknum(scid) < first_blocknum
|| short_channel_id_blocknum(scid) > end_block) {
continue;
}
tal_arr_expand(&scids, scid);
if (*tstamps) {
struct channel_update_timestamps ts;
ts.timestamp_node_id_1 = get_timestamp(gossmap, chan, 0);
ts.timestamp_node_id_2 = get_timestamp(gossmap, chan, 1);
tal_arr_expand(tstamps, ts);
}
if (*csums) {
struct channel_update_checksums cs;
cs.checksum_node_id_1 = get_checksum(gossmap, chan, 0);
cs.checksum_node_id_2 = get_checksum(gossmap, chan, 1);
tal_arr_expand(csums, cs);
}
}
return scids;
}
/*~ When we need to send an array of channels, it might go over our 64k packet
* size. But because we use compression, we can't actually tell how much
* we'll use. We pack them into the maximum amount for uncompressed, then
* compress afterwards.
*/
static void queue_channel_ranges(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
enum query_option_flags query_option_flags)
{
struct daemon *daemon = peer->daemon;
struct channel_update_timestamps *tstamps;
struct channel_update_checksums *csums;
struct short_channel_id *scids;
size_t off, limit;
scids = gather_range(tmpctx, daemon, first_blocknum, number_of_blocks,
query_option_flags, &tstamps, &csums);
limit = max_entries(query_option_flags);
off = 0;
/* We need to send an empty msg if we have nothing! */
do {
size_t n = tal_count(scids) - off;
u32 this_num_blocks;
if (n > limit) {
status_debug("reply_channel_range: splitting %zu-%zu of %zu",
off, off + limit, tal_count(scids));
n = limit;
/* ... and reduce to a block boundary. */
while (short_channel_id_blocknum(scids[off + n - 1])
== short_channel_id_blocknum(scids[off + limit])) {
/* We assume one block doesn't have limit #
* channels. If it does, we have to violate
* spec and send over multiple blocks. */
if (n == 0) {
status_broken("reply_channel_range: "
"could not fit %zu scids for %u!",
limit,
short_channel_id_blocknum(scids[off + n - 1]));
n = limit;
break;
}
n--;
}
/* Get *next* channel, add num blocks */
this_num_blocks
= short_channel_id_blocknum(scids[off + n])
- first_blocknum;
} else
/* Last one must end with correct total */
this_num_blocks = number_of_blocks;
send_reply_channel_range(peer, first_blocknum, this_num_blocks,
scids + off,
query_option_flags & QUERY_ADD_TIMESTAMPS
? tstamps + off : NULL,
query_option_flags & QUERY_ADD_CHECKSUMS
? csums + off : NULL,
n,
this_num_blocks == number_of_blocks);
first_blocknum += this_num_blocks;
number_of_blocks -= this_num_blocks;
off += n;
} while (number_of_blocks);
}
/*~ The peer can ask for all channels in a series of blocks. We reply with one
* or more messages containing the short_channel_ids. */
const u8 *handle_query_channel_range(struct peer *peer, const u8 *msg)
{
struct bitcoin_blkid chain_hash;
u32 first_blocknum, number_of_blocks;
enum query_option_flags query_option_flags;
struct tlv_query_channel_range_tlvs *tlvs;
if (!fromwire_query_channel_range(msg, msg, &chain_hash,
&first_blocknum, &number_of_blocks,
&tlvs)) {
return towire_warningfmt(peer, NULL,
"Bad query_channel_range w/tlvs %s",
tal_hex(tmpctx, msg));
}
if (tlvs->query_option)
query_option_flags = *tlvs->query_option;
else
query_option_flags = 0;
/* BOLT #7
*
* The receiver of `query_channel_range`:
* ...
* - if does not maintain up-to-date channel information for `chain_hash`:
* - MUST set `complete` to 0.
*/
if (!bitcoin_blkid_eq(&chainparams->genesis_blockhash, &chain_hash)) {
status_peer_debug(&peer->id,
"query_channel_range with chainhash %s",
fmt_bitcoin_blkid(tmpctx, &chain_hash));
u8 *end = towire_reply_channel_range(NULL, &chain_hash, first_blocknum,
number_of_blocks, false, NULL, NULL);
queue_peer_msg(peer->daemon, &peer->id, take(end));
return NULL;
}
/* Fix up number_of_blocks to avoid overflow. */
if (first_blocknum + number_of_blocks < first_blocknum)
number_of_blocks = UINT_MAX - first_blocknum;
queue_channel_ranges(peer, first_blocknum, number_of_blocks,
query_option_flags);
return NULL;
}
/* Append these scids (and optional timestamps) to our pending replies */
static u8 *append_range_reply(struct peer *peer,
const struct short_channel_id *scids,
@ -903,211 +401,6 @@ const u8 *handle_reply_short_channel_ids_end(struct peer *peer, const u8 *msg)
return NULL;
}
/*~ Arbitrary ordering function of pubkeys.
*
* Note that we could use memcmp() here: even if they had somehow different
* bitwise representations for the same key, we copied them all from struct
* node which should make them unique. Even if not (say, a node vanished
* and reappeared) we'd just end up sending two node_announcement for the
* same node.
*/
static int pubkey_order(const struct node_id *k1,
const struct node_id *k2,
void *unused UNUSED)
{
return node_id_cmp(k1, k2);
}
static void uniquify_node_ids(struct node_id **ids)
{
size_t dst, src;
/* BOLT #7:
* - SHOULD avoid sending duplicate `node_announcements` in
* response to a single `query_short_channel_ids`.
*/
/* ccan/asort is a typesafe qsort wrapper: like most ccan modules
* it eschews exposing 'void *' pointers and ensures that the
* callback function and its arguments match types correctly. */
asort(*ids, tal_count(*ids), pubkey_order, NULL);
/* Compact the array */
for (dst = 0, src = 0; src < tal_count(*ids); src++) {
if (dst && node_id_eq(&(*ids)[dst-1], &(*ids)[src]))
continue;
(*ids)[dst++] = (*ids)[src];
}
/* And trim to length, so tal_count() gives correct answer. */
tal_resize(ids, dst);
}
/* We are fairly careful to avoid the peer DoSing us with channel queries:
* this routine sends information about a single short_channel_id, unless
* it's finished all of them. */
static bool maybe_send_query_responses_peer(struct peer *peer)
{
struct daemon *daemon = peer->daemon;
size_t i, num;
bool sent = false;
const u8 *msg;
struct gossmap *gossmap = gossmap_manage_get_gossmap(daemon->gm);
/* BOLT #7:
*
* - MUST respond to each known `short_channel_id`:
*/
/* Search for next short_channel_id we know about. */
num = tal_count(peer->scid_queries);
for (i = peer->scid_query_idx; !sent && i < num; i++) {
struct gossmap_chan *chan;
struct gossmap_node *node;
struct node_id node_id;
chan = gossmap_find_chan(gossmap, &peer->scid_queries[i]);
if (!chan)
continue;
/* BOLT #7:
* - if bit 0 of `query_flag` is set:
* - MUST reply with a `channel_announcement`
*/
if (peer->scid_query_flags[i] & SCID_QF_ANNOUNCE) {
msg = gossmap_chan_get_announce(NULL, gossmap, chan);
queue_peer_msg(daemon, &peer->id, take(msg));
sent = true;
}
/* BOLT #7:
* - if bit 1 of `query_flag` is set and it has received a
* `channel_update` from `node_id_1`:
* - MUST reply with the latest `channel_update` for
* `node_id_1`
* - if bit 2 of `query_flag` is set and it has received a
* `channel_update` from `node_id_2`:
* - MUST reply with the latest `channel_update` for
* `node_id_2` */
if ((peer->scid_query_flags[i] & SCID_QF_UPDATE1)
&& gossmap_chan_set(chan, 0)) {
msg = gossmap_chan_get_update(NULL, gossmap, chan, 0);
queue_peer_msg(daemon, &peer->id, take(msg));
sent = true;
}
if ((peer->scid_query_flags[i] & SCID_QF_UPDATE2)
&& gossmap_chan_set(chan, 1)) {
msg = gossmap_chan_get_update(NULL, gossmap, chan, 1);
queue_peer_msg(daemon, &peer->id, take(msg));
sent = true;
}
/* BOLT #7:
* - if bit 3 of `query_flag` is set and it has received
* a `node_announcement` from `node_id_1`:
* - MUST reply with the latest `node_announcement` for
* `node_id_1`
* - if bit 4 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_2`:
* - MUST reply with the latest `node_announcement` for
* `node_id_2` */
/* Save node ids for later transmission of node_announcement */
if (peer->scid_query_flags[i] & SCID_QF_NODE1) {
node = gossmap_nth_node(gossmap, chan, 0);
gossmap_node_get_id(gossmap, node, &node_id);
tal_arr_expand(&peer->scid_query_nodes, node_id);
}
if (peer->scid_query_flags[i] & SCID_QF_NODE2) {
node = gossmap_nth_node(gossmap, chan, 1);
gossmap_node_get_id(gossmap, node, &node_id);
tal_arr_expand(&peer->scid_query_nodes, node_id);
}
}
/* Just finished channels? Remove duplicate nodes. */
if (peer->scid_query_idx != num && i == num)
uniquify_node_ids(&peer->scid_query_nodes);
/* Update index for next time we're called. */
peer->scid_query_idx = i;
/* BOLT #7:
*
* - if the incoming message does not include `encoded_query_flags`:
* ...
* - MUST follow with any `node_announcement`s for each
* `channel_announcement`
* - otherwise:
* ...
* - if bit 3 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_1`:
* - MUST reply with the latest `node_announcement` for
* `node_id_1`
* - if bit 4 of `query_flag` is set and it has received a
* `node_announcement` from `node_id_2`:
* - MUST reply with the latest `node_announcement` for
* `node_id_2`
*/
/* If we haven't sent anything above, we look for the next
* node_announcement to send. */
num = tal_count(peer->scid_query_nodes);
for (i = peer->scid_query_nodes_idx; !sent && i < num; i++) {
const struct gossmap_node *n;
/* Not every node announces itself (we know it exists because
* of a channel_announcement, however) */
n = gossmap_find_node(gossmap, &peer->scid_query_nodes[i]);
if (!n || !gossmap_node_announced(n))
continue;
msg = gossmap_node_get_announce(NULL, gossmap, n);
queue_peer_msg(daemon, &peer->id, take(msg));
sent = true;
}
peer->scid_query_nodes_idx = i;
/* All finished? */
if (peer->scid_queries
&& peer->scid_query_idx == tal_count(peer->scid_queries)
&& peer->scid_query_nodes_idx == num) {
/* BOLT #7:
*
* - MUST follow these responses with
* `reply_short_channel_ids_end`.
* - if does not maintain up-to-date channel information for
* `chain_hash`:
* - MUST set `full_information` to 0.
* - otherwise:
* - SHOULD set `full_information` to 1.
*/
/* FIXME: We consider ourselves to have complete knowledge. */
u8 *end = towire_reply_short_channel_ids_end(peer,
&chainparams->genesis_blockhash,
true);
queue_peer_msg(peer->daemon, &peer->id, take(end));
/* We're done! Clean up so we simply pass-through next time. */
peer->scid_queries = tal_free(peer->scid_queries);
peer->scid_query_flags = tal_free(peer->scid_query_flags);
peer->scid_query_idx = 0;
peer->scid_query_nodes = tal_free(peer->scid_query_nodes);
peer->scid_query_nodes_idx = 0;
}
return sent;
}
void maybe_send_query_responses(struct daemon *daemon)
{
struct peer *first, *p;
struct peer_node_id_map_iter it;
/* Rotate through, so we don't favor a single peer. */
p = first = first_random_peer(daemon, &it);
while (p) {
if (maybe_send_query_responses_peer(p))
break;
p = next_random_peer(daemon, first, &it);
}
}
bool query_channel_range(struct daemon *daemon,
struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
@ -1146,15 +439,3 @@ bool query_channel_range(struct daemon *daemon,
return true;
}
/* This is a testing hack to allow us to artificially lower the maximum bytes
* of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */
void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg)
{
assert(daemon->developer);
if (!fromwire_gossipd_dev_set_max_scids_encode_size(msg,
&dev_max_encoding_bytes))
master_badmsg(WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE, msg);
status_debug("Set max_scids_encode_bytes to %u", dev_max_encoding_bytes);
}

View File

@ -10,31 +10,11 @@ struct peer;
struct range_query_reply;
struct short_channel_id;
/* Various handlers when peer fwds a gossip query msg: return is NULL or
/* Various handlers when peer fwds a gossip query reply msg: return is NULL or
* error packet. */
const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg);
const u8 *handle_reply_short_channel_ids_end(struct peer *peer, const u8 *msg);
const u8 *handle_query_channel_range(struct peer *peer, const u8 *msg);
const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg);
/* This called when the connectd is idle. */
void maybe_send_query_responses(struct daemon *daemon);
/* BOLT #7:
*
* `query_option_flags` is a bitfield represented as a minimally-encoded bigsize.
* Bits have the following meaning:
*
* | Bit Position | Meaning |
* | ------------- | ----------------------- |
* | 0 | Sender wants timestamps |
* | 1 | Sender wants checksums |
*/
enum query_option_flags {
QUERY_ADD_TIMESTAMPS = 0x1,
QUERY_ADD_CHECKSUMS = 0x2,
};
/* Ask this peer for a range of scids. Must support it, and not already
* have a query pending. */
bool query_channel_range(struct daemon *daemon,
@ -53,12 +33,4 @@ bool query_short_channel_ids(struct daemon *daemon,
const u8 *query_flags,
void (*cb)(struct peer *peer_, bool complete));
/* This is a testing hack to allow us to artificially lower the maximum bytes
* of short_channel_ids we'll encode, using dev_set_max_scids_encode_size. */
void dev_set_max_scids_encode_size(struct daemon *daemon, const u8 *msg);
void get_cupdate_parts(const u8 *channel_update,
const u8 *parts[2],
size_t sizes[2]);
#endif /* LIGHTNING_GOSSIPD_QUERIES_H */

View File

@ -1,165 +0,0 @@
#include "config.h"
int unused_main(int argc, char *argv[]);
#define main unused_main
#include "../queries.c"
#undef main
#include <common/blinding.h>
#include <common/channel_type.h>
#include <common/ecdh.h>
#include <common/json_stream.h>
#include <common/onionreply.h>
#include <common/setup.h>
#include <stdio.h>
/* AUTOGENERATED MOCKS START */
/* Generated stub for blinding_hash_e_and_ss */
void blinding_hash_e_and_ss(const struct pubkey *e UNNEEDED,
const struct secret *ss UNNEEDED,
struct sha256 *sha UNNEEDED)
{ fprintf(stderr, "blinding_hash_e_and_ss called!\n"); abort(); }
/* Generated stub for blinding_next_privkey */
bool blinding_next_privkey(const struct privkey *e UNNEEDED,
const struct sha256 *h UNNEEDED,
struct privkey *next UNNEEDED)
{ fprintf(stderr, "blinding_next_privkey called!\n"); abort(); }
/* Generated stub for blinding_next_pubkey */
bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED,
const struct sha256 *h UNNEEDED,
struct pubkey *next UNNEEDED)
{ fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); }
/* Generated stub for daemon_conn_wake */
void daemon_conn_wake(struct daemon_conn *dc UNNEEDED)
{ fprintf(stderr, "daemon_conn_wake called!\n"); abort(); }
/* Generated stub for decode_channel_update_timestamps */
struct channel_update_timestamps *decode_channel_update_timestamps(const tal_t *ctx UNNEEDED,
const struct tlv_reply_channel_range_tlvs_timestamps_tlv *timestamps_tlv UNNEEDED)
{ fprintf(stderr, "decode_channel_update_timestamps called!\n"); abort(); }
/* Generated stub for decode_scid_query_flags */
bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED,
const struct tlv_query_short_channel_ids_tlvs_query_flags *qf UNNEEDED)
{ fprintf(stderr, "decode_scid_query_flags called!\n"); abort(); }
/* Generated stub for decode_short_ids */
struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED)
{ fprintf(stderr, "decode_short_ids called!\n"); abort(); }
/* Generated stub for first_random_peer */
struct peer *first_random_peer(struct daemon *daemon UNNEEDED,
struct peer_node_id_map_iter *it UNNEEDED)
{ fprintf(stderr, "first_random_peer called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */
bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); }
/* Generated stub for fromwire_sciddir_or_pubkey */
void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct sciddir_or_pubkey *sciddpk UNNEEDED)
{ fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); }
/* Generated stub for gossmap_chan_byidx */
struct gossmap_chan *gossmap_chan_byidx(const struct gossmap *map UNNEEDED, u32 idx UNNEEDED)
{ fprintf(stderr, "gossmap_chan_byidx called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_announce */
u8 *gossmap_chan_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update */
u8 *gossmap_chan_get_update(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update_details */
void gossmap_chan_get_update_details(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED,
u32 *timestamp UNNEEDED,
u8 *message_flags UNNEEDED,
u8 *channel_flags UNNEEDED,
u32 *fee_base_msat UNNEEDED,
u32 *fee_proportional_millionths UNNEEDED,
struct amount_msat *htlc_minimum_msat UNNEEDED,
struct amount_msat *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update_details called!\n"); abort(); }
/* Generated stub for gossmap_chan_scid */
struct short_channel_id gossmap_chan_scid(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_scid called!\n"); abort(); }
/* Generated stub for gossmap_find_chan */
struct gossmap_chan *gossmap_find_chan(const struct gossmap *map UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "gossmap_find_chan called!\n"); abort(); }
/* Generated stub for gossmap_find_node */
struct gossmap_node *gossmap_find_node(const struct gossmap *map UNNEEDED,
const struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_find_node called!\n"); abort(); }
/* Generated stub for gossmap_manage_get_gossmap */
struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED)
{ fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); }
/* Generated stub for gossmap_max_chan_idx */
u32 gossmap_max_chan_idx(const struct gossmap *map UNNEEDED)
{ fprintf(stderr, "gossmap_max_chan_idx called!\n"); abort(); }
/* Generated stub for gossmap_node_get_announce */
u8 *gossmap_node_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_node *n UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_node_get_id */
void gossmap_node_get_id(const struct gossmap *map UNNEEDED,
const struct gossmap_node *node UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_id called!\n"); abort(); }
/* Generated stub for gossmap_nth_node */
struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int n UNNEEDED)
{ fprintf(stderr, "gossmap_nth_node 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(); }
/* Generated stub for next_random_peer */
struct peer *next_random_peer(struct daemon *daemon UNNEEDED,
const struct peer *first UNNEEDED,
struct peer_node_id_map_iter *it UNNEEDED)
{ fprintf(stderr, "next_random_peer called!\n"); abort(); }
/* Generated stub for peer_supplied_good_gossip */
void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED,
const struct node_id *source_peer UNNEEDED,
size_t amount UNNEEDED)
{ fprintf(stderr, "peer_supplied_good_gossip called!\n"); abort(); }
/* Generated stub for queue_peer_msg */
void queue_peer_msg(struct daemon *daemon UNNEEDED,
const struct node_id *peer UNNEEDED,
const u8 *msg TAKES UNNEEDED)
{ fprintf(stderr, "queue_peer_msg called!\n"); abort(); }
/* Generated stub for status_fmt */
void status_fmt(enum log_level level UNNEEDED,
const struct node_id *peer UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "status_fmt called!\n"); abort(); }
/* Generated stub for towire_sciddir_or_pubkey */
void towire_sciddir_or_pubkey(u8 **pptr UNNEEDED,
const struct sciddir_or_pubkey *sciddpk UNNEEDED)
{ fprintf(stderr, "towire_sciddir_or_pubkey called!\n"); abort(); }
/* Generated stub for towire_warningfmt */
u8 *towire_warningfmt(const tal_t *ctx UNNEEDED,
const struct channel_id *channel UNNEEDED,
const char *fmt UNNEEDED, ...)
{ fprintf(stderr, "towire_warningfmt called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
int main(int argc, char *argv[])
{
u8 *update;
common_setup(argv[0]);
update = tal_hexdata(NULL, "010276df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c8029328206226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100005d50f933000000900000000000000000000003e80000000a",
strlen("010276df7e70c63cc2b63ef1c062b99c6d934a80ef2fd4dae9e1d86d277f47674af3255a97fa52ade7f129263f591ed784996eba6383135896cc117a438c8029328206226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100005d50f933000000900000000000000000000003e80000000a"));
assert(crc32_of_update(update) == 0x1112fa30);
tal_free(update);
update = tal_hexdata(NULL, "010206737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006d00000100005d50f935010000300000000000000000000000640000000b00000000000186a0",
strlen("010206737e9e18d3e4d0ab4066ccaecdcc10e648c5f1c5413f1610747e0d463fa7fa39c1b02ea2fd694275ecfefe4fe9631f24afd182ab75b805e16cd550941f858c06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006d00000100005d50f935010000300000000000000000000000640000000b00000000000186a0"));
assert(crc32_of_update(update) == 0xf32ce968);
tal_free(update);
common_shutdown();
return 0;
}

View File

@ -31,98 +31,17 @@ bool blinding_next_pubkey(const struct pubkey *pk UNNEEDED,
const struct sha256 *h UNNEEDED,
struct pubkey *next UNNEEDED)
{ fprintf(stderr, "blinding_next_pubkey called!\n"); abort(); }
/* Generated stub for daemon_conn_wake */
void daemon_conn_wake(struct daemon_conn *dc UNNEEDED)
{ fprintf(stderr, "daemon_conn_wake called!\n"); abort(); }
/* Generated stub for decode_channel_update_timestamps */
struct channel_update_timestamps *decode_channel_update_timestamps(const tal_t *ctx UNNEEDED,
const struct tlv_reply_channel_range_tlvs_timestamps_tlv *timestamps_tlv UNNEEDED)
{ fprintf(stderr, "decode_channel_update_timestamps called!\n"); abort(); }
/* Generated stub for decode_scid_query_flags */
bigsize_t *decode_scid_query_flags(const tal_t *ctx UNNEEDED,
const struct tlv_query_short_channel_ids_tlvs_query_flags *qf UNNEEDED)
{ fprintf(stderr, "decode_scid_query_flags called!\n"); abort(); }
/* Generated stub for decode_short_ids */
struct short_channel_id *decode_short_ids(const tal_t *ctx UNNEEDED, const u8 *encoded UNNEEDED)
{ fprintf(stderr, "decode_short_ids called!\n"); abort(); }
/* Generated stub for first_random_peer */
struct peer *first_random_peer(struct daemon *daemon UNNEEDED,
struct peer_node_id_map_iter *it UNNEEDED)
{ fprintf(stderr, "first_random_peer called!\n"); abort(); }
/* Generated stub for fromwire_gossipd_dev_set_max_scids_encode_size */
bool fromwire_gossipd_dev_set_max_scids_encode_size(const void *p UNNEEDED, u32 *max UNNEEDED)
{ fprintf(stderr, "fromwire_gossipd_dev_set_max_scids_encode_size called!\n"); abort(); }
/* Generated stub for fromwire_sciddir_or_pubkey */
void fromwire_sciddir_or_pubkey(const u8 **cursor UNNEEDED, size_t *max UNNEEDED,
struct sciddir_or_pubkey *sciddpk UNNEEDED)
{ fprintf(stderr, "fromwire_sciddir_or_pubkey called!\n"); abort(); }
/* Generated stub for gossmap_chan_byidx */
struct gossmap_chan *gossmap_chan_byidx(const struct gossmap *map UNNEEDED, u32 idx UNNEEDED)
{ fprintf(stderr, "gossmap_chan_byidx called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_announce */
u8 *gossmap_chan_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update */
u8 *gossmap_chan_get_update(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update called!\n"); abort(); }
/* Generated stub for gossmap_chan_get_update_details */
void gossmap_chan_get_update_details(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int dir UNNEEDED,
u32 *timestamp UNNEEDED,
u8 *message_flags UNNEEDED,
u8 *channel_flags UNNEEDED,
u32 *fee_base_msat UNNEEDED,
u32 *fee_proportional_millionths UNNEEDED,
struct amount_msat *htlc_minimum_msat UNNEEDED,
struct amount_msat *htlc_maximum_msat UNNEEDED)
{ fprintf(stderr, "gossmap_chan_get_update_details called!\n"); abort(); }
/* Generated stub for gossmap_chan_scid */
struct short_channel_id gossmap_chan_scid(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *c UNNEEDED)
{ fprintf(stderr, "gossmap_chan_scid called!\n"); abort(); }
/* Generated stub for gossmap_find_chan */
struct gossmap_chan *gossmap_find_chan(const struct gossmap *map UNNEEDED,
const struct short_channel_id *scid UNNEEDED)
{ fprintf(stderr, "gossmap_find_chan called!\n"); abort(); }
/* Generated stub for gossmap_find_node */
struct gossmap_node *gossmap_find_node(const struct gossmap *map UNNEEDED,
const struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_find_node called!\n"); abort(); }
/* Generated stub for gossmap_manage_get_gossmap */
struct gossmap *gossmap_manage_get_gossmap(struct gossmap_manage *gm UNNEEDED)
{ fprintf(stderr, "gossmap_manage_get_gossmap called!\n"); abort(); }
/* Generated stub for gossmap_max_chan_idx */
u32 gossmap_max_chan_idx(const struct gossmap *map UNNEEDED)
{ fprintf(stderr, "gossmap_max_chan_idx called!\n"); abort(); }
/* Generated stub for gossmap_node_get_announce */
u8 *gossmap_node_get_announce(const tal_t *ctx UNNEEDED,
const struct gossmap *map UNNEEDED,
const struct gossmap_node *n UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_announce called!\n"); abort(); }
/* Generated stub for gossmap_node_get_id */
void gossmap_node_get_id(const struct gossmap *map UNNEEDED,
const struct gossmap_node *node UNNEEDED,
struct node_id *id UNNEEDED)
{ fprintf(stderr, "gossmap_node_get_id called!\n"); abort(); }
/* Generated stub for gossmap_nth_node */
struct gossmap_node *gossmap_nth_node(const struct gossmap *map UNNEEDED,
const struct gossmap_chan *chan UNNEEDED,
int n UNNEEDED)
{ fprintf(stderr, "gossmap_nth_node 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(); }
/* Generated stub for next_random_peer */
struct peer *next_random_peer(struct daemon *daemon UNNEEDED,
const struct peer *first UNNEEDED,
struct peer_node_id_map_iter *it UNNEEDED)
{ fprintf(stderr, "next_random_peer called!\n"); abort(); }
/* Generated stub for peer_supplied_good_gossip */
void peer_supplied_good_gossip(struct daemon *daemon UNNEEDED,
const struct node_id *source_peer UNNEEDED,
@ -325,7 +244,7 @@ static u8 *test_reply_channel_range(const char *test_vector, const jsmntok_t *ob
json_get_member(test_vector, t,
"timestamp2"),
&ts.timestamp_node_id_2));
encoding_add_timestamps(&tlvs->timestamps_tlv->encoded_timestamps, &ts);
towire_channel_update_timestamps(&tlvs->timestamps_tlv->encoded_timestamps, &ts);
}
assert(json_tok_streq(test_vector, encodingtok, "UNCOMPRESSED"));
tlvs->timestamps_tlv->encoding_type = ARR_UNCOMPRESSED;

View File

@ -612,6 +612,7 @@ static unsigned connectd_msg(struct subd *connectd, const u8 *msg, const int *fd
case WIRE_CONNECTD_START_SHUTDOWN:
case WIRE_CONNECTD_SET_CUSTOMMSGS:
case WIRE_CONNECTD_DEV_EXHAUST_FDS:
case WIRE_CONNECTD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
/* This is a reply, so never gets through to here. */
case WIRE_CONNECTD_INIT_REPLY:
case WIRE_CONNECTD_ACTIVATE_REPLY:

View File

@ -176,7 +176,6 @@ static unsigned gossip_msg(struct subd *gossip, const u8 *msg, const int *fds)
case WIRE_GOSSIPD_INIT:
case WIRE_GOSSIPD_GET_TXOUT_REPLY:
case WIRE_GOSSIPD_OUTPOINTS_SPENT:
case WIRE_GOSSIPD_DEV_SET_MAX_SCIDS_ENCODE_SIZE:
case WIRE_GOSSIPD_DEV_MEMLEAK:
case WIRE_GOSSIPD_DEV_SET_TIME:
case WIRE_GOSSIPD_NEW_BLOCKHEIGHT:
@ -429,6 +428,7 @@ static const struct json_command addgossip_command = {
};
AUTODATA(json_command, &addgossip_command);
/* FIXME: move to connect_control.c! */
static struct command_result *
json_dev_set_max_scids_encode_size(struct command *cmd,
const char *buffer,
@ -443,8 +443,8 @@ json_dev_set_max_scids_encode_size(struct command *cmd,
NULL))
return command_param_failed();
msg = towire_gossipd_dev_set_max_scids_encode_size(NULL, *max);
subd_send_msg(cmd->ld->gossip, take(msg));
msg = towire_connectd_dev_set_max_scids_encode_size(NULL, *max);
subd_send_msg(cmd->ld->connectd, take(msg));
return command_success(cmd, json_stream_success(cmd));
}

View File

@ -64,11 +64,11 @@ bool is_msg_for_gossipd(const u8 *cursor)
case WIRE_CHANNEL_ANNOUNCEMENT:
case WIRE_NODE_ANNOUNCEMENT:
case WIRE_CHANNEL_UPDATE:
case WIRE_QUERY_SHORT_CHANNEL_IDS:
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_REPLY_CHANNEL_RANGE:
return true;
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_QUERY_SHORT_CHANNEL_IDS:
case WIRE_WARNING:
case WIRE_INIT:
case WIRE_PING: