Skip to content

Commit b2ee44b

Browse files
committed
gossipd: use modern 'sync_complete' field.
We assume if they set this to 0 (which nobody did previously), they're using it as a modern flag and use it to indicate when they're finished. Otherwise, we count how many blocks they've sent and use that to determine whether they've finished. See: lightning/bolts#826 Signed-off-by: Rusty Russell <[email protected]> Changelog-Changed: Protocol: we use `sync_complete` for gossip range query replies, with detection for older spec nodes.
1 parent 628b2af commit b2ee44b

File tree

11 files changed

+100
-62
lines changed

11 files changed

+100
-62
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ CCANDIR := ccan
2424

2525
# Where we keep the BOLT RFCs
2626
BOLTDIR := ../lightning-rfc/
27-
BOLTVERSION := b80f8a719406b70f67e4cf7d034e8cd331850173
27+
BOLTVERSION := edd45ecf22095ce97c1b5e9136a7d79351bd68cb
2828

2929
-include config.vars
3030

gossipd/gossipd.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,11 @@ struct peer {
102102

103103
/* What we're querying: [range_first_blocknum, range_end_blocknum) */
104104
u32 range_first_blocknum, range_end_blocknum;
105-
u32 range_prev_end_blocknum;
105+
u32 range_blocks_outstanding;
106106
struct range_query_reply *range_replies;
107107
void (*query_channel_range_cb)(struct peer *peer,
108108
u32 first_blocknum, u32 number_of_blocks,
109-
const struct range_query_reply *replies,
110-
bool complete);
109+
const struct range_query_reply *replies);
111110

112111
/* The daemon_conn used to queue messages to/from the peer. */
113112
struct daemon_conn *dc;

gossipd/queries.c

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -350,19 +350,15 @@ static void send_reply_channel_range(struct peer *peer,
350350
const struct short_channel_id *scids,
351351
const struct channel_update_timestamps *tstamps,
352352
const struct channel_update_checksums *csums,
353-
size_t num_scids)
353+
size_t num_scids,
354+
bool final)
354355
{
355356
/* BOLT #7:
356357
*
357358
* - MUST respond with one or more `reply_channel_range`:
358359
* - MUST set with `chain_hash` equal to that of `query_channel_range`,
359360
* - MUST limit `number_of_blocks` to the maximum number of blocks
360361
* whose results could fit in `encoded_short_ids`
361-
* - if does not maintain up-to-date channel information for
362-
* `chain_hash`:
363-
* - MUST set `full_information` to 0.
364-
* - otherwise:
365-
* - SHOULD set `full_information` to 1.
366362
*/
367363
u8 *encoded_scids = encoding_start(tmpctx);
368364
u8 *encoded_timestamps = encoding_start(tmpctx);
@@ -392,11 +388,16 @@ static void send_reply_channel_range(struct peer *peer,
392388
struct channel_update_checksums,
393389
csums, num_scids, 0);
394390

391+
/* BOLT #7:
392+
*
393+
* - MUST set `sync_complete` to `false` if this is not the final
394+
* `reply_channel_range`.
395+
*/
395396
u8 *msg = towire_reply_channel_range(NULL,
396397
&chainparams->genesis_blockhash,
397398
first_blocknum,
398399
number_of_blocks,
399-
1, encoded_scids, tlvs);
400+
final, encoded_scids, tlvs);
400401
queue_peer_msg(peer, take(msg));
401402
}
402403

@@ -453,7 +454,7 @@ static size_t max_entries(enum query_option_flags query_option_flags)
453454
* * [`chain_hash`:`chain_hash`]
454455
* * [`u32`:`first_blocknum`]
455456
* * [`u32`:`number_of_blocks`]
456-
* * [`byte`:`full_information`]
457+
* * [`byte`:`sync_complete`]
457458
* * [`u16`:`len`]
458459
* * [`len*byte`:`encoded_short_ids`]
459460
*/
@@ -632,7 +633,8 @@ static void queue_channel_ranges(struct peer *peer,
632633
? tstamps + off : NULL,
633634
query_option_flags & QUERY_ADD_CHECKSUMS
634635
? csums + off : NULL,
635-
n);
636+
n,
637+
this_num_blocks == number_of_blocks);
636638
first_blocknum += this_num_blocks;
637639
number_of_blocks -= this_num_blocks;
638640
off += n;
@@ -733,21 +735,20 @@ static u8 *append_range_reply(struct peer *peer,
733735
const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
734736
{
735737
struct bitcoin_blkid chain;
736-
u8 complete;
738+
u8 sync_complete;
737739
u32 first_blocknum, number_of_blocks, start, end;
738740
u8 *encoded;
739741
struct short_channel_id *scids;
740742
const struct range_query_reply *replies;
741743
const u8 *err;
742744
void (*cb)(struct peer *peer,
743745
u32 first_blocknum, u32 number_of_blocks,
744-
const struct range_query_reply *replies,
745-
bool complete);
746+
const struct range_query_reply *replies);
746747
struct tlv_reply_channel_range_tlvs *tlvs
747748
= tlv_reply_channel_range_tlvs_new(tmpctx);
748749

749750
if (!fromwire_reply_channel_range(tmpctx, msg, &chain, &first_blocknum,
750-
&number_of_blocks, &complete,
751+
&number_of_blocks, &sync_complete,
751752
&encoded, tlvs)) {
752753
return towire_warningfmt(peer, NULL,
753754
"Bad reply_channel_range w/tlvs %s",
@@ -788,7 +789,6 @@ const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
788789
tal_count(scids));
789790

790791
/* BOLT #7:
791-
*
792792
* The receiver of `query_channel_range`:
793793
*...
794794
* - the first `reply_channel_range` message:
@@ -797,12 +797,14 @@ const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
797797
* - MUST set `first_blocknum` plus `number_of_blocks` greater than
798798
* `first_blocknum` in `query_channel_range`.
799799
* - successive `reply_channel_range` message:
800-
* - MUST set `first_blocknum` to the previous `first_blocknum`
801-
* plus `number_of_blocks`.
800+
* - MUST have `first_blocknum` equal or greater than the previous
801+
* `first_blocknum`.
802+
* - MUST set `sync_complete` to `false` if this is not the final `reply_channel_range`.
802803
* - the final `reply_channel_range` message:
803804
* - MUST have `first_blocknum` plus `number_of_blocks` equal or
804805
* greater than the `query_channel_range` `first_blocknum` plus
805806
* `number_of_blocks`.
807+
* - MUST set `sync_complete` to `true`.
806808
*/
807809
/* ie. They can be outside range we asked, but they must overlap! */
808810
if (first_blocknum + number_of_blocks <= peer->range_first_blocknum
@@ -823,28 +825,58 @@ const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
823825
if (end > peer->range_end_blocknum)
824826
end = peer->range_end_blocknum;
825827

826-
/* LND mis-implemented the spec. If they have multiple replies, set
827-
* each one to the *whole* range, with complete=0 except the last.
828-
* Try to accomodate that (pretend we make no progress until the
829-
* end)! */
828+
/* Have a seat. It's time for a history lesson in Rusty Screws Up.
829+
*
830+
* Part 1
831+
* ------
832+
* The original spec had a field called "complete" which meant
833+
* "I believe I have complete knowledge of gossip", with the idea
834+
* that lite nodes in future would not set this.
835+
*
836+
* But I chose a terrible name, and LND mis-implemented the spec,
837+
* thinking this was an "end of replies". If they have multiple
838+
* replies, set each one to the *whole* range, with complete=0 except
839+
* the last.
840+
*
841+
* Here we try to accomodate that (pretend we make no progress
842+
* until the end)! */
830843
if (first_blocknum == peer->range_first_blocknum
831844
&& first_blocknum + number_of_blocks == peer->range_end_blocknum
832-
&& !complete
845+
&& !sync_complete
833846
&& tal_bytelen(msg) == 64046) {
834847
status_unusual("Old LND reply_channel_range detected: result will be truncated!");
835848
}
836849

837-
/* They're supposed to send them in order, but LND actually
838-
* can overlap. */
839-
if (first_blocknum != peer->range_prev_end_blocknum + 1
840-
&& first_blocknum != peer->range_prev_end_blocknum) {
841-
return towire_warningfmt(peer, NULL,
842-
"reply_channel_range %u+%u previous end was block %u",
843-
first_blocknum, number_of_blocks,
844-
peer->range_prev_end_blocknum);
845-
}
846-
peer->range_prev_end_blocknum = end;
847-
850+
/*
851+
* Part 2
852+
* ------
853+
* You were supposed to use the first_blocknum + number_of_blocks
854+
* to tell when gossip was finished, with the rule being no replies
855+
* could overlap, so you could say "I asked for blocks 100-199" and if
856+
* you got a reply saying it covered blocks 50-150, you knew that you
857+
* still had 49 blocks to receive.
858+
*
859+
* The field was renamed to `full_information`, and since everyone
860+
* did it this way anyway, we insisted the replies be in
861+
* non-overlapping ascending order.
862+
*
863+
* But LND didn't do this, and can actually overlap, since they just
864+
* chop them up when they reach length, not by block boundary, so
865+
* we had to allow that.
866+
*
867+
* Reading this implementation gave me envy: it was much simpler than
868+
* backing out to a block boundary!
869+
*
870+
* And what if a single block had so many channel openings that you
871+
* couldn't fit it in a single reply? (This was originally
872+
* inconceivable, but with the addition of timestamps and checksums,
873+
* is now possible).
874+
*
875+
* So we decided to make the lie into a truth. `full_information`
876+
* was re-renamed to `sync_complete`, and once everyone has upgraded
877+
* we can use that, rather than tallying the block numbers, to
878+
* tell if replies are finished.
879+
*/
848880
err = append_range_reply(peer, scids, tlvs->timestamps_tlv);
849881
if (err)
850882
return err;
@@ -853,9 +885,20 @@ const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
853885
* since scids are only 8 bytes, use a discount over normal gossip. */
854886
peer_supplied_good_gossip(peer, tal_count(scids) / 20);
855887

856-
/* Still more to go? */
857-
if (peer->range_prev_end_blocknum < peer->range_end_blocknum)
888+
/* Old code used to set this to 1 all the time; not setting it implies
889+
* we're talking to an upgraded node. */
890+
if (!sync_complete) {
891+
/* We no longer need old heuristic counter. */
892+
peer->range_blocks_outstanding = 0;
858893
return NULL;
894+
}
895+
896+
/* FIXME: This "how many blocks do we have answers for?" heuristic
897+
* can go away once everyone uses sync_complete properly. */
898+
if (end - start < peer->range_blocks_outstanding) {
899+
peer->range_blocks_outstanding -= end - start;
900+
return NULL;
901+
}
859902

860903
/* Clear these immediately in case cb want to queue more */
861904
replies = tal_steal(tmpctx, peer->range_replies);
@@ -864,7 +907,7 @@ const u8 *handle_reply_channel_range(struct peer *peer, const u8 *msg)
864907
peer->range_replies = NULL;
865908
peer->query_channel_range_cb = NULL;
866909

867-
cb(peer, first_blocknum, number_of_blocks, replies, complete);
910+
cb(peer, first_blocknum, number_of_blocks, replies);
868911
return NULL;
869912
}
870913

@@ -1087,8 +1130,7 @@ bool query_channel_range(struct daemon *daemon,
10871130
enum query_option_flags qflags,
10881131
void (*cb)(struct peer *peer,
10891132
u32 first_blocknum, u32 number_of_blocks,
1090-
const struct range_query_reply *replies,
1091-
bool complete))
1133+
const struct range_query_reply *replies))
10921134
{
10931135
u8 *msg;
10941136
struct tlv_query_channel_range_tlvs *tlvs;
@@ -1114,7 +1156,7 @@ bool query_channel_range(struct daemon *daemon,
11141156
queue_peer_msg(peer, take(msg));
11151157
peer->range_first_blocknum = first_blocknum;
11161158
peer->range_end_blocknum = first_blocknum + number_of_blocks;
1117-
peer->range_prev_end_blocknum = first_blocknum-1;
1159+
peer->range_blocks_outstanding = number_of_blocks;
11181160
peer->range_replies = tal_arr(peer, struct range_query_reply, 0);
11191161
peer->query_channel_range_cb = cb;
11201162

gossipd/queries.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,7 @@ bool query_channel_range(struct daemon *daemon,
4242
enum query_option_flags qflags,
4343
void (*cb)(struct peer *peer,
4444
u32 first_blocknum, u32 number_of_blocks,
45-
const struct range_query_reply *replies,
46-
bool complete));
45+
const struct range_query_reply *replies));
4746

4847
/* Ask this peer for info about an array of scids, with optional query_flags */
4948
bool query_short_channel_ids(struct daemon *daemon,

gossipd/seeker.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,7 @@ static void check_timestamps(struct seeker *seeker,
643643

644644
static void process_scid_probe(struct peer *peer,
645645
u32 first_blocknum, u32 number_of_blocks,
646-
const struct range_query_reply *replies,
647-
bool complete)
646+
const struct range_query_reply *replies)
648647
{
649648
struct seeker *seeker = peer->daemon->seeker;
650649
bool new_unknown_scids = false;

gossipd/test/run-next_block_range.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ bool query_channel_range(struct daemon *daemon UNNEEDED,
3939
enum query_option_flags qflags UNNEEDED,
4040
void (*cb)(struct peer *peer UNNEEDED,
4141
u32 first_blocknum UNNEEDED, u32 number_of_blocks UNNEEDED,
42-
const struct range_query_reply *replies UNNEEDED,
43-
bool complete))
42+
const struct range_query_reply *replies))
4443
{ fprintf(stderr, "query_channel_range called!\n"); abort(); }
4544
/* Generated stub for query_short_channel_ids */
4645
bool query_short_channel_ids(struct daemon *daemon UNNEEDED,

wire/peer_printgen.c

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wire/peer_printgen.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wire/peer_wire.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ msgtype,reply_channel_range,264,gossip_queries
195195
msgdata,reply_channel_range,chain_hash,chain_hash,
196196
msgdata,reply_channel_range,first_blocknum,u32,
197197
msgdata,reply_channel_range,number_of_blocks,u32,
198-
msgdata,reply_channel_range,full_information,byte,
198+
msgdata,reply_channel_range,sync_complete,byte,
199199
msgdata,reply_channel_range,len,u16,
200200
msgdata,reply_channel_range,encoded_short_ids,byte,len
201201
msgdata,reply_channel_range,tlvs,reply_channel_range_tlvs,

wire/peer_wiregen.c

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wire/peer_wiregen.h

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)