From 1490ae4cf6ab16d058baf1e813e42ba7119e80f2 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 2 Feb 2021 11:05:23 +1030 Subject: [PATCH] common: support transitory local map additions to gossmap. This will let us add routehints to the map and use dijkstra etc like normal. Signed-off-by: Rusty Russell --- common/gossmap.c | 222 +++++++++++++++++- common/gossmap.h | 29 +++ common/test/run-gossmap-fp16.c | 7 - common/test/run-gossmap_local.c | 402 ++++++++++++++++++++++++++++++++ 4 files changed, 645 insertions(+), 15 deletions(-) create mode 100644 common/test/run-gossmap_local.c diff --git a/common/gossmap.c b/common/gossmap.c index 9afbffef5..8947cb50a 100644 --- a/common/gossmap.c +++ b/common/gossmap.c @@ -80,20 +80,28 @@ struct gossmap { /* Linked list of freed ones, if any. */ u32 freed_nodes, freed_chans; + + /* local messages (tal array) */ + u8 *local; }; /* Accessors for the gossmap */ static void map_copy(const struct gossmap *map, size_t offset, void *dst, size_t len) { - assert(offset < map->map_size); - assert(offset + len <= map->map_size); - if (map->mmap) - memcpy(dst, map->mmap + offset, len); - else { - /* Yeah, we'll crash on I/O errors. */ - if (pread(map->fd, dst, len, offset) != len) - abort(); + if (offset >= map->map_size) { + size_t localoff = offset - map->map_size; + assert(localoff + len <= tal_bytelen(map->local)); + memcpy(dst, map->local + localoff, len); + } else { + assert(offset + len <= map->map_size); + if (map->mmap) + memcpy(dst, map->mmap + offset, len); + else { + /* Yeah, we'll crash on I/O errors. */ + if (pread(map->fd, dst, len, offset) != len) + abort(); + } } } @@ -604,6 +612,9 @@ static bool load_gossip_store(struct gossmap *map) if (map->fd < 0) return false; + /* Start with empty local map */ + map->local = tal_arr(map, u8, 0); + fstat(map->fd, &st); map->st_dev = st.st_dev; map->st_ino = st.st_ino; @@ -650,10 +661,70 @@ static void destroy_map(struct gossmap *map) free(map->node_arr[i].chan_idxs); } +void gossmap_local_cleanup(struct gossmap *map) +{ + size_t off, msglen; + + /* We need to undo all the local additions and updates. + * FIXME: local updates may have overriden previous ones, but + * we simply mark them disabled (they're usually used to + * update local-only channels anyway). */ + for (off = 0; + off < tal_bytelen(map->local); + off += sizeof(msglen) + msglen) { + struct short_channel_id scid; + struct gossmap_chan *chan; + be64 bescid; + be16 type; + + /* Local cursor */ + u8 *p = map->local + off; + memcpy(&msglen, p, sizeof(msglen)); + p += sizeof(msglen); + memcpy(&type, p, sizeof(type)); + p += sizeof(type); + + if (type == CPU_TO_BE16(WIRE_CHANNEL_ANNOUNCEMENT)) { + /* Get scid from inside announcement. */ + be16 flen; + p += 64 * 4; + memcpy(&flen, p, sizeof(flen)); + p += sizeof(flen) + be16_to_cpu(flen) + 32; + memcpy(&bescid, p, sizeof(bescid)); + scid.u64 = be64_to_cpu(bescid); + + chan = gossmap_find_chan(map, &scid); + if (chan) + gossmap_remove_chan(map, chan); + } else { + u8 channel_flags; + assert(type == CPU_TO_BE16(WIRE_CHANNEL_UPDATE)); + p += 64 + 32; + memcpy(&bescid, p, sizeof(bescid)); + p += sizeof(bescid); + scid.u64 = be64_to_cpu(bescid); + p += 4 + 1; + channel_flags = *p; + + chan = gossmap_find_chan(map, &scid); + /* May have removed it when we processed + * announce above */ + if (chan) + chan->half[channel_flags & 1].enabled = false; + } + } + + /* Now zero out map */ + tal_resize(&map->local, 0); +} + bool gossmap_refresh(struct gossmap *map) { struct stat st; + /* You must clean local updates before this. */ + assert(tal_bytelen(map->local) == 0); + /* If file has changed, move to it. */ if (stat(map->fname, &st) != 0) err(1, "statting %s", map->fname); @@ -691,6 +762,141 @@ struct gossmap *gossmap_load(const tal_t *ctx, const char *filename) return map; } +/* Add something to the local map, return offset it was added at. */ +static size_t insert_local_goss(struct gossmap *map, const u8 *msg TAKES) +{ + size_t oldlen = tal_bytelen(map->local); + size_t msglen = tal_bytelen(msg); + + /* We store length, then the msg. */ + tal_resize(&map->local, oldlen + sizeof(msglen) + msglen); + memcpy(map->local + oldlen, &msglen, sizeof(msglen)); + memcpy(map->local + oldlen + sizeof(msglen), msg, msglen); + if (taken(msg)) + tal_free(msg); + + return map->map_size + oldlen + sizeof(msglen); +} + +void gossmap_local_addchan(struct gossmap *map, + const struct node_id *n1, + const struct node_id *n2, + const struct short_channel_id *scid, + const u8 *features) +{ + be16 be16; + be64 be64; + size_t off; + u8 *fake_ann = tal_arr(NULL, u8, + 2 + 64 * 4 + 2 + tal_bytelen(features) + + 32 + 8 + 33 + 33); + off = 0; + + /* Set type to be kosher. */ + be16 = CPU_TO_BE16(WIRE_CHANNEL_ANNOUNCEMENT); + memcpy(fake_ann + off, &be16, sizeof(be16)); + off += sizeof(be16); + + /* Skip sigs */ + off += 64 * 4; + + /* Set length and features */ + be16 = cpu_to_be16(tal_bytelen(features)); + memcpy(fake_ann + off, &be16, sizeof(be16)); + off += sizeof(be16); + memcpy(fake_ann + off, features, tal_bytelen(features)); + off += tal_bytelen(features); + + /* Skip chain_hash */ + off += 32; + + /* Set scid */ + be64 = be64_to_cpu(scid->u64); + memcpy(fake_ann + off, &be64, sizeof(be64)); + off += sizeof(be64); + + /* set node_ids */ + memcpy(fake_ann + off, n1->k, sizeof(n1->k)); + off += sizeof(n1->k); + memcpy(fake_ann + off, n2->k, sizeof(n2->k)); + off += sizeof(n2->k); + + assert(off == tal_bytelen(fake_ann)); + + add_channel(map, insert_local_goss(map, take(fake_ann))); +} + +/* Insert a local-only channel_update (not in the mmap'ed gossmap, + * cleared on refresh). Must exist! */ +void gossmap_local_updatechan(struct gossmap *map, + const struct short_channel_id *scid, + struct amount_msat htlc_min, + struct amount_msat htlc_max, + u32 base_fee, + u32 proportional_fee, + u16 delay, + bool enabled, + int dir) +{ + be16 be16; + be32 be32; + be64 be64; + size_t off; + u8 *fake_upd = tal_arr(NULL, u8, + 2 + 64 + 32 + 8 + 4 + 1 + 1 + 2 + 8 + 4 + 4 + 8); + + off = 0; + + /* Set type to be kosher. */ + be16 = CPU_TO_BE16(WIRE_CHANNEL_UPDATE); + memcpy(fake_upd + off, &be16, sizeof(be16)); + off += sizeof(be16); + + /* Skip signature and chainhash */ + off += 64 + 32; + + /* Set scid */ + be64 = be64_to_cpu(scid->u64); + memcpy(fake_upd + off, &be64, sizeof(be64)); + off += sizeof(be64); + + /* Skip timestamp. */ + off += 4; + + /* We support htlc_maximum_msat. */ + fake_upd[off] = 1; + off += 1; + + /* Bottom bit is direction, second is disable. */ + fake_upd[off] = dir; + if (!enabled) + fake_upd[off] |= 2; + off += 1; + + be16 = cpu_to_be16(delay); + memcpy(fake_upd + off, &be16, sizeof(be16)); + off += sizeof(be16); + + be64 = cpu_to_be64(htlc_min.millisatoshis); /* Raw: endian */ + memcpy(fake_upd + off, &be64, sizeof(be64)); + off += sizeof(be64); + + be32 = cpu_to_be32(base_fee); + memcpy(fake_upd + off, &be32, sizeof(be32)); + off += sizeof(be32); + + be32 = cpu_to_be32(proportional_fee); + memcpy(fake_upd + off, &be32, sizeof(be32)); + off += sizeof(be32); + + be64 = cpu_to_be64(htlc_max.millisatoshis); /* Raw: endian */ + memcpy(fake_upd + off, &be64, sizeof(be64)); + off += sizeof(be64); + + assert(off == tal_bytelen(fake_upd)); + update_channel(map, insert_local_goss(map, take(fake_upd))); +} + void gossmap_node_get_id(const struct gossmap *map, const struct gossmap_node *node, struct node_id *id) diff --git a/common/gossmap.h b/common/gossmap.h index 6dae347f7..494440f5e 100644 --- a/common/gossmap.h +++ b/common/gossmap.h @@ -2,6 +2,7 @@ #define LIGHTNING_COMMON_GOSSMAP_H #include "config.h" #include +#include #include #include #include @@ -42,6 +43,34 @@ struct gossmap *gossmap_load(const tal_t *ctx, const char *filename); * was updated. Note: this can scramble node and chan indexes! */ bool gossmap_refresh(struct gossmap *map); +/* Insert a local-only channel (not in the mmap'ed gossmap, cleared on + * refresh). */ +void gossmap_local_addchan(struct gossmap *map, + const struct node_id *n1, + const struct node_id *n2, + const struct short_channel_id *scid, + const u8 *features) + NON_NULL_ARGS(1,2,3,4); + +/* Insert a local-only channel_update (not in the mmap'ed gossmap, + * cleared on refresh). Must exist, and usually should be a local + * channel (otherwise channel will be disabled on + * gossmap_local_addchan!) */ +void gossmap_local_updatechan(struct gossmap *map, + const struct short_channel_id *scid, + struct amount_msat htlc_min, + struct amount_msat htlc_max, + u32 base_fee, + u32 proportional_fee, + u16 delay, + bool enabled, + int dir) + NO_NULL_ARGS; + +/* Remove all local-only changes. Must be done before calling + * gossmap_refresh! */ +void gossmap_local_cleanup(struct gossmap *map); + /* Each channel has a unique (low) index. */ u32 gossmap_node_idx(const struct gossmap *map, const struct gossmap_node *node); u32 gossmap_chan_idx(const struct gossmap *map, const struct gossmap_chan *chan); diff --git a/common/test/run-gossmap-fp16.c b/common/test/run-gossmap-fp16.c index cc7e84d70..659a7af6d 100644 --- a/common/test/run-gossmap-fp16.c +++ b/common/test/run-gossmap-fp16.c @@ -74,9 +74,6 @@ u8 fromwire_u8(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) /* 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 siphash_seed */ -const struct siphash_seed *siphash_seed(void) -{ fprintf(stderr, "siphash_seed 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(); } @@ -108,10 +105,6 @@ void towire_u8(u8 **pptr UNNEEDED, u8 v UNNEEDED) /* 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 type_to_string_ */ -const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED, - union printable_types u UNNEEDED) -{ fprintf(stderr, "type_to_string_ called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ int main(void) diff --git a/common/test/run-gossmap_local.c b/common/test/run-gossmap_local.c new file mode 100644 index 000000000..dd3222cae --- /dev/null +++ b/common/test/run-gossmap_local.c @@ -0,0 +1,402 @@ +/* Test local modifications to gossmap */ +#include "../fp16.c" +#include "../gossmap.c" +#include "../node_id.c" +#include "../pseudorand.c" +#include +#include +#include +#include +#include + +/* 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_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 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_amount_sat */ +struct amount_sat fromwire_amount_sat(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_amount_sat 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_fail */ +void *fromwire_fail(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_fail 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 towire */ +void towire(u8 **pptr UNNEEDED, const void *data UNNEEDED, size_t len UNNEEDED) +{ fprintf(stderr, "towire called!\n"); abort(); } +/* Generated stub for towire_amount_sat */ +void towire_amount_sat(u8 **pptr UNNEEDED, const struct amount_sat sat UNNEEDED) +{ fprintf(stderr, "towire_amount_sat 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_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 type_to_string_ */ +const char *type_to_string_(const tal_t *ctx UNNEEDED, const char *typename UNNEEDED, + union printable_types u UNNEEDED) +{ fprintf(stderr, "type_to_string_ called!\n"); abort(); } +/* AUTOGENERATED MOCKS END */ + +/* Canned gossmap, taken from tests/test_gossip.py's + * setup_gossip_store_test via od -v -Anone -tx1 < /tmp/ltests-kaf30pn0/test_gossip_store_compact_noappend_1/lightning-2/regtest/gossip_store + */ +static u8 canned_map[] = { + 0x09, 0x80, 0x00, 0x01, 0xbc, 0x09, 0x8b, 0x67, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x0f, 0x42, 0x40, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x22, 0x6e + , 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f + , 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67 + , 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x2d, 0x22, 0x36, 0x20, 0xa3, 0x59, 0xa4, 0x7f, 0xf7, 0xf7 + , 0xac, 0x44, 0x7c, 0x85, 0xc4, 0x6c, 0x92, 0x3d, 0xa5, 0x33, 0x89, 0x22, 0x1a, 0x00, 0x54, 0xc1 + , 0x1c, 0x1e, 0x3c, 0xa3, 0x1d, 0x59, 0x03, 0x5d, 0x2b, 0x11, 0x92, 0xdf, 0xba, 0x13, 0x4e, 0x10 + , 0xe5, 0x40, 0x87, 0x5d, 0x36, 0x6e, 0xbc, 0x8b, 0xc3, 0x53, 0xd5, 0xaa, 0x76, 0x6b, 0x80, 0xc0 + , 0x90, 0xb3, 0x9c, 0x3a, 0x5d, 0x88, 0x5d, 0x03, 0x1b, 0x84, 0xc5, 0x56, 0x7b, 0x12, 0x64, 0x40 + , 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, 0xd7, 0x1e, 0x18, 0x34, 0x60, 0x48, 0x19, 0xff + , 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f, 0x03, 0x1b, 0x84, 0xc5, 0x56, 0x7b, 0x12, 0x64 + , 0x40, 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, 0xd7, 0x1e, 0x18, 0x34, 0x60, 0x48, 0x19 + , 0xff, 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f, 0x80, 0x00, 0x00, 0x8e, 0x33, 0x3b, 0x90 + , 0x12, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x8a, 0x01, 0x02, 0x14, 0xb8, 0x21, 0x42, 0x7d + , 0x40, 0x89, 0x60, 0x71, 0x05, 0x8d, 0xe4, 0x50, 0x8e, 0xc3, 0x87, 0x6f, 0xa6, 0x4b, 0x19, 0xe4 + , 0x81, 0xc5, 0x5f, 0xb7, 0x04, 0xb8, 0x74, 0x08, 0x0b, 0x40, 0x5a, 0x74, 0x89, 0xbc, 0x63, 0x24 + , 0x27, 0x93, 0x4d, 0xfc, 0x1a, 0x72, 0xe4, 0xc7, 0xf8, 0x9b, 0xc1, 0x6b, 0xad, 0x9b, 0x04, 0x2e + , 0x14, 0xa4, 0xe9, 0xf5, 0x80, 0xf1, 0x02, 0x8f, 0x50, 0xf3, 0x2c, 0x06, 0x22, 0x6e, 0x46, 0x11 + , 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e + , 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67, 0x00, 0x00 + , 0x01, 0x00, 0x00, 0x60, 0x17, 0x53, 0x70, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x3b + , 0x02, 0x33, 0x80, 0x80, 0x00, 0x00, 0x8e, 0x3e, 0xa2, 0x81, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10 + , 0x06, 0x00, 0x8a, 0x01, 0x02, 0x01, 0x0a, 0xb3, 0x54, 0x3f, 0xd2, 0xa9, 0xf5, 0x30, 0x0f, 0x60 + , 0x7d, 0xf9, 0xf1, 0xdd, 0x63, 0x62, 0xd8, 0xde, 0xe2, 0x94, 0xe4, 0x68, 0xc9, 0x5c, 0xe8, 0x32 + , 0x9b, 0x14, 0xd9, 0xf8, 0x6a, 0x23, 0x3a, 0x67, 0x10, 0x09, 0x64, 0x96, 0x40, 0xcb, 0x0b, 0xf5 + , 0xec, 0xe6, 0xba, 0x8e, 0x77, 0xb4, 0x6a, 0xf1, 0x39, 0x94, 0x86, 0xb0, 0x69, 0xd5, 0x17, 0x67 + , 0x83, 0xda, 0xfa, 0x49, 0x63, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12 + , 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7 + , 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x17, 0x53 + , 0x70, 0x01, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33, 0x80, 0x00, 0x00, 0x00 + , 0x0a, 0x01, 0xf0, 0xcb, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x10, 0x07, 0x00, 0x00, 0x67, 0x00, 0x00 + , 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0xb0, 0xd2, 0xfa, 0x8f, 0x8d, 0x60, 0x17, 0x53, 0x70, 0x01 + , 0x00, 0x24, 0xfd, 0xae, 0x1a, 0xc8, 0x40, 0xa7, 0x33, 0x22, 0xe1, 0x45, 0x7e, 0x76, 0xb8, 0x86 + , 0xdd, 0x17, 0x8c, 0xd4, 0x49, 0x4b, 0x14, 0x3f, 0x81, 0xd4, 0xd4, 0xfa, 0xa7, 0x16, 0x17, 0xd2 + , 0x51, 0x33, 0x9e, 0xcb, 0x0e, 0x22, 0x1c, 0xf6, 0x02, 0x3a, 0x2e, 0x3e, 0x94, 0xf8, 0xae, 0xdb + , 0xee, 0x47, 0x23, 0xda, 0x5c, 0x35, 0x51, 0x57, 0xd8, 0xe4, 0x67, 0x2b, 0x46, 0x82, 0x5e, 0xc7 + , 0x98, 0x51, 0xb3, 0xb0, 0x1a, 0x2c, 0x72, 0x3f, 0x9b, 0xf5, 0xdb, 0xa8, 0xe3, 0x5f, 0x8b, 0x47 + , 0x9d, 0x9c, 0xd9, 0x73, 0xae, 0xc5, 0x0c, 0xca, 0x08, 0xfb, 0x97, 0x57, 0xb5, 0x21, 0x92, 0x05 + , 0x18, 0x42, 0x2d, 0x68, 0x19, 0x70, 0x76, 0x30, 0x61, 0x24, 0xff, 0xa5, 0xb6, 0x58, 0xa2, 0xe2 + , 0xb3, 0x68, 0x93, 0x37, 0xda, 0x6c, 0x3c, 0xcc, 0x5e, 0xf7, 0x3b, 0x51, 0x29, 0x64, 0x30, 0xbe + , 0x2a, 0x19, 0x38, 0x88, 0x9d, 0xda, 0x2a, 0xd1, 0xcb, 0x5e, 0x33, 0xdb, 0x75, 0xcf, 0x2e, 0x0e + , 0xfd, 0xbd, 0x38, 0xce, 0x01, 0x54, 0x62, 0x30, 0xb4, 0xdd, 0xdc, 0x7f, 0x67, 0xca, 0xf8, 0x39 + , 0x10, 0x02, 0x8a, 0x05, 0x3b, 0x76, 0x62, 0x72, 0xd2, 0x84, 0x71, 0x19, 0x19, 0x30, 0x92, 0xfa + , 0x2a, 0x1f, 0xdf, 0x71, 0xe3, 0xd8, 0x4a, 0x56, 0xd0, 0xe4, 0x35, 0xfe, 0x5d, 0x4a, 0x5b, 0x5b + , 0x90, 0x05, 0x28, 0xe4, 0x3b, 0x24, 0x13, 0x46, 0x99, 0x45, 0xc4, 0x92, 0x14, 0x7d, 0x43, 0x21 + , 0x06, 0x50, 0x51, 0xf8, 0x5b, 0x92, 0xb5, 0xb0, 0x90, 0xb1, 0xd7, 0x0d, 0x5a, 0xac, 0xfe, 0xf4 + , 0xe2, 0x70, 0x3e, 0x97, 0x42, 0x25, 0xfb, 0x21, 0x15, 0xf6, 0xb9, 0x32, 0xc8, 0xc3, 0x03, 0xbd + , 0x7a, 0xbd, 0x86, 0xf7, 0xcd, 0x64, 0xe6, 0x1a, 0x7f, 0x5a, 0x04, 0x7a, 0x22, 0xad, 0x7c, 0xfc + , 0x6a, 0x00, 0x00, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43 + , 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1 + , 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x2d, 0x22, 0x36, 0x20 + , 0xa3, 0x59, 0xa4, 0x7f, 0xf7, 0xf7, 0xac, 0x44, 0x7c, 0x85, 0xc4, 0x6c, 0x92, 0x3d, 0xa5, 0x33 + , 0x89, 0x22, 0x1a, 0x00, 0x54, 0xc1, 0x1c, 0x1e, 0x3c, 0xa3, 0x1d, 0x59, 0x03, 0x5d, 0x2b, 0x11 + , 0x92, 0xdf, 0xba, 0x13, 0x4e, 0x10, 0xe5, 0x40, 0x87, 0x5d, 0x36, 0x6e, 0xbc, 0x8b, 0xc3, 0x53 + , 0xd5, 0xaa, 0x76, 0x6b, 0x80, 0xc0, 0x90, 0xb3, 0x9c, 0x3a, 0x5d, 0x88, 0x5d, 0x02, 0xd5, 0x95 + , 0xae, 0x92, 0xb3, 0x54, 0x4c, 0x32, 0x50, 0xfb, 0x77, 0x2f, 0x21, 0x4a, 0xd8, 0xd4, 0xc5, 0x14 + , 0x25, 0x03, 0x37, 0x40, 0xa5, 0xbc, 0xc3, 0x57, 0x19, 0x0a, 0xdd, 0x6d, 0x7e, 0x7a, 0x02, 0xd6 + , 0x06, 0x3d, 0x02, 0x26, 0x91, 0xb2, 0x49, 0x0a, 0xb4, 0x54, 0xde, 0xe7, 0x3a, 0x57, 0xc6, 0xff + , 0x5d, 0x30, 0x83, 0x52, 0xb4, 0x61, 0xec, 0xe6, 0x9f, 0x3c, 0x28, 0x4f, 0x2c, 0x24, 0x12, 0x00 + , 0x00, 0x00, 0x0a, 0x91, 0x11, 0x83, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x0f, 0x42, 0x40, 0xc0, 0x00, 0x00, 0x8a, 0xf3, 0x48, 0xd5, 0xb3, 0x60, 0x17, 0x53 + , 0x70, 0x01, 0x02, 0x14, 0xb8, 0x21, 0x42, 0x7d, 0x40, 0x89, 0x60, 0x71, 0x05, 0x8d, 0xe4, 0x50 + , 0x8e, 0xc3, 0x87, 0x6f, 0xa6, 0x4b, 0x19, 0xe4, 0x81, 0xc5, 0x5f, 0xb7, 0x04, 0xb8, 0x74, 0x08 + , 0x0b, 0x40, 0x5a, 0x74, 0x89, 0xbc, 0x63, 0x24, 0x27, 0x93, 0x4d, 0xfc, 0x1a, 0x72, 0xe4, 0xc7 + , 0xf8, 0x9b, 0xc1, 0x6b, 0xad, 0x9b, 0x04, 0x2e, 0x14, 0xa4, 0xe9, 0xf5, 0x80, 0xf1, 0x02, 0x8f + , 0x50, 0xf3, 0x2c, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43 + , 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1 + , 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x17, 0x53, 0x70, 0x01 + , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 + , 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33, 0x80, 0xc0, 0x00, 0x00, 0x8a, 0xfe + , 0xd1, 0xc4, 0x47, 0x60, 0x17, 0x53, 0x70, 0x01, 0x02, 0x01, 0x0a, 0xb3, 0x54, 0x3f, 0xd2, 0xa9 + , 0xf5, 0x30, 0x0f, 0x60, 0x7d, 0xf9, 0xf1, 0xdd, 0x63, 0x62, 0xd8, 0xde, 0xe2, 0x94, 0xe4, 0x68 + , 0xc9, 0x5c, 0xe8, 0x32, 0x9b, 0x14, 0xd9, 0xf8, 0x6a, 0x23, 0x3a, 0x67, 0x10, 0x09, 0x64, 0x96 + , 0x40, 0xcb, 0x0b, 0xf5, 0xec, 0xe6, 0xba, 0x8e, 0x77, 0xb4, 0x6a, 0xf1, 0x39, 0x94, 0x86, 0xb0 + , 0x69, 0xd5, 0x17, 0x67, 0x83, 0xda, 0xfa, 0x49, 0x63, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b + , 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a + , 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67, 0x00, 0x00, 0x01, 0x00 + , 0x00, 0x60, 0x17, 0x53, 0x70, 0x01, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33 + , 0x80, 0x40, 0x00, 0x00, 0x9b, 0x4f, 0x9d, 0xb7, 0xb9, 0x60, 0x17, 0x53, 0x77, 0x01, 0x01, 0x6e + , 0x99, 0xf5, 0x9c, 0x1f, 0x21, 0x8d, 0x4a, 0x2b, 0x6e, 0x36, 0x9a, 0x95, 0x20, 0x76, 0x2c, 0x27 + , 0xfb, 0xa8, 0xb1, 0x82, 0x1f, 0x64, 0x34, 0x93, 0x91, 0x9c, 0xeb, 0xfa, 0x40, 0x50, 0x73, 0x4d + , 0x00, 0xce, 0x10, 0xbf, 0x3f, 0x42, 0x3e, 0x56, 0x8f, 0xf8, 0xe0, 0x59, 0x58, 0xb5, 0xbd, 0xc5 + , 0x00, 0x82, 0xe3, 0x27, 0x92, 0x5b, 0xf8, 0x4f, 0x2c, 0x39, 0xec, 0x49, 0x3b, 0x07, 0x5e, 0x00 + , 0x0d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x22, 0xaa, 0xa2, 0x60, 0x17 + , 0x53, 0x77, 0x02, 0x2d, 0x22, 0x36, 0x20, 0xa3, 0x59, 0xa4, 0x7f, 0xf7, 0xf7, 0xac, 0x44, 0x7c + , 0x85, 0xc4, 0x6c, 0x92, 0x3d, 0xa5, 0x33, 0x89, 0x22, 0x1a, 0x00, 0x54, 0xc1, 0x1c, 0x1e, 0x3c + , 0xa3, 0x1d, 0x59, 0x02, 0x2d, 0x22, 0x53, 0x49, 0x4c, 0x45, 0x4e, 0x54, 0x41, 0x52, 0x54, 0x49 + , 0x53, 0x54, 0x2d, 0x2d, 0x35, 0x36, 0x2d, 0x67, 0x64, 0x64, 0x31, 0x35, 0x33, 0x63, 0x38, 0x2d + , 0x6d, 0x6f, 0x64, 0x64, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x15, 0x33, 0x0c, 0x6b + , 0x60, 0x17, 0x53, 0x77, 0x01, 0x01, 0x0e, 0x07, 0xaf, 0xd2, 0x33, 0x19, 0x0e, 0x06, 0x01, 0x6d + , 0x57, 0x88, 0x4e, 0x66, 0xf8, 0x08, 0xd9, 0x65, 0x8a, 0x73, 0xfb, 0x1d, 0xe0, 0xad, 0xee, 0x47 + , 0xf8, 0x1c, 0xfc, 0xc3, 0xd2, 0xfd, 0x06, 0x3e, 0x5a, 0x05, 0x65, 0x72, 0x18, 0x61, 0xb8, 0x23 + , 0x04, 0x3d, 0x4b, 0x39, 0x79, 0xe0, 0x85, 0x38, 0xd2, 0x92, 0x14, 0x35, 0x32, 0xaa, 0x9f, 0xab + , 0x5f, 0x98, 0x2c, 0x53, 0xfe, 0x0d, 0x00, 0x0d, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 + , 0x00, 0x00, 0x22, 0xaa, 0xa2, 0x60, 0x17, 0x53, 0x77, 0x03, 0x5d, 0x2b, 0x11, 0x92, 0xdf, 0xba + , 0x13, 0x4e, 0x10, 0xe5, 0x40, 0x87, 0x5d, 0x36, 0x6e, 0xbc, 0x8b, 0xc3, 0x53, 0xd5, 0xaa, 0x76 + , 0x6b, 0x80, 0xc0, 0x90, 0xb3, 0x9c, 0x3a, 0x5d, 0x88, 0x5d, 0x03, 0x5d, 0x2b, 0x48, 0x4f, 0x50 + , 0x50, 0x49, 0x4e, 0x47, 0x46, 0x49, 0x52, 0x45, 0x2d, 0x33, 0x2d, 0x35, 0x36, 0x2d, 0x67, 0x64 + , 0x64, 0x31, 0x35, 0x33, 0x63, 0x38, 0x2d, 0x6d, 0x6f, 0x64, 0x64, 0x65, 0x64, 0x00, 0x00, 0x40 + , 0x00, 0x00, 0x8a, 0x22, 0x55, 0xdf, 0xb2, 0x60, 0x17, 0x53, 0x79, 0x01, 0x02, 0x3a, 0x2b, 0xe5 + , 0x81, 0x83, 0xa3, 0x1a, 0x49, 0x93, 0x89, 0x8d, 0xac, 0xa7, 0xb2, 0x2e, 0xc3, 0x94, 0x6c, 0xd1 + , 0xd6, 0xd0, 0x82, 0x34, 0xf3, 0x9c, 0x71, 0xa0, 0xd1, 0xdb, 0x3f, 0xcc, 0xfc, 0x53, 0xce, 0x8c + , 0x84, 0x3d, 0x14, 0x2c, 0x81, 0x4a, 0x07, 0xf0, 0x00, 0x03, 0x7a, 0x28, 0x10, 0xf4, 0xb9, 0x50 + , 0xb3, 0x22, 0x00, 0xdf, 0xc2, 0xc7, 0xfb, 0x6f, 0xf3, 0xfb, 0xf6, 0x94, 0x8e, 0x06, 0x22, 0x6e + , 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f + , 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x67 + , 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x17, 0x53, 0x79, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00 + , 0x00, 0x3b, 0x02, 0x33, 0x80, 0x00, 0x00, 0x01, 0xbc, 0x4d, 0x34, 0xb9, 0xcd, 0x00, 0x00, 0x00 + , 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x42, 0x40, 0x01, 0xb0, 0x01, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b + , 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91 + , 0x0f, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x2d, 0x22, 0x36, 0x20, 0xa3, 0x59 + , 0xa4, 0x7f, 0xf7, 0xf7, 0xac, 0x44, 0x7c, 0x85, 0xc4, 0x6c, 0x92, 0x3d, 0xa5, 0x33, 0x89, 0x22 + , 0x1a, 0x00, 0x54, 0xc1, 0x1c, 0x1e, 0x3c, 0xa3, 0x1d, 0x59, 0x02, 0x66, 0xe4, 0x59, 0x8d, 0x1d + , 0x3c, 0x41, 0x5f, 0x57, 0x2a, 0x84, 0x88, 0x83, 0x0b, 0x60, 0xf7, 0xe7, 0x44, 0xed, 0x92, 0x35 + , 0xeb, 0x0b, 0x1b, 0xa9, 0x32, 0x83, 0xb3, 0x15, 0xc0, 0x35, 0x18, 0x03, 0x1b, 0x84, 0xc5, 0x56 + , 0x7b, 0x12, 0x64, 0x40, 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, 0xd7, 0x1e, 0x18, 0x34 + , 0x60, 0x48, 0x19, 0xff, 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f, 0x03, 0x1b, 0x84, 0xc5 + , 0x56, 0x7b, 0x12, 0x64, 0x40, 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, 0xd7, 0x1e, 0x18 + , 0x34, 0x60, 0x48, 0x19, 0xff, 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f, 0x80, 0x00, 0x00 + , 0x8e, 0xf4, 0xbc, 0x2c, 0x78, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x8a, 0x01, 0x02, 0x7a + , 0x2a, 0x3b, 0xad, 0x69, 0xf3, 0x8b, 0xba, 0xd2, 0xd3, 0xa2, 0x99, 0x66, 0x5f, 0x2d, 0x14, 0xc2 + , 0xca, 0xc2, 0xf4, 0x84, 0x97, 0x21, 0x93, 0x2f, 0xfd, 0x44, 0x19, 0xf6, 0xfa, 0x7f, 0x21, 0x3c + , 0x61, 0x45, 0x1e, 0x67, 0xfd, 0x5f, 0x9e, 0xee, 0x35, 0x03, 0xda, 0x96, 0xc3, 0x37, 0x2b, 0xfd + , 0x99, 0xb4, 0xdb, 0x0b, 0x6e, 0xa3, 0xdc, 0x8e, 0xad, 0x64, 0xf5, 0x9a, 0x4f, 0x5f, 0xae, 0x06 + , 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28 + , 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00 + , 0x00, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x01, 0x60, 0x17, 0x53, 0x7a, 0x01, 0x00, 0x00, 0x06, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00 + , 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33, 0x80, 0x80, 0x00, 0x00, 0x8e, 0xc3, 0xd8, 0xfd, 0x83, 0x00 + , 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x8a, 0x01, 0x02, 0x17, 0xdf, 0xc0, 0xb6, 0x5f, 0x8f, 0x42 + , 0x50, 0xe1, 0x4d, 0x35, 0xe7, 0x57, 0x2a, 0x07, 0x66, 0x8e, 0xa9, 0xe2, 0x61, 0xbf, 0xbc, 0x91 + , 0x5c, 0xa1, 0x80, 0x43, 0xcf, 0xb2, 0xba, 0x40, 0xf6, 0x2f, 0x0d, 0x37, 0x2c, 0xbc, 0x90, 0x96 + , 0x71, 0x00, 0x79, 0x35, 0xe3, 0xe8, 0x94, 0x90, 0x3c, 0x23, 0x8f, 0x5b, 0x8e, 0xcc, 0x39, 0x82 + , 0x2e, 0xdf, 0xbc, 0xcb, 0x66, 0xe9, 0xe4, 0x3e, 0xad, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b + , 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a + , 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x01, 0x00 + , 0x01, 0x60, 0x17, 0x53, 0x7a, 0x01, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33 + , 0x80, 0x40, 0x00, 0x00, 0x8a, 0x62, 0xdd, 0xe7, 0xfd, 0x60, 0x17, 0x53, 0x7b, 0x01, 0x02, 0x0b + , 0x5d, 0x1b, 0x41, 0x29, 0x50, 0xe7, 0x79, 0x39, 0x76, 0xc2, 0xd0, 0xbd, 0x54, 0x2c, 0x1c, 0x2b + , 0x78, 0x25, 0x8b, 0xd6, 0x2d, 0x70, 0x09, 0x73, 0xb7, 0x1c, 0xe4, 0xa2, 0x88, 0x98, 0xb6, 0x44 + , 0xa5, 0x33, 0x0a, 0x98, 0xdc, 0x63, 0xd1, 0x7b, 0x99, 0x49, 0xf2, 0x29, 0xe6, 0x6f, 0x58, 0xc6 + , 0xcb, 0x5a, 0x74, 0xa0, 0xdf, 0xa7, 0x74, 0x84, 0xd5, 0xe1, 0x0f, 0x03, 0x7d, 0xb6, 0xcd, 0x06 + , 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28 + , 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00 + , 0x00, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x60, 0x17, 0x53, 0x7b, 0x01, 0x01, 0x00, 0x06, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0xe8, 0x00 + , 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33, 0x80, 0x00, 0x00, 0x00, 0x8e, 0x76, 0xce, 0x94, 0x8e, 0x00 + , 0x00, 0x00, 0x00, 0x10, 0x06, 0x00, 0x8a, 0x01, 0x02, 0x25, 0x9f, 0x23, 0x6a, 0xbd, 0x5b, 0x6a + , 0x6b, 0x0f, 0x77, 0xaa, 0xce, 0xe9, 0xe1, 0x6d, 0xe3, 0xfb, 0xcd, 0x10, 0xa6, 0x2b, 0xb6, 0x15 + , 0x0c, 0xdf, 0xa1, 0xde, 0x79, 0x82, 0x99, 0xb1, 0x83, 0x47, 0x44, 0xf7, 0x20, 0xbc, 0x49, 0x11 + , 0x59, 0x58, 0x25, 0x63, 0x76, 0x01, 0x69, 0x27, 0xdc, 0xb3, 0x6c, 0x68, 0xc8, 0x5f, 0xae, 0x13 + , 0xaa, 0x46, 0xcc, 0xe9, 0x68, 0x03, 0x2a, 0xd3, 0x21, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b + , 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43, 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a + , 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1, 0x88, 0x91, 0x0f, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x01, 0x00 + , 0x01, 0x60, 0x17, 0x53, 0x7f, 0x01, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + , 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33 + , 0x80, 0x00, 0x00, 0x00, 0x8e, 0x4b, 0x8b, 0x0b, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x10, 0x06, 0x00 + , 0x8a, 0x01, 0x02, 0x7b, 0xd9, 0xa5, 0xe6, 0xfb, 0x26, 0xe2, 0xe1, 0xcb, 0x9a, 0x68, 0xdf, 0x50 + , 0x6c, 0x14, 0xcb, 0x5a, 0x2d, 0x12, 0x40, 0x94, 0x5e, 0xa4, 0x2d, 0xe9, 0x2a, 0x29, 0x48, 0xd5 + , 0xd0, 0x2e, 0xd9, 0x0c, 0xdc, 0xba, 0xe2, 0x74, 0x6e, 0xfb, 0xca, 0x77, 0xea, 0xe9, 0xa2, 0xce + , 0x9a, 0xa8, 0x42, 0x09, 0xa3, 0xa3, 0xae, 0x0e, 0x0f, 0xcc, 0xd3, 0x93, 0xd5, 0xcc, 0x38, 0x76 + , 0xd3, 0x58, 0xcc, 0x06, 0x22, 0x6e, 0x46, 0x11, 0x1a, 0x0b, 0x59, 0xca, 0xaf, 0x12, 0x60, 0x43 + , 0xeb, 0x5b, 0xbf, 0x28, 0xc3, 0x4f, 0x3a, 0x5e, 0x33, 0x2a, 0x1f, 0xc7, 0xb2, 0xb7, 0x3c, 0xf1 + , 0x88, 0x91, 0x0f, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x01, 0x00, 0x01, 0x60, 0x17, 0x53, 0x7f, 0x01 + , 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00 + , 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x33, 0x80 +}; + +int main(int argc, char *argv[]) +{ + int fd; + char gossfile[] = "/tmp/run-gossip_local.XXXXXX"; + struct gossmap *map; + struct node_id l1, l2, l3, l4; + struct short_channel_id scid23, scid12, scid_local; + struct gossmap_chan *chan; + + common_setup(argv[0]); + + fd = mkstemp(gossfile); + assert(write_all(fd, canned_map, sizeof(canned_map))); + + map = gossmap_load(tmpctx, gossfile); + assert(map); + + /* There is a public channel 2<->3 (103x1x0), and private + * 1<->2 (110x1x1). */ + assert(node_id_from_hexstr("0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518", 66, &l1)); + assert(node_id_from_hexstr("022d223620a359a47ff7f7ac447c85c46c923da53389221a0054c11c1e3ca31d59", 66, &l2)); + assert(node_id_from_hexstr("035d2b1192dfba134e10e540875d366ebc8bc353d5aa766b80c090b39c3a5d885d", 66, &l3)); + assert(gossmap_find_node(map, &l1)); + assert(gossmap_find_node(map, &l2)); + assert(gossmap_find_node(map, &l3)); + + assert(short_channel_id_from_str("103x1x0", 7, &scid23)); + assert(short_channel_id_from_str("110x1x1", 7, &scid12)); + assert(gossmap_find_chan(map, &scid23)); + assert(gossmap_find_chan(map, &scid12)); + + /* Now, let's add a new channel l1 -> l4. */ + assert(node_id_from_hexstr("0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199", 66, &l4)); + + assert(short_channel_id_from_str("111x1x1", 7, &scid_local)); + gossmap_local_addchan(map, &l1, &l4, &scid_local, NULL); + + assert(gossmap_find_node(map, &l4)); + chan = gossmap_find_chan(map, &scid_local); + + /* Exists, but no updates. */ + assert(!gossmap_chan_set(chan, 0)); + assert(!gossmap_chan_set(chan, 1)); + + /* Now update it. */ + gossmap_local_updatechan(map, &scid_local, + AMOUNT_MSAT(1), + AMOUNT_MSAT(100000), + 2, 3, 4, true, 0); + chan = gossmap_find_chan(map, &scid_local); + assert(gossmap_chan_set(chan, 0)); + assert(!gossmap_chan_set(chan, 1)); + + assert(chan->half[0].enabled); + assert(chan->half[0].htlc_min == u64_to_fp16(1, false)); + assert(chan->half[0].htlc_max == u64_to_fp16(100000, true)); + assert(chan->half[0].base_fee == 2); + assert(chan->half[0].proportional_fee == 3); + assert(chan->half[0].delay == 4); + + /* Cleanup leaves everything previous intact */ + gossmap_local_cleanup(map); + assert(!gossmap_find_node(map, &l4)); + assert(!gossmap_find_chan(map, &scid_local)); + assert(gossmap_find_node(map, &l1)); + assert(gossmap_find_node(map, &l2)); + assert(gossmap_find_node(map, &l3)); + assert(gossmap_find_chan(map, &scid23)); + assert(gossmap_find_chan(map, &scid12)); + + /* Now we can refresh. */ + assert(write(fd, "", 1) == 1); + gossmap_refresh(map); +}