gossmap: make API more robust against future changes.

Many changes to gossmap (including the pending ones!) don't actually
concern readers, as long as they obey certain rules:

1. Ignore unknown messages.
2. Treat all 16 upper bits of length as flags, ignore unknown ones.

So now we split the version byte into MAJOR and MINOR, and you can
ignore MINOR changes.

We don't expose the internal version (for creating the map)
programmatically: you should really hardcode what major version you
understand!

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-09-14 13:20:31 +09:30
parent 3817a690c9
commit 6338758018
9 changed files with 51 additions and 22 deletions

View File

@@ -11,7 +11,18 @@ struct gossip_rcvd_filter;
/** /**
* gossip_store -- On-disk storage related information * gossip_store -- On-disk storage related information
*/ */
#define GOSSIP_STORE_VERSION 10
/* First byte of file is the version.
*
* Top three bits mean incompatible change.
* As of this writing, major == 0, minor == 10.
*/
#define GOSSIP_STORE_MAJOR_VERSION_MASK 0xE0
#define GOSSIP_STORE_MINOR_VERSION_MASK 0x1F
/* Extract version from first byte */
#define GOSSIP_STORE_MAJOR_VERSION(verbyte) (((u8)(verbyte)) >> 5)
#define GOSSIP_STORE_MINOR_VERSION(verbyte) ((verbyte) & GOSSIP_STORE_MINOR_VERSION_MASK)
/** /**
* Bit of length we use to mark a deleted record. * Bit of length we use to mark a deleted record.
@@ -26,12 +37,16 @@ struct gossip_rcvd_filter;
/** /**
* Bit of length used to define a rate-limited record (do not rebroadcast) * Bit of length used to define a rate-limited record (do not rebroadcast)
*/ */
#define GOSSIP_STORE_LEN_RATELIMIT_BIT 0x20000000U #define GOSSIP_STORE_LEN_RATELIMIT_BIT 0x20000000U
/**
* Full flags mask
*/
#define GOSSIP_STORE_FLAGS_MASK 0xFFFF0000U
/* Mask for extracting just the length part of len field */ /* Mask for extracting just the length part of len field */
#define GOSSIP_STORE_LEN_MASK \ #define GOSSIP_STORE_LEN_MASK \
(~(GOSSIP_STORE_LEN_PUSH_BIT | GOSSIP_STORE_LEN_DELETED_BIT | \ (~(GOSSIP_STORE_FLAGS_MASK))
GOSSIP_STORE_LEN_RATELIMIT_BIT))
/** /**
* gossip_hdr -- On-disk format header. * gossip_hdr -- On-disk format header.

View File

@@ -672,7 +672,8 @@ static bool load_gossip_store(struct gossmap *map, size_t *num_rejected)
if (map->mmap == MAP_FAILED) if (map->mmap == MAP_FAILED)
map->mmap = NULL; map->mmap = NULL;
if (map_u8(map, 0) != GOSSIP_STORE_VERSION) { /* We only support major version 0 */
if (GOSSIP_STORE_MAJOR_VERSION(map_u8(map, 0)) != 0) {
close(map->fd); close(map->fd);
if (map->mmap) if (map->mmap)
munmap(map->mmap, map->map_size); munmap(map->mmap, map->map_size);

View File

@@ -179,7 +179,7 @@ int main(int argc, char *argv[])
int store_fd; int store_fd;
struct gossmap *gossmap; struct gossmap *gossmap;
const double riskfactor = 1.0; const double riskfactor = 1.0;
char gossip_version = GOSSIP_STORE_VERSION; char gossip_version = 10;
char *gossipfilename; char *gossipfilename;
common_setup(argv[0]); common_setup(argv[0]);

View File

@@ -176,7 +176,7 @@ int main(int argc, char *argv[])
int store_fd; int store_fd;
struct gossmap *gossmap; struct gossmap *gossmap;
const double riskfactor = 1.0; const double riskfactor = 1.0;
char gossip_version = GOSSIP_STORE_VERSION; char gossip_version = 10;
char *gossipfilename; char *gossipfilename;
chainparams = chainparams_for_network("regtest"); chainparams = chainparams_for_network("regtest");

View File

@@ -9,13 +9,12 @@ import io
import struct import struct
# These duplicate constants in lightning/common/gossip_store.h # These duplicate constants in lightning/common/gossip_store.h
GOSSIP_STORE_VERSIONS = [0x09, 0x0a] GOSSIP_STORE_MAJOR_VERSION = (0 << 5)
GOSSIP_STORE_MAJOR_VERSION_MASK = 0xE0
GOSSIP_STORE_LEN_DELETED_BIT = 0x80000000 GOSSIP_STORE_LEN_DELETED_BIT = 0x80000000
GOSSIP_STORE_LEN_PUSH_BIT = 0x40000000 GOSSIP_STORE_LEN_PUSH_BIT = 0x40000000
GOSSIP_STORE_LEN_RATELIMIT_BIT = 0x20000000 GOSSIP_STORE_LEN_RATELIMIT_BIT = 0x20000000
GOSSIP_STORE_LEN_MASK = (~(GOSSIP_STORE_LEN_PUSH_BIT GOSSIP_STORE_LEN_MASK = (0x0000FFFF)
| GOSSIP_STORE_LEN_DELETED_BIT
| GOSSIP_STORE_LEN_RATELIMIT_BIT))
# These duplicate constants in lightning/gossipd/gossip_store_wiregen.h # These duplicate constants in lightning/gossipd/gossip_store_wiregen.h
WIRE_GOSSIP_STORE_PRIVATE_CHANNEL = 4104 WIRE_GOSSIP_STORE_PRIVATE_CHANNEL = 4104
@@ -174,7 +173,7 @@ class Gossmap(object):
self.channels: Dict[ShortChannelId, GossmapChannel] = {} self.channels: Dict[ShortChannelId, GossmapChannel] = {}
self._last_scid: Optional[str] = None self._last_scid: Optional[str] = None
version = self.store_file.read(1)[0] version = self.store_file.read(1)[0]
if version not in GOSSIP_STORE_VERSIONS: if (version & GOSSIP_STORE_MAJOR_VERSION_MASK) != GOSSIP_STORE_MAJOR_VERSION:
raise ValueError("Invalid gossip store version {}".format(version)) raise ValueError("Invalid gossip store version {}".format(version))
self.bytes_read = 1 self.bytes_read = 1
self.refresh() self.refresh()

View File

@@ -155,7 +155,7 @@ int main(int argc, char *argv[])
} else } else
outfd = STDOUT_FILENO; outfd = STDOUT_FILENO;
version = GOSSIP_STORE_VERSION; version = ((0 << 5) | 10);
if (!write_all(outfd, &version, sizeof(version))) if (!write_all(outfd, &version, sizeof(version)))
err(1, "Writing version"); err(1, "Writing version");

View File

@@ -10,6 +10,10 @@
#include <unistd.h> #include <unistd.h>
#include <wire/peer_wire.h> #include <wire/peer_wire.h>
/* Current versions we support */
#define GSTORE_MAJOR 0
#define GSTORE_MINOR 10
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int fd; int fd;
@@ -43,11 +47,19 @@ int main(int argc, char *argv[])
if (read(fd, &version, sizeof(version)) != sizeof(version)) if (read(fd, &version, sizeof(version)) != sizeof(version))
errx(1, "Empty file"); errx(1, "Empty file");
if (version != GOSSIP_STORE_VERSION) if (GOSSIP_STORE_MAJOR_VERSION(version) != GSTORE_MAJOR)
warnx("UNSUPPORTED GOSSIP VERSION %u (expected %u)", errx(1, "Unsupported major gossip_version %u (expected %u)",
version, GOSSIP_STORE_VERSION); GOSSIP_STORE_MAJOR_VERSION(version), GSTORE_MAJOR);
printf("GOSSIP VERSION %u\n", version); /* Unsupported minor just means we might not understand all fields,
* or all flags. */
if (GOSSIP_STORE_MINOR_VERSION(version) != GSTORE_MINOR)
warnx("UNKNOWN GOSSIP minor VERSION %u (expected %u)",
GOSSIP_STORE_MINOR_VERSION(version), GSTORE_MINOR);
printf("GOSSIP VERSION %u/%u\n",
GOSSIP_STORE_MINOR_VERSION(version),
GOSSIP_STORE_MAJOR_VERSION(version));
off = 1; off = 1;
while (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)) { while (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr)) {

View File

@@ -17,6 +17,8 @@
#include <wire/peer_wire.h> #include <wire/peer_wire.h>
#define GOSSIP_STORE_TEMP_FILENAME "gossip_store.tmp" #define GOSSIP_STORE_TEMP_FILENAME "gossip_store.tmp"
/* We write it as major version 0, minor version 10 */
#define GOSSIP_STORE_VER ((0 << 5) | 10)
struct gossip_store { struct gossip_store {
/* This is false when we're loading */ /* This is false when we're loading */
@@ -123,7 +125,7 @@ static u32 gossip_store_compact_offline(struct routing_state *rstate)
int old_fd, new_fd; int old_fd, new_fd;
u64 oldlen, newlen; u64 oldlen, newlen;
struct gossip_hdr hdr; struct gossip_hdr hdr;
u8 oldversion, version = GOSSIP_STORE_VERSION; u8 oldversion, version = GOSSIP_STORE_VER;
struct stat st; struct stat st;
old_fd = open(GOSSIP_STORE_FILENAME, O_RDWR); old_fd = open(GOSSIP_STORE_FILENAME, O_RDWR);
@@ -267,11 +269,11 @@ struct gossip_store *gossip_store_new(struct routing_state *rstate,
if (read(gs->fd, &gs->version, sizeof(gs->version)) if (read(gs->fd, &gs->version, sizeof(gs->version))
== sizeof(gs->version)) { == sizeof(gs->version)) {
/* Version match? All good */ /* Version match? All good */
if (gs->version == GOSSIP_STORE_VERSION) if (gs->version == GOSSIP_STORE_VER)
return gs; return gs;
status_unusual("Gossip store version %u not %u: removing", status_unusual("Gossip store version %u not %u: removing",
gs->version, GOSSIP_STORE_VERSION); gs->version, GOSSIP_STORE_VER);
if (ftruncate(gs->fd, 0) != 0) if (ftruncate(gs->fd, 0) != 0)
status_failed(STATUS_FAIL_INTERNAL_ERROR, status_failed(STATUS_FAIL_INTERNAL_ERROR,
"Truncating store: %s", strerror(errno)); "Truncating store: %s", strerror(errno));
@@ -282,7 +284,7 @@ struct gossip_store *gossip_store_new(struct routing_state *rstate,
strerror(errno)); strerror(errno));
} }
/* Empty file, write version byte */ /* Empty file, write version byte */
gs->version = GOSSIP_STORE_VERSION; gs->version = GOSSIP_STORE_VER;
if (write(gs->fd, &gs->version, sizeof(gs->version)) if (write(gs->fd, &gs->version, sizeof(gs->version))
!= sizeof(gs->version)) != sizeof(gs->version))
status_failed(STATUS_FAIL_INTERNAL_ERROR, status_failed(STATUS_FAIL_INTERNAL_ERROR,

View File

@@ -335,7 +335,7 @@ int main(int argc, char *argv[])
int store_fd; int store_fd;
struct payment *p; struct payment *p;
struct payment_modifier **mods; struct payment_modifier **mods;
char gossip_version = GOSSIP_STORE_VERSION; char gossip_version = 10;
char *gossipfilename; char *gossipfilename;
common_setup(argv[0]); common_setup(argv[0]);