forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gossip_store.c
206 lines (183 loc) · 5.29 KB
/
gossip_store.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
#include "config.h"
#include <ccan/crc32c/crc32c.h>
#include <common/status.h>
#include <connectd/gossip_store.h>
#include <errno.h>
#include <fcntl.h>
#include <gossipd/gossip_store_wiregen.h>
#include <inttypes.h>
#include <unistd.h>
#include <wire/peer_wire.h>
static bool timestamp_filter(u32 timestamp_min, u32 timestamp_max,
u32 timestamp)
{
/* BOLT #7:
*
* - SHOULD send all gossip messages whose `timestamp` is greater or
* equal to `first_timestamp`, and less than `first_timestamp` plus
* `timestamp_range`.
*/
/* Note that we turn first_timestamp & timestamp_range into an inclusive range */
return timestamp >= timestamp_min
&& timestamp <= timestamp_max;
}
static size_t reopen_gossip_store(int *gossip_store_fd, const u8 *msg)
{
u64 equivalent_offset;
int newfd;
if (!fromwire_gossip_store_ended(msg, &equivalent_offset))
status_failed(STATUS_FAIL_GOSSIP_IO,
"Bad gossipd GOSSIP_STORE_ENDED msg: %s",
tal_hex(tmpctx, msg));
newfd = open(GOSSIP_STORE_FILENAME, O_RDONLY);
if (newfd < 0)
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Cannot open %s: %s",
GOSSIP_STORE_FILENAME,
strerror(errno));
status_debug("gossip_store at end, new fd moved to %"PRIu64,
equivalent_offset);
close(*gossip_store_fd);
*gossip_store_fd = newfd;
return equivalent_offset;
}
static bool public_msg_type(enum peer_wire type)
{
/* This switch statement makes you think about new types as they
* are introduced. */
switch (type) {
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_WARNING:
case WIRE_PING:
case WIRE_PONG:
case WIRE_TX_ADD_INPUT:
case WIRE_TX_ADD_OUTPUT:
case WIRE_TX_REMOVE_INPUT:
case WIRE_TX_REMOVE_OUTPUT:
case WIRE_TX_COMPLETE:
case WIRE_TX_SIGNATURES:
case WIRE_OPEN_CHANNEL:
case WIRE_ACCEPT_CHANNEL:
case WIRE_FUNDING_CREATED:
case WIRE_FUNDING_SIGNED:
case WIRE_CHANNEL_READY:
case WIRE_OPEN_CHANNEL2:
case WIRE_ACCEPT_CHANNEL2:
case WIRE_TX_INIT_RBF:
case WIRE_TX_ACK_RBF:
case WIRE_TX_ABORT:
case WIRE_SHUTDOWN:
case WIRE_CLOSING_SIGNED:
case WIRE_UPDATE_ADD_HTLC:
case WIRE_UPDATE_FULFILL_HTLC:
case WIRE_UPDATE_FAIL_HTLC:
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
case WIRE_COMMITMENT_SIGNED:
case WIRE_REVOKE_AND_ACK:
case WIRE_UPDATE_FEE:
case WIRE_UPDATE_BLOCKHEIGHT:
case WIRE_CHANNEL_REESTABLISH:
case WIRE_ANNOUNCEMENT_SIGNATURES:
case WIRE_QUERY_SHORT_CHANNEL_IDS:
case WIRE_REPLY_SHORT_CHANNEL_IDS_END:
case WIRE_QUERY_CHANNEL_RANGE:
case WIRE_REPLY_CHANNEL_RANGE:
case WIRE_GOSSIP_TIMESTAMP_FILTER:
case WIRE_ONION_MESSAGE:
case WIRE_PEER_STORAGE:
case WIRE_YOUR_PEER_STORAGE:
case WIRE_STFU:
case WIRE_SPLICE:
case WIRE_SPLICE_ACK:
case WIRE_SPLICE_LOCKED:
return false;
case WIRE_CHANNEL_ANNOUNCEMENT:
case WIRE_NODE_ANNOUNCEMENT:
case WIRE_CHANNEL_UPDATE:
return true;
}
/* Actually, we do have other (internal) messages. */
return false;
}
u8 *gossip_store_next(const tal_t *ctx,
int *gossip_store_fd,
u32 timestamp_min, u32 timestamp_max,
size_t *off, size_t *end)
{
u8 *msg = NULL;
size_t initial_off = *off;
while (!msg) {
struct gossip_hdr hdr;
u16 msglen, flags;
u32 checksum, timestamp;
int type, r;
r = pread(*gossip_store_fd, &hdr, sizeof(hdr), *off);
if (r != sizeof(hdr))
return NULL;
msglen = be16_to_cpu(hdr.len);
flags = be16_to_cpu(hdr.flags);
/* Skip any deleted/dying entries. */
if (flags & (GOSSIP_STORE_DELETED_BIT|GOSSIP_STORE_DYING_BIT)) {
*off += r + msglen;
continue;
}
/* Skip any timestamp filtered */
timestamp = be32_to_cpu(hdr.timestamp);
/* Note: channel_announcements without a channel_update yet
* will have 0 timestamp (we don't know). Better to send them. */
if (timestamp &&
!timestamp_filter(timestamp_min, timestamp_max, timestamp)) {
*off += r + msglen;
continue;
}
checksum = be32_to_cpu(hdr.crc);
msg = tal_arr(ctx, u8, msglen);
r = pread(*gossip_store_fd, msg, msglen, *off + r);
if (r != msglen)
return tal_free(msg);
if (checksum != crc32c(be32_to_cpu(hdr.timestamp), msg, msglen))
status_failed(STATUS_FAIL_INTERNAL_ERROR,
"gossip_store: bad checksum at offset %zu"
"(was at %zu): %s",
*off, initial_off, tal_hex(tmpctx, msg));
/* Definitely processing it now */
*off += sizeof(hdr) + msglen;
if (*off > *end)
*end = *off;
type = fromwire_peektype(msg);
/* end can go backwards in this case! */
if (type == WIRE_GOSSIP_STORE_ENDED) {
*off = *end = reopen_gossip_store(gossip_store_fd, msg);
msg = tal_free(msg);
/* Ignore gossipd internal messages. */
} else if (!public_msg_type(type)) {
msg = tal_free(msg);
}
}
return msg;
}
/* Keep seeking forward until we hit something >= timestamp */
size_t find_gossip_store_by_timestamp(int gossip_store_fd,
size_t off,
u32 timestamp)
{
u16 type, flags;
u32 ts;
size_t msglen;
while (gossip_store_readhdr(gossip_store_fd, off,
&msglen, &ts, &flags, &type)) {
/* Don't swallow end marker! Reset, as they will call
* gossip_store_next and reopen file. */
if (type == WIRE_GOSSIP_STORE_ENDED)
return 1;
/* Only to-be-broadcast types have valid timestamps! */
if (!(flags & GOSSIP_STORE_DELETED_BIT)
&& public_msg_type(type)
&& ts >= timestamp) {
break;
}
off += sizeof(struct gossip_hdr) + msglen;
}
return off;
}