From a1f964546275f960e6969f3d412d027e5949a618 Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 28 Nov 2019 12:17:57 +0100 Subject: [PATCH 1/4] connectd: setup chainparams We are going to signal the genesis block hash in the init message. --- connectd/connect_wire.csv | 1 + connectd/connectd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/connectd/connect_wire.csv b/connectd/connect_wire.csv index 9407889a1c7b..7f80adae0e17 100644 --- a/connectd/connect_wire.csv +++ b/connectd/connect_wire.csv @@ -4,6 +4,7 @@ #include msgtype,connectctl_init,2000 +msgdata,connectctl_init,chainparams,chainparams, msgdata,connectctl_init,id,node_id, msgdata,connectctl_init,num_wireaddrs,u16, msgdata,connectctl_init,wireaddrs,wireaddr_internal,num_wireaddrs diff --git a/connectd/connectd.c b/connectd/connectd.c index 9e0c234630e2..c256d0a333a6 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -1145,6 +1145,7 @@ static struct io_plan *connect_init(struct io_conn *conn, /* Fields which require allocation are allocated off daemon */ if (!fromwire_connectctl_init( daemon, msg, + &chainparams, &daemon->id, &proposed_wireaddr, &proposed_listen_announce, From 4ece097eedaca652049e485f08009cfde8aa43c9 Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 28 Nov 2019 15:10:08 +0100 Subject: [PATCH 2/4] bitcoin/chainparams: add an utility to retrieve chainparams for all networks --- bitcoin/chainparams.c | 9 +++++++++ bitcoin/chainparams.h | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/bitcoin/chainparams.c b/bitcoin/chainparams.c index 39e689fb990c..6147524d3adf 100644 --- a/bitcoin/chainparams.c +++ b/bitcoin/chainparams.c @@ -1,6 +1,7 @@ #include "chainparams.h" #include #include +#include #include /* Version codes for BIP32 extended keys in libwally-core. @@ -220,6 +221,14 @@ const struct chainparams *chainparams_for_network(const char *network_name) return NULL; } +const struct chainparams **chainparams_for_networks(const tal_t *ctx) +{ + const struct chainparams **params = tal_arr(ctx, const struct chainparams*, 0); + for (size_t i = 0; i < ARRAY_SIZE(networks); i++) + tal_arr_expand(¶ms, &networks[i]); + return params; +} + const struct chainparams *chainparams_by_chainhash(const struct bitcoin_blkid *chain_hash) { for (size_t i = 0; i < ARRAY_SIZE(networks); i++) { diff --git a/bitcoin/chainparams.h b/bitcoin/chainparams.h index 2feca23a8e36..e041a79a1f9d 100644 --- a/bitcoin/chainparams.h +++ b/bitcoin/chainparams.h @@ -46,6 +46,12 @@ struct chainparams { */ const struct chainparams *chainparams_for_network(const char *network_name); +/** + * chainparams_for_networks - Get blockchain parameters for all known networks, + * as a tal array. + */ +const struct chainparams **chainparams_for_networks(const tal_t *ctx); + /** * chainparams_by_bip173 - Helper to get a network by its bip173 name * From 54e6aa5aeff207ce5be1a4967fd32947e89ba612 Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 28 Nov 2019 15:11:07 +0100 Subject: [PATCH 3/4] connectd: add network to init message Changelog-Added: protocol: We now signal the network we are running on at init. --- connectd/peer_exchange_initmsg.c | 47 ++++++++++++++++++++++-- devtools/gossipwith.c | 2 +- lightningd/connect_control.c | 3 +- wire/extracted_peer_wire_csv | 3 ++ wire/test/Makefile | 1 + wire/test/run-peer-wire.c | 62 ++++++++++++++++---------------- 6 files changed, 81 insertions(+), 37 deletions(-) diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 514613ebe2d3..a9fd483ce9f1 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -27,6 +27,15 @@ struct peer { u8 *msg; }; +static bool contains_common_chain(struct bitcoin_blkid *chains) +{ + for (size_t i = 0; i < tal_count(chains); i++) { + if (bitcoin_blkid_eq(&chains[0], &chainparams->genesis_blockhash)) + return true; + } + return false; +} + /* Here in case we need to read another message. */ static struct io_plan *read_init(struct io_conn *conn, struct peer *peer); @@ -36,6 +45,7 @@ static struct io_plan *peer_init_received(struct io_conn *conn, u8 *msg = cryptomsg_decrypt_body(tmpctx, &peer->cs, peer->msg); u8 *globalfeatures, *features; int unsup; + struct tlv_init_tlvs *tlvs = tlv_init_tlvs_new(msg); if (!msg) return io_close(conn); @@ -51,13 +61,34 @@ static struct io_plan *peer_init_received(struct io_conn *conn, if (unlikely(is_unknown_msg_discardable(msg))) return read_init(conn, peer); - if (!fromwire_init(tmpctx, msg, &globalfeatures, &features)) { + if (!fromwire_init(tmpctx, msg, &globalfeatures, &features, tlvs)) { status_peer_debug(&peer->id, "bad fromwire_init '%s', closing", tal_hex(tmpctx, msg)); return io_close(conn); } + /* BOLT-ef7c97c02b6fa67a1df1af30b3843eb576100ebd #1: + * The receiving node: + * ... + * - upon receiving `networks` containing no common chains + * - MAY fail the connection. + */ + if (tlvs->networks) { + if (!tlvs->networks->chains) { + status_peer_debug(&peer->id, + "bad networks TLV in init '%s', closing", + tal_hex(tmpctx, msg)); + return io_close(conn); + } + if (!contains_common_chain(tlvs->networks->chains)) { + status_peer_debug(&peer->id, + "No common chain with this peer '%s', closing", + tal_hex(tmpctx, msg)); + return io_close(conn); + } + } + /* The globalfeatures field is now unused, but there was a * window where it was: combine the two. */ for (size_t i = 0; i < tal_bytelen(globalfeatures) * 8; i++) { @@ -136,18 +167,27 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, /* If conn is closed, forget peer */ struct peer *peer = tal(conn, struct peer); struct io_plan *(*next)(struct io_conn *, struct peer *); + struct tlv_init_tlvs *tlvs; peer->daemon = daemon; peer->id = *id; peer->addr = *addr; peer->cs = *cs; - /* BOLT #1: + /* BOLT-ef7c97c02b6fa67a1df1af30b3843eb576100ebd #1: * * The sending node: * - MUST send `init` as the first Lightning message for any * connection. + * ... + * - SHOULD set `networks` to all chains it will gossip or open + * channels for. */ + tlvs = tlv_init_tlvs_new(tmpctx); + tlvs->networks = tal(tlvs, struct tlv_init_tlvs_networks); + tlvs->networks->chains = tal_arr(tlvs->networks, struct bitcoin_blkid, 1); + tlvs->networks->chains[0] = chainparams->genesis_blockhash; + /* Initially, there were two sets of feature bits: global and local. * Local affected peer nodes only, global affected everyone. Both were * sent in the `init` message, but node_announcement only advertized @@ -167,7 +207,8 @@ struct io_plan *peer_exchange_initmsg(struct io_conn *conn, * from now on they'll all go in initfeatures. */ peer->msg = towire_init(NULL, get_offered_globalinitfeatures(tmpctx), - get_offered_initfeatures(tmpctx)); + get_offered_initfeatures(tmpctx), + tlvs); status_peer_io(LOG_IO_OUT, &peer->id, peer->msg); peer->msg = cryptomsg_encrypt_msg(peer, &peer->cs, take(peer->msg)); diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 8a16f9988af7..980c3da1cd9a 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -137,7 +137,7 @@ static struct io_plan *handshake_success(struct io_conn *conn, OPTIONAL_FEATURE(OPT_INITIAL_ROUTING_SYNC)); if (!no_init) { - msg = towire_init(NULL, NULL, features); + msg = towire_init(NULL, NULL, features, NULL); sync_crypto_write(pps, take(msg)); /* Ignore their init message. */ diff --git a/lightningd/connect_control.c b/lightningd/connect_control.c index 8f2bdaafec0c..a18e2673d2c7 100644 --- a/lightningd/connect_control.c +++ b/lightningd/connect_control.c @@ -361,7 +361,8 @@ int connectd_init(struct lightningd *ld) } msg = towire_connectctl_init( - tmpctx, &ld->id, + tmpctx, chainparams, + &ld->id, wireaddrs, listen_announce, ld->proxyaddr, ld->use_proxy_always || ld->pure_tor_setup, diff --git a/wire/extracted_peer_wire_csv b/wire/extracted_peer_wire_csv index 6509fc970cc8..5a2a8c23ffe5 100644 --- a/wire/extracted_peer_wire_csv +++ b/wire/extracted_peer_wire_csv @@ -3,6 +3,9 @@ msgdata,init,gflen,u16, msgdata,init,globalfeatures,byte,gflen msgdata,init,lflen,u16, msgdata,init,localfeatures,byte,lflen +msgdata,init,tlvs,init_tlvs, +tlvtype,init_tlvs,networks,1 +tlvdata,init_tlvs,networks,chains,chain_hash,... msgtype,error,17 msgdata,error,channel_id,channel_id, msgdata,error,len,u16, diff --git a/wire/test/Makefile b/wire/test/Makefile index f086ac1b7a37..4fa865bfc96a 100644 --- a/wire/test/Makefile +++ b/wire/test/Makefile @@ -21,3 +21,4 @@ ALL_TEST_PROGRAMS += $(WIRE_TEST_PROGRAMS) wire-tests: $(WIRE_TEST_PROGRAMS:%=unittest/%) +wire/test/run-peer-wire: wire/gen_peer_wire.o wire/tlvstream.o common/bigsize.o diff --git a/wire/test/run-peer-wire.c b/wire/test/run-peer-wire.c index dfe3e2741b1a..fef9a24cfafd 100644 --- a/wire/test/run-peer-wire.c +++ b/wire/test/run-peer-wire.c @@ -1,13 +1,16 @@ -#include "../gen_peer_wire.c" - #include "../towire.c" #include "../fromwire.c" #include "../peer_wire.c" #include #include + +#include #include +#include +#include #include +#include secp256k1_context *secp256k1_ctx; @@ -31,24 +34,6 @@ bool amount_sat_eq(struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) struct amount_sat a UNNEEDED, struct amount_sat b UNNEEDED) { fprintf(stderr, "amount_sat_sub called!\n"); abort(); } -/* Generated stub for bigsize_get */ -size_t bigsize_get(const u8 *p UNNEEDED, size_t max UNNEEDED, bigsize_t *val UNNEEDED) -{ fprintf(stderr, "bigsize_get called!\n"); abort(); } -/* Generated stub for bigsize_put */ -size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED) -{ fprintf(stderr, "bigsize_put called!\n"); abort(); } -/* Generated stub for fromwire_tlvs */ -bool fromwire_tlvs(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, - const struct tlv_record_type types[] UNNEEDED, - size_t num_types UNNEEDED, - void *record UNNEEDED) -{ fprintf(stderr, "fromwire_tlvs called!\n"); abort(); } -/* Generated stub for towire_tlvs */ -void towire_tlvs(u8 **pptr UNNEEDED, - const struct tlv_record_type types[] UNNEEDED, - size_t num_types UNNEEDED, - const void *record UNNEEDED) -{ fprintf(stderr, "towire_tlvs called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ /* memsetting pubkeys doesn't work */ @@ -236,6 +221,7 @@ struct msg_channel_announcement { struct msg_init { u8 *globalfeatures; u8 *localfeatures; + struct tlv_init_tlvs *tlvs; }; struct msg_update_add_htlc { struct channel_id channel_id; @@ -761,16 +747,19 @@ static void *towire_struct_init(const tal_t *ctx, { return towire_init(ctx, s->globalfeatures, - s->localfeatures); + s->localfeatures, + s->tlvs); } static struct msg_init *fromwire_struct_init(const tal_t *ctx, const void *p) { struct msg_init *s = tal(ctx, struct msg_init); + s->tlvs = tlv_init_tlvs_new(s); if (!fromwire_init(s, p, &s->globalfeatures, - &s->localfeatures)) + &s->localfeatures, + s->tlvs)) return tal_free(s); return s; @@ -844,6 +833,9 @@ static bool error_eq(const struct msg_error *a, static bool init_eq(const struct msg_init *a, const struct msg_init *b) { + for (size_t i = 0; i < tal_count(a->tlvs->networks->chains); i++) + assert(bitcoin_blkid_eq(&a->tlvs->networks->chains[i], + &b->tlvs->networks->chains[i])); return eq_var(a, b, globalfeatures) && eq_var(a, b, localfeatures); } @@ -959,6 +951,7 @@ int main(void) void *ctx = tal(NULL, char); size_t i; u8 *msg; + const struct chainparams **chains; secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); @@ -1039,16 +1032,21 @@ int main(void) assert(error_eq(&e, e2)); test_corruption(&e, e2, error); - memset(&init, 2, sizeof(init)); - init.globalfeatures = tal_arr(ctx, u8, 2); - memset(init.globalfeatures, 2, 2); - init.localfeatures = tal_arr(ctx, u8, 2); - memset(init.localfeatures, 2, 2); - - msg = towire_struct_init(ctx, &init); - init2 = fromwire_struct_init(ctx, msg); - assert(init_eq(&init, init2)); - test_corruption(&init, init2, init); + chains = chainparams_for_networks(ctx); + for (i = 0; i < tal_count(chains); i++) { + memset(&init, 2, sizeof(init)); + init.globalfeatures = tal_arr(ctx, u8, 2); + memset(init.globalfeatures, 2, 2); + init.localfeatures = tal_arr(ctx, u8, 2); + memset(init.localfeatures, 2, 2); + init.tlvs = tlv_init_tlvs_new(ctx); + init.tlvs->networks = tal(init.tlvs, struct tlv_init_tlvs_networks); + init.tlvs->networks->chains = tal_arr(ctx, struct bitcoin_blkid, 1); + init.tlvs->networks->chains[0] = chains[i]->genesis_blockhash; + msg = towire_struct_init(ctx, &init); + init2 = fromwire_struct_init(ctx, msg); + assert(init_eq(&init, init2)); + } memset(&uf, 2, sizeof(uf)); From bcc7e708f108ee8b6d16d685233fd934d3520aa7 Mon Sep 17 00:00:00 2001 From: darosior Date: Thu, 28 Nov 2019 15:33:34 +0100 Subject: [PATCH 4/4] devtools/gossipwith: add a "network" option If specified, this will add the corresponding chain_hash to the init message. --- devtools/gossipwith.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/devtools/gossipwith.c b/devtools/gossipwith.c index 980c3da1cd9a..49001ad9eb8d 100644 --- a/devtools/gossipwith.c +++ b/devtools/gossipwith.c @@ -1,4 +1,6 @@ /* Simple tool to route gossip from a peer. */ +#include +#include #include #include #include @@ -81,6 +83,22 @@ enum dev_disconnect dev_disconnect(int pkt_type) } #endif +static char *opt_set_network(const char *arg, void *unused) +{ + assert(arg != NULL); + + /* Set the global chainparams instance */ + chainparams = chainparams_for_network(arg); + if (!chainparams) + return tal_fmt(NULL, "Unknown network name '%s'", arg); + return NULL; +} + +static void opt_show_network(char buf[OPT_SHOW_LEN], const void *unused) +{ + snprintf(buf, OPT_SHOW_LEN, "%s", chainparams->network_name); +} + void peer_failed_connection_lost(void) { exit(0); @@ -137,11 +155,19 @@ static struct io_plan *handshake_success(struct io_conn *conn, OPTIONAL_FEATURE(OPT_INITIAL_ROUTING_SYNC)); if (!no_init) { - msg = towire_init(NULL, NULL, features, NULL); + struct tlv_init_tlvs *tlvs = NULL; + if (chainparams) { + tlvs = tlv_init_tlvs_new(NULL); + tlvs->networks = tal(tlvs, struct tlv_init_tlvs_networks); + tlvs->networks->chains = tal_arr(tlvs->networks, struct bitcoin_blkid, 1); + tlvs->networks->chains[0] = chainparams->genesis_blockhash; + } + msg = towire_init(NULL, NULL, features, tlvs); sync_crypto_write(pps, take(msg)); /* Ignore their init message. */ tal_free(sync_crypto_read(NULL, pps)); + tal_free(tlvs); } if (stream_stdin) @@ -254,6 +280,10 @@ int main(int argc, char *argv[]) "Print out messages in hex"); opt_register_arg("--features=", opt_set_features, NULL, &features, "Send these features in init"); + opt_register_arg("--network", opt_set_network, opt_show_network, + NULL, + "Select the network parameters (bitcoin, testnet, regtest" + " liquid, liquid-regtest, litecoin or litecoin-testnet)"); opt_register_noarg("--help|-h", opt_usage_and_exit, "id@addr[:port] [hex-msg-tosend...]\n" "Connect to a lightning peer and relay gossip messages from it",