forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
seeker.c
961 lines (806 loc) · 26.3 KB
/
seeker.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
/* This contains the code which actively seeks out gossip from peers */
#include "config.h"
#include <bitcoin/chainparams.h>
#include <ccan/array_size/array_size.h>
#include <ccan/asort/asort.h>
#include <ccan/tal/str/str.h>
#include <common/decode_array.h>
#include <common/pseudorand.h>
#include <common/random_select.h>
#include <common/status.h>
#include <common/timeout.h>
#include <gossipd/gossipd.h>
#include <gossipd/queries.h>
#include <gossipd/routing.h>
#include <gossipd/seeker.h>
#define GOSSIP_SEEKER_INTERVAL(seeker) \
DEV_FAST_GOSSIP((seeker)->daemon->rstate->dev_fast_gossip, 5, 60)
enum seeker_state {
/* Still streaming gossip from single peer. */
STARTING_UP,
/* Probing: checking our startup really is finished. */
PROBING_SCIDS,
/* Probing: check that we have node_announcements. */
PROBING_NANNOUNCES,
/* Normal running. */
NORMAL,
/* Asking a peer for unknown scids. */
ASKING_FOR_UNKNOWN_SCIDS,
/* Asking a peer for stale scids. */
ASKING_FOR_STALE_SCIDS,
};
/* Gossip we're seeking at the moment. */
struct seeker {
struct daemon *daemon;
enum seeker_state state;
/* Timer which checks on progress every minute */
struct oneshot *check_timer;
/* Channels we've heard about, but don't know (by scid). */
UINTMAP(bool) unknown_scids;
/* Channels we've heard about newer timestamps for (by scid). u8 is
* query_flags. */
UINTMAP(u8 *) stale_scids;
/* Range of scid blocks we've probed. */
size_t scid_probe_start, scid_probe_end;
/* During startup, we ask a single peer for gossip. */
struct peer *random_peer_softref;
/* This checks progress of our random peer */
size_t prev_gossip_count;
/* Array of scids for node announcements. */
struct short_channel_id *nannounce_scids;
u8 *nannounce_query_flags;
/* Are there any node_ids we didn't know? Implies we're
* missing channels. */
bool unknown_nodes;
/* Peers we've asked to stream us gossip */
struct peer *gossiper_softref[5];
/* A peer that told us about unknown gossip. */
struct peer *preferred_peer_softref;
};
/* Mutual recursion */
static void seeker_check(struct seeker *seeker);
static void probe_some_random_scids(struct seeker *seeker);
static void begin_check_timer(struct seeker *seeker)
{
const u32 polltime = GOSSIP_SEEKER_INTERVAL(seeker);
seeker->check_timer = new_reltimer(&seeker->daemon->timers,
seeker,
time_from_sec(polltime),
seeker_check, seeker);
}
/* Set this peer as our random peer; return false if NULL. */
static bool selected_peer(struct seeker *seeker, struct peer *peer)
{
if (!peer)
return false;
set_softref(seeker, &seeker->random_peer_softref, peer);
/* Give it some grace in case we immediately hit timer */
seeker->prev_gossip_count
= peer->gossip_counter - GOSSIP_SEEKER_INTERVAL(seeker);
return true;
}
#define set_state(seeker, state, peer, ...) \
set_state_((seeker), (state), (peer), stringify(state), __VA_ARGS__)
static void set_state_(struct seeker *seeker, enum seeker_state state,
struct peer *peer,
const char *statename, const char *fmt, ...)
PRINTF_FMT(5,6);
static void set_state_(struct seeker *seeker, enum seeker_state state,
struct peer *peer,
const char *statename, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
status_peer_debug(peer ? &peer->id : NULL,
"seeker: state = %s %s",
statename, tal_vfmt(tmpctx, fmt, ap));
va_end(ap);
seeker->state = state;
selected_peer(seeker, peer);
}
struct seeker *new_seeker(struct daemon *daemon)
{
struct seeker *seeker = tal(daemon, struct seeker);
seeker->daemon = daemon;
uintmap_init(&seeker->unknown_scids);
uintmap_init(&seeker->stale_scids);
seeker->random_peer_softref = NULL;
for (size_t i = 0; i < ARRAY_SIZE(seeker->gossiper_softref); i++)
seeker->gossiper_softref[i] = NULL;
seeker->preferred_peer_softref = NULL;
seeker->unknown_nodes = false;
set_state(seeker, STARTING_UP, NULL, "New seeker");
begin_check_timer(seeker);
return seeker;
}
static void set_preferred_peer(struct seeker *seeker, struct peer *peer)
{
if (seeker->preferred_peer_softref
&& seeker->preferred_peer_softref != peer) {
clear_softref(seeker, &seeker->preferred_peer_softref);
set_softref(seeker, &seeker->preferred_peer_softref, peer);
}
}
/* Get a random peer, but try our preferred peer first, if any. This
* biasses us to the peer that told us of unexpected gossip. */
static struct peer *random_seeker(struct seeker *seeker,
bool (*check_peer)(const struct peer *peer))
{
struct peer *peer = seeker->preferred_peer_softref;
/* 80% chance of immediately choosing a peer who reported the missing
* stuff: they presumably can tell us more about it. We don't
* *always* choose it because it could be simply spamming us with
* invalid announcements to get chosen, and we don't handle that case
* well yet. */
if (peer && check_peer(peer) && pseudorand(5) != 0) {
clear_softref(seeker, &seeker->random_peer_softref);
return peer;
}
return random_peer(seeker->daemon, check_peer);
}
static bool peer_made_progress(struct seeker *seeker)
{
const struct peer *peer = seeker->random_peer_softref;
/* Has it made progress (at least one valid update per second)? If
* not, we assume it's finished, and if it hasn't, we'll end up
* querying backwards in next steps. */
if (peer->gossip_counter
>= seeker->prev_gossip_count + GOSSIP_SEEKER_INTERVAL(seeker)) {
seeker->prev_gossip_count = peer->gossip_counter;
return true;
}
return false;
}
static void disable_gossip_stream(struct seeker *seeker, struct peer *peer)
{
u8 *msg;
status_peer_debug(&peer->id, "seeker: disabling gossip");
/* This is allowed even if they don't understand it (odd) */
msg = towire_gossip_timestamp_filter(NULL,
&chainparams->genesis_blockhash,
UINT32_MAX,
UINT32_MAX);
queue_peer_msg(peer, take(msg));
}
static void enable_gossip_stream(struct seeker *seeker, struct peer *peer)
{
/* We seek some way back, to take into account propagation time */
const u32 polltime = GOSSIP_SEEKER_INTERVAL(seeker) * 10;
u32 start = seeker->daemon->rstate->last_timestamp;
u8 *msg;
if (start > polltime)
start -= polltime;
else
start = 0;
status_peer_debug(&peer->id, "seeker: starting gossip");
/* This is allowed even if they don't understand it (odd) */
msg = towire_gossip_timestamp_filter(NULL,
&chainparams->genesis_blockhash,
start,
UINT32_MAX);
queue_peer_msg(peer, take(msg));
}
static void normal_gossip_start(struct seeker *seeker, struct peer *peer)
{
bool enable_stream = false;
/* Make this one of our streaming gossipers if we aren't full */
for (size_t i = 0; i < ARRAY_SIZE(seeker->gossiper_softref); i++) {
if (seeker->gossiper_softref[i] == NULL) {
set_softref(seeker, &seeker->gossiper_softref[i], peer);
enable_stream = true;
break;
}
}
if (enable_stream)
enable_gossip_stream(seeker, peer);
else
disable_gossip_stream(seeker, peer);
}
/* Turn unknown_scids map into a flat array, removes from map. */
static struct short_channel_id *unknown_scids_remove(const tal_t *ctx,
struct seeker *seeker)
{
struct short_channel_id *scids;
/* Marshal into an array: we can fit 8000 comfortably. */
size_t i, max = 8000;
u64 scid;
scids = tal_arr(ctx, struct short_channel_id, max);
i = 0;
while (uintmap_first(&seeker->unknown_scids, &scid)) {
scids[i].u64 = scid;
(void)uintmap_del(&seeker->unknown_scids, scid);
if (++i == max)
break;
}
tal_resize(&scids, i);
return scids;
}
/* We have selected this peer to stream us startup gossip */
static void peer_gossip_startup(struct seeker *seeker, struct peer *peer)
{
status_peer_debug(&peer->id, "seeker: chosen as startup peer");
selected_peer(seeker, peer);
normal_gossip_start(seeker, peer);
}
static bool peer_has_gossip_queries(const struct peer *peer)
{
return peer->gossip_queries_feature;
}
static bool peer_can_take_range_query(const struct peer *peer)
{
return peer->gossip_queries_feature
&& !peer->range_replies;
}
static bool peer_can_take_scid_query(const struct peer *peer)
{
return peer->gossip_queries_feature
&& !peer->scid_query_outstanding;
}
static void scid_query_done(struct peer *peer, bool complete)
{
struct seeker *seeker = peer->daemon->seeker;
/* Peer completed! OK, start random scid probe in case we're
* still missing gossip. */
probe_some_random_scids(seeker);
}
/* Returns true if there were scids to seek. */
static bool seek_any_unknown_scids(struct seeker *seeker)
{
struct peer *peer;
struct short_channel_id *scids;
/* Nothing we need to know about? */
if (uintmap_empty(&seeker->unknown_scids))
return false;
/* No peers can answer? Try again later. */
peer = random_seeker(seeker, peer_can_take_scid_query);
if (!peer)
return false;
scids = unknown_scids_remove(tmpctx, seeker);
set_state(seeker, ASKING_FOR_UNKNOWN_SCIDS, peer,
"Asking for %zu scids", tal_count(scids));
if (!query_short_channel_ids(seeker->daemon, peer, scids, NULL,
scid_query_done))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"seeker: quering %zu scids is too many?",
tal_count(scids));
return true;
}
/* Turns stale_scid_map into two arrays, and removes from map */
static struct short_channel_id *stale_scids_remove(const tal_t *ctx,
struct seeker *seeker,
u8 **query_flags)
{
struct short_channel_id *scids;
const u8 *qf;
/* We can fit 7000 comfortably (8 byte scid, 1 byte flag). */
size_t i, max = 7000;
u64 scid;
scids = tal_arr(ctx, struct short_channel_id, max);
*query_flags = tal_arr(ctx, u8, max);
i = 0;
while ((qf = uintmap_first(&seeker->stale_scids, &scid)) != NULL) {
scids[i].u64 = scid;
(*query_flags)[i] = *qf;
uintmap_del(&seeker->stale_scids, scid);
tal_free(qf);
i++;
if (i == max)
break;
}
tal_resize(&scids, i);
tal_resize(query_flags, i);
return scids;
}
static bool seek_any_stale_scids(struct seeker *seeker)
{
struct peer *peer;
struct short_channel_id *scids;
u8 *query_flags;
/* Nothing we need to know about? */
if (uintmap_empty(&seeker->stale_scids))
return false;
/* No peers can answer? Try again later. */
peer = random_seeker(seeker, peer_can_take_scid_query);
if (!peer)
return false;
/* This is best-effort, so this consumes them as well. */
scids = stale_scids_remove(tmpctx, seeker, &query_flags);
set_state(seeker, ASKING_FOR_STALE_SCIDS, peer,
"Asking for %zu scids", tal_count(scids));
if (!query_short_channel_ids(seeker->daemon, peer, scids, query_flags,
scid_query_done))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"seeker: quering %zu scids is too many?",
tal_count(scids));
return true;
}
/* Returns true and sets first_blocknum and number_of_blocks if
* there's more to find. */
static bool next_block_range(struct seeker *seeker,
u32 prev_num_blocks,
u32 *first_blocknum, u32 *number_of_blocks)
{
const u32 current_height = seeker->daemon->current_blockheight;
/* We always try to get twice as many as last time. */
*number_of_blocks = prev_num_blocks * 2;
if (seeker->scid_probe_start > 0) {
/* Enlarge probe to cover prior blocks, but twice as many. */
if (*number_of_blocks > seeker->scid_probe_start) {
*number_of_blocks = seeker->scid_probe_start;
*first_blocknum = 0;
} else {
*first_blocknum
= seeker->scid_probe_start - *number_of_blocks;
}
seeker->scid_probe_start = *first_blocknum;
return true;
}
/* We allow 6 new blocks since we started; they should be empty anyway */
if (seeker->scid_probe_end + 6 < current_height) {
if (seeker->scid_probe_end + *number_of_blocks > current_height)
*number_of_blocks
= current_height - seeker->scid_probe_end;
*first_blocknum = seeker->scid_probe_end + 1;
seeker->scid_probe_end = *first_blocknum + *number_of_blocks - 1;
return true;
}
/* No more to find. */
return false;
}
static int cmp_scid(const struct short_channel_id *a,
const struct short_channel_id *b,
void *unused)
{
if (a->u64 > b->u64)
return 1;
else if (a->u64 < b->u64)
return -1;
return 0;
}
/* We can't ask for channels by node_id, so probe at random */
static bool get_unannounced_nodes(const tal_t *ctx,
struct routing_state *rstate,
size_t max,
struct short_channel_id **scids,
u8 **query_flags)
{
size_t num = 0;
u64 offset;
double total_weight = 0.0;
/* Pick an example short_channel_id at random to query. As a
* side-effect this gets the node. */
*scids = tal_arr(ctx, struct short_channel_id, max);
/* FIXME: This is inefficient! Reuse next_block_range here! */
for (struct chan *c = uintmap_first(&rstate->chanmap, &offset);
c;
c = uintmap_after(&rstate->chanmap, &offset)) {
/* Local-only? Don't ask. */
if (!is_chan_public(c))
continue;
if (c->nodes[0]->bcast.index && c->nodes[1]->bcast.index)
continue;
if (num < max) {
(*scids)[num++] = c->scid;
} else {
/* Maybe replace one: approx. reservoir sampling */
if (random_select(1.0, &total_weight))
(*scids)[pseudorand(max)] = c->scid;
}
}
if (num == 0) {
*scids = tal_free(*scids);
return false;
}
if (num < max)
tal_resize(scids, num);
/* Sort them into order. */
asort(*scids, num, cmp_scid, NULL);
/* Now get flags. */
*query_flags = tal_arr(ctx, u8, num);
for (size_t i = 0; i < tal_count(*scids); i++) {
struct chan *c = get_channel(rstate, &(*scids)[i]);
(*query_flags)[i] = 0;
if (!c->nodes[0]->bcast.index)
(*query_flags)[i] |= SCID_QF_NODE1;
if (!c->nodes[1]->bcast.index)
(*query_flags)[i] |= SCID_QF_NODE2;
}
return true;
}
/* Mutual recursion */
static void peer_gossip_probe_nannounces(struct seeker *seeker);
static void nodeannounce_query_done(struct peer *peer, bool complete)
{
struct seeker *seeker = peer->daemon->seeker;
struct routing_state *rstate = seeker->daemon->rstate;
size_t new_nannounce = 0, num_scids;
/* We might have given up on them, then they replied. */
if (seeker->random_peer_softref != peer) {
status_peer_debug(&peer->id, "seeker: belated reply: ignoring");
return;
}
clear_softref(seeker, &seeker->random_peer_softref);
num_scids = tal_count(seeker->nannounce_scids);
for (size_t i = 0; i < num_scids; i++) {
struct chan *c = get_channel(rstate,
&seeker->nannounce_scids[i]);
/* Could have closed since we asked. */
if (!c)
continue;
if ((seeker->nannounce_query_flags[i] & SCID_QF_NODE1)
&& c->nodes[0]->bcast.index)
new_nannounce++;
if ((seeker->nannounce_query_flags[i] & SCID_QF_NODE2)
&& c->nodes[1]->bcast.index)
new_nannounce++;
}
status_peer_debug(&peer->id,
"seeker: found %zu new node_announcements in %zu scids",
new_nannounce, num_scids);
seeker->nannounce_scids = tal_free(seeker->nannounce_scids);
seeker->nannounce_query_flags = tal_free(seeker->nannounce_query_flags);
if (!new_nannounce) {
set_state(seeker, NORMAL, NULL,
"No new node_announcements in %zu scids", num_scids);
return;
}
/* Since they told us about new announcements, keep asking them. */
set_preferred_peer(seeker, peer);
/* Double every time. We may skip a few, of course, since map
* is changing. */
num_scids *= 2;
/* Don't try to create a query larger than 64k */
if (num_scids > 7000)
num_scids = 7000;
if (!get_unannounced_nodes(seeker, seeker->daemon->rstate, num_scids,
&seeker->nannounce_scids,
&seeker->nannounce_query_flags)) {
/* Nothing unknown at all? Great, we're done */
set_state(seeker, NORMAL, NULL, "No unannounced nodes");
return;
}
peer_gossip_probe_nannounces(seeker);
}
/* Pick a peer, ask it for a few node announcements, to check. */
static void peer_gossip_probe_nannounces(struct seeker *seeker)
{
struct peer *peer;
peer = random_seeker(seeker, peer_can_take_scid_query);
set_state(seeker, PROBING_NANNOUNCES, peer,
"Probing for %zu scids",
tal_count(seeker->nannounce_scids));
if (!peer)
return;
if (!query_short_channel_ids(seeker->daemon, peer,
seeker->nannounce_scids,
seeker->nannounce_query_flags,
nodeannounce_query_done))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"seeker: quering %zu scids is too many?",
tal_count(seeker->nannounce_scids));
}
/* They have update with this timestamp: do we want it? */
static bool want_update(struct seeker *seeker,
u32 timestamp, const struct half_chan *hc)
{
if (!is_halfchan_defined(hc))
return timestamp != 0;
if (timestamp <= hc->bcast.timestamp)
return false;
return !would_ratelimit_cupdate(seeker->daemon->rstate, hc, timestamp);
}
/* They gave us timestamps. Do we want updated versions? */
static void check_timestamps(struct seeker *seeker,
struct chan *c,
const struct channel_update_timestamps *ts,
struct peer *peer)
{
u8 *stale;
u8 query_flag = 0;
/* BOLT #7:
* * `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.
*/
if (want_update(seeker, ts->timestamp_node_id_1, &c->half[0]))
query_flag |= SCID_QF_UPDATE1;
if (want_update(seeker, ts->timestamp_node_id_2, &c->half[1]))
query_flag |= SCID_QF_UPDATE2;
if (!query_flag)
return;
/* Add in flags if we're already getting it. */
stale = uintmap_get(&seeker->stale_scids, c->scid.u64);
if (!stale) {
stale = talz(seeker, u8);
uintmap_add(&seeker->stale_scids, c->scid.u64, stale);
set_preferred_peer(seeker, peer);
}
*stale |= query_flag;
}
static void process_scid_probe(struct peer *peer,
u32 first_blocknum, u32 number_of_blocks,
const struct range_query_reply *replies)
{
struct seeker *seeker = peer->daemon->seeker;
bool new_unknown_scids = false;
/* We might have given up on them, then they replied. */
if (seeker->random_peer_softref != peer)
return;
clear_softref(seeker, &seeker->random_peer_softref);
for (size_t i = 0; i < tal_count(replies); i++) {
struct chan *c = get_channel(seeker->daemon->rstate,
&replies[i].scid);
if (c) {
check_timestamps(seeker, c, &replies[i].ts, peer);
continue;
}
new_unknown_scids |= add_unknown_scid(seeker, &replies[i].scid,
peer);
}
/* No new unknown scids, or no more to ask? We give some wiggle
* room in case blocks came in since we started. */
if (new_unknown_scids
&& next_block_range(seeker, number_of_blocks,
&first_blocknum, &number_of_blocks)) {
/* This must return a peer, since we have the current peer! */
peer = random_seeker(seeker, peer_can_take_range_query);
assert(peer);
selected_peer(seeker, peer);
query_channel_range(seeker->daemon, peer,
first_blocknum, number_of_blocks,
QUERY_ADD_TIMESTAMPS,
process_scid_probe);
return;
}
/* Channel probe finished, try asking for 128 unannounced nodes. */
if (!get_unannounced_nodes(seeker, seeker->daemon->rstate, 128,
&seeker->nannounce_scids,
&seeker->nannounce_query_flags)) {
/* No unknown nodes. Great! */
set_state(seeker, NORMAL, NULL, "No unannounced nodes");
return;
}
peer_gossip_probe_nannounces(seeker);
}
/* Pick a peer, ask it for a few scids, to check. */
static void peer_gossip_probe_scids(struct seeker *seeker)
{
struct peer *peer;
peer = random_seeker(seeker, peer_can_take_range_query);
set_state(seeker, PROBING_SCIDS, peer,
"Seeking scids %zu - %zu",
seeker->scid_probe_start, seeker->scid_probe_end);
if (!peer)
return;
/* This calls process_scid_probe when we get the reply. */
query_channel_range(seeker->daemon, peer,
seeker->scid_probe_start,
seeker->scid_probe_end - seeker->scid_probe_start + 1,
QUERY_ADD_TIMESTAMPS,
process_scid_probe);
}
static void probe_random_scids(struct seeker *seeker, size_t num_blocks)
{
u32 avail_blocks;
/* Ignore early blocks (unless we're before, which would be weird) */
if (seeker->daemon->current_blockheight
< chainparams->when_lightning_became_cool)
avail_blocks = seeker->daemon->current_blockheight;
else
avail_blocks = seeker->daemon->current_blockheight
- chainparams->when_lightning_became_cool;
if (avail_blocks < num_blocks) {
seeker->scid_probe_start = 0;
seeker->scid_probe_end = seeker->daemon->current_blockheight;
} else {
seeker->scid_probe_start
= chainparams->when_lightning_became_cool
+ pseudorand(avail_blocks - num_blocks);
seeker->scid_probe_end
= seeker->scid_probe_start + num_blocks - 1;
}
seeker->nannounce_scids = NULL;
peer_gossip_probe_scids(seeker);
}
/* We usually get a channel per block, so these cover a fair bit of ground */
static void probe_some_random_scids(struct seeker *seeker)
{
return probe_random_scids(seeker, 1024);
}
static void probe_many_random_scids(struct seeker *seeker)
{
return probe_random_scids(seeker, 10000);
}
static void check_firstpeer(struct seeker *seeker)
{
struct peer *peer = seeker->random_peer_softref, *p;
/* It might have died, pick another. */
if (!peer) {
peer = random_seeker(seeker, peer_has_gossip_queries);
/* No peer? Wait for a new one to join. */
if (!peer) {
status_debug("seeker: no peers, waiting");
return;
}
peer_gossip_startup(seeker, peer);
return;
}
/* If no progress, we assume it's finished, and if it hasn't,
* we'll end up querying backwards in next steps. */
if (peer_made_progress(seeker))
return;
/* Other peers can gossip now. */
status_peer_debug(&peer->id, "seeker: startup peer finished");
clear_softref(seeker, &seeker->random_peer_softref);
list_for_each(&seeker->daemon->peers, p, list) {
if (p == peer)
continue;
normal_gossip_start(seeker, p);
}
/* Ask a random peer for all channels, in case we're missing */
seeker->scid_probe_start = chainparams->when_lightning_became_cool;
seeker->scid_probe_end = seeker->daemon->current_blockheight;
if (seeker->scid_probe_start > seeker->scid_probe_end)
seeker->scid_probe_start = 0;
peer_gossip_probe_scids(seeker);
}
static void check_probe(struct seeker *seeker,
void (*restart)(struct seeker *seeker))
{
struct peer *peer = seeker->random_peer_softref;
/* It might have died, pick another. */
if (!peer) {
restart(seeker);
return;
}
/* Is peer making progress with responses? */
if (peer_made_progress(seeker))
return;
status_peer_debug(&peer->id,
"has only moved gossip %zu->%zu for probe, giving up on it",
seeker->prev_gossip_count, peer->gossip_counter);
clear_softref(seeker, &seeker->random_peer_softref);
restart(seeker);
}
static bool peer_is_not_gossipper(const struct peer *peer)
{
const struct seeker *seeker = peer->daemon->seeker;
for (size_t i = 0; i < ARRAY_SIZE(seeker->gossiper_softref); i++) {
if (seeker->gossiper_softref[i] == peer)
return false;
}
return true;
}
/* FIXME: We should look at gossip performance and replace the underperforming
* peers in preference. */
static void maybe_rotate_gossipers(struct seeker *seeker)
{
struct peer *peer;
size_t i;
/* If all peers are gossiping, we're done */
peer = random_seeker(seeker, peer_is_not_gossipper);
if (!peer)
return;
/* If we have a slot free, or ~ 1 per hour */
for (i = 0; i < ARRAY_SIZE(seeker->gossiper_softref); i++) {
if (!seeker->gossiper_softref[i]) {
status_peer_debug(&peer->id, "seeker: filling slot %zu",
i);
goto set_gossiper;
}
if (pseudorand(ARRAY_SIZE(seeker->gossiper_softref) * 60) == 0) {
status_peer_debug(&peer->id,
"seeker: replacing slot %zu",
i);
goto clear_and_set_gossiper;
}
}
return;
clear_and_set_gossiper:
disable_gossip_stream(seeker, seeker->gossiper_softref[i]);
clear_softref(seeker, &seeker->gossiper_softref[i]);
set_gossiper:
set_softref(seeker, &seeker->gossiper_softref[i], peer);
enable_gossip_stream(seeker, peer);
}
static bool seek_any_unknown_nodes(struct seeker *seeker)
{
if (!seeker->unknown_nodes)
return false;
seeker->unknown_nodes = false;
probe_many_random_scids(seeker);
return true;
}
/* Periodic timer to see how our gossip is going. */
static void seeker_check(struct seeker *seeker)
{
/* We don't do anything until we're synced. */
if (seeker->daemon->current_blockheight == 0)
goto out;
switch (seeker->state) {
case STARTING_UP:
check_firstpeer(seeker);
break;
case PROBING_SCIDS:
check_probe(seeker, peer_gossip_probe_scids);
break;
case ASKING_FOR_UNKNOWN_SCIDS:
check_probe(seeker, probe_many_random_scids);
break;
case ASKING_FOR_STALE_SCIDS:
check_probe(seeker, probe_some_random_scids);
break;
case PROBING_NANNOUNCES:
check_probe(seeker, peer_gossip_probe_nannounces);
break;
case NORMAL:
maybe_rotate_gossipers(seeker);
if (!seek_any_unknown_scids(seeker)
&& !seek_any_stale_scids(seeker))
seek_any_unknown_nodes(seeker);
break;
}
out:
begin_check_timer(seeker);
}
/* We get this when we have a new peer. */
void seeker_setup_peer_gossip(struct seeker *seeker, struct peer *peer)
{
/* Can't do anything useful with these peers. */
if (!peer->gossip_queries_feature)
return;
/* Don't start gossiping until we're synced. */
if (seeker->daemon->current_blockheight == 0)
return;
switch (seeker->state) {
case STARTING_UP:
if (seeker->random_peer_softref == NULL)
peer_gossip_startup(seeker, peer);
/* Waiting for seeker_check to release us */
return;
/* In these states, we set up peers to stream gossip normally */
case PROBING_SCIDS:
case PROBING_NANNOUNCES:
case NORMAL:
case ASKING_FOR_UNKNOWN_SCIDS:
case ASKING_FOR_STALE_SCIDS:
normal_gossip_start(seeker, peer);
return;
}
abort();
}
bool remove_unknown_scid(struct seeker *seeker,
const struct short_channel_id *scid,
bool found /*FIXME: use this info!*/)
{
return uintmap_del(&seeker->unknown_scids, scid->u64);
}
bool add_unknown_scid(struct seeker *seeker,
const struct short_channel_id *scid,
struct peer *peer)
{
/* Check we're not already getting this one. */
if (!uintmap_add(&seeker->unknown_scids, scid->u64, true))
return false;
set_preferred_peer(seeker, peer);
return true;
}
/* This peer told us about an update to an unknown channel. Ask it for a
* channel_announcement. */
void query_unknown_channel(struct daemon *daemon,
struct peer *peer,
const struct short_channel_id *id)
{
/* Too many, or duplicate? */
if (!add_unknown_scid(daemon->seeker, id, peer))
return;
}
/* This peer told us about an unknown node. Start probing it. */
void query_unknown_node(struct seeker *seeker, struct peer *peer)
{
seeker->unknown_nodes = true;
set_preferred_peer(seeker, peer);
}