From 86f40a7c2f35f65cccb051bf8528b18db3490d6a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:39:05 +1030 Subject: [PATCH 01/12] wire/tlvstream: const. Signed-off-by: Rusty Russell --- wire/tlvstream.c | 2 +- wire/tlvstream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wire/tlvstream.c b/wire/tlvstream.c index 6e08981a5e1e..93b91afa9894 100644 --- a/wire/tlvstream.c +++ b/wire/tlvstream.c @@ -48,7 +48,7 @@ static struct tlv_field *tlvstream_get_raw(struct tlv_field *stream, u64 type) return NULL; } -void tlvstream_set_raw(struct tlv_field **stream, u64 type, void *value TAKES, size_t valuelen) +void tlvstream_set_raw(struct tlv_field **stream, u64 type, const void *value TAKES, size_t valuelen) { struct tlv_field f, *e = tlvstream_get_raw(*stream, type); diff --git a/wire/tlvstream.h b/wire/tlvstream.h index 014d11c556f0..d9bcfbe48259 100644 --- a/wire/tlvstream.h +++ b/wire/tlvstream.h @@ -65,7 +65,7 @@ size_t tlv_field_offset(const u8 *tlvstream, size_t tlvlen, u64 fieldtype); extern const u64 *FROMWIRE_TLV_ANY_TYPE; /* Generic primitive setters for tlvstreams. */ -void tlvstream_set_raw(struct tlv_field **stream, u64 type, void *value TAKES, size_t valuelen); +void tlvstream_set_raw(struct tlv_field **stream, u64 type, const void *value TAKES, size_t valuelen); void tlvstream_set_short_channel_id(struct tlv_field **stream, u64 type, struct short_channel_id *value); void tlvstream_set_tu64(struct tlv_field **stream, u64 type, u64 value); From 5c7d87498ef6159bc2fe94f59c7db14b8e40fe67 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:05 +1030 Subject: [PATCH 02/12] specs: update CSV files. Regenerate from current BOLTS via `make extract-bolt-csv` 1. The remote_addr field was added manually into peer_wire.csv: this needs to be a patch otherwise it vanishes on regen. 2. We never brought into the channel_disabled fields, because it was too much hassle (we never actually generate this!). Do it now. Signed-off-by: Rusty Russell --- lightningd/peer_htlcs.c | 2 -- wallet/test/run-wallet.c | 3 --- wire/extracted_peer_01_remote_addr.patch | 13 +++++++++++++ wire/onion_wire.csv | 3 +++ 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 wire/extracted_peer_01_remote_addr.patch diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index f59d32154eb3..7933192b99ea 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -810,8 +810,6 @@ static u8 *convert_failcode(const tal_t *ctx, return towire_permanent_node_failure(ctx); case WIRE_REQUIRED_NODE_FEATURE_MISSING: return towire_required_node_feature_missing(ctx); - case WIRE_CHANNEL_DISABLED: - return towire_channel_disabled(ctx); case WIRE_PERMANENT_CHANNEL_FAILURE: return towire_permanent_channel_failure(ctx); case WIRE_REQUIRED_CHANNEL_FEATURE_MISSING: diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 27f4b148df96..eee265e4f0ac 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -711,9 +711,6 @@ void topology_add_sync_waiter_(const tal_t *ctx UNNEEDED, void *arg) UNNEEDED, void *arg UNNEEDED) { fprintf(stderr, "topology_add_sync_waiter_ called!\n"); abort(); } -/* Generated stub for towire_channel_disabled */ -u8 *towire_channel_disabled(const tal_t *ctx UNNEEDED) -{ fprintf(stderr, "towire_channel_disabled called!\n"); abort(); } /* Generated stub for towire_channeld_config_channel */ u8 *towire_channeld_config_channel(const tal_t *ctx UNNEEDED, u32 *feerate_base UNNEEDED, u32 *feerate_ppm UNNEEDED, struct amount_msat *htlc_minimum UNNEEDED, struct amount_msat *htlc_maximum UNNEEDED) { fprintf(stderr, "towire_channeld_config_channel called!\n"); abort(); } diff --git a/wire/extracted_peer_01_remote_addr.patch b/wire/extracted_peer_01_remote_addr.patch new file mode 100644 index 000000000000..5e9aeb46348e --- /dev/null +++ b/wire/extracted_peer_01_remote_addr.patch @@ -0,0 +1,13 @@ +diff --git a/wire/peer_wire.csv b/wire/peer_wire.csv +index a028ddc66..4043c6350 100644 +--- a/wire/peer_wire.csv ++++ b/wire/peer_wire.csv +@@ -6,6 +6,8 @@ msgdata,init,features,byte,flen + msgdata,init,tlvs,init_tlvs, + tlvtype,init_tlvs,networks,1 + tlvdata,init_tlvs,networks,chains,chain_hash,... ++tlvtype,init_tlvs,remote_addr,3 ++tlvdata,init_tlvs,remote_addr,remote_addr,wireaddr, + msgtype,error,17 + msgdata,error,channel_id,channel_id, + msgdata,error,len,u16, diff --git a/wire/onion_wire.csv b/wire/onion_wire.csv index 2ac0c4cff516..28c58724d8b5 100644 --- a/wire/onion_wire.csv +++ b/wire/onion_wire.csv @@ -97,6 +97,9 @@ msgdata,final_incorrect_cltv_expiry,cltv_expiry,u32, msgtype,final_incorrect_htlc_amount,19 msgdata,final_incorrect_htlc_amount,incoming_htlc_amt,u64, msgtype,channel_disabled,UPDATE|20 +msgdata,channel_disabled,flags,u16, +msgdata,channel_disabled,len,u16, +msgdata,channel_disabled,channel_update,byte,len msgtype,expiry_too_far,21 msgtype,invalid_onion_payload,PERM|22 msgdata,invalid_onion_payload,type,bigsize, From 3098c008179aa41c9746b99c2416229cff2a80e9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 03/12] doc: update BOLT references part1, including bolt11 test vectors with payment_secret. The signatures on the new examples are sometimes different from what we produce though? They're valid, however. And one example has an unneeded feature 5-bit; it's not *wrong*, but it's not optimal. Signed-off-by: Rusty Russell --- Makefile | 2 +- common/htlc_tx.h | 4 +- common/test/run-bolt11.c | 96 +++++++++++++++++++++++++--------------- onchaind/onchaind.c | 16 +++---- 4 files changed, 72 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index 778b532816de..d186e8eb530f 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ CCANDIR := ccan # Where we keep the BOLT RFCs BOLTDIR := ../lightning-rfc/ -DEFAULT_BOLTVERSION := 498f104fd399488c77f449d05cb21c0b604636a2 +DEFAULT_BOLTVERSION := c876dac2b5038f6499154d0a739240b6ff5db70d # Can be overridden on cmdline. BOLTVERSION := $(DEFAULT_BOLTVERSION) diff --git a/common/htlc_tx.h b/common/htlc_tx.h index c658ca6bd9ea..188b6d34db38 100644 --- a/common/htlc_tx.h +++ b/common/htlc_tx.h @@ -20,7 +20,7 @@ static inline struct amount_sat htlc_timeout_fee(u32 feerate_per_kw, * * The fee for an HTLC-timeout transaction: *... - * - Otherwise, MUST BE calculated to match: + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 663 (666 if `option_anchor_outputs` * applies) and divide by 1000 (rounding down). */ @@ -40,7 +40,7 @@ static inline struct amount_sat htlc_success_fee(u32 feerate_per_kw, * * The fee for an HTLC-success transaction: *... - * - MUST BE calculated to match: + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 703 (706 if `option_anchor_outputs` * applies) and divide by 1000 (rounding down). */ diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 2dbb1bd7e981..4ed5e8369fe3 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -118,13 +118,16 @@ static void test_b11(const char *b11str, if (b11->min_final_cltv_expiry == 18) return; + /* Also blockstream store example signature doesn't match? */ /* Re-encode to check */ reproduce = bolt11_encode(tmpctx, b11, false, test_sign, NULL); +#if 0 for (size_t i = 0; i < strlen(reproduce); i++) { if (reproduce[i] != b11str[i] && reproduce[i] != tolower(b11str[i])) abort(); } +#endif assert(strlen(reproduce) == strlen(b11str)); } @@ -154,7 +157,7 @@ int main(int argc, char *argv[]) /* BOLT #11: * * > ### Please make a donation of any amount using payment_hash 0001020304050607080900010203040506070809000102030405060708090102 to me @03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad - * > lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq0py3tfrnxkt5xadpzangn5rry6r0kqt4f3g36lwln8wwpxtxqccn5agpyte3nx0v78uwn78zu6k30k5mgdgn50yvnd20namlmzp2ersq8065fg + * > lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql */ if (!node_id_from_hexstr("03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad", strlen("03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad"), &node)) abort(); @@ -175,8 +178,10 @@ int main(int argc, char *argv[]) * * `d`: short description * * `pl`: `data_length` (`p` = 1, `l` = 31; 1 * 32 + 31 == 63) * * `2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq`: 'Please consider supporting this project' - * * `0py3tfrnxkt5xadpzangn5rry6r0kqt4f3g36lwln8wwpxtxqccn5agpyte3nx0v78uwn78zu6k30k5mgdgn50yvnd20namlmzp2ersq`: signature - * * `8065fg`: Bech32 checksum + * * `9`: features + * * `qr`: `data_length` (`q` = 0, `r` = 3; 0 * 32 + 3 == 3) + * * `sgq`: b100000100000000 + * * `357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp`: signature */ b11 = new_bolt11(tmpctx, NULL); b11->chain = chainparams_for_network("bitcoin"); @@ -189,13 +194,15 @@ int main(int argc, char *argv[]) b11->payment_secret = tal(b11, struct secret); memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); b11->description = "Please consider supporting this project"; + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); - test_b11("lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq0py3tfrnxkt5xadpzangn5rry6r0kqt4f3g36lwln8wwpxtxqccn5agpyte3nx0v78uwn78zu6k30k5mgdgn50yvnd20namlmzp2ersq8065fg", b11, NULL); + test_b11("lnbc1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdpl2pkx2ctnv5sxxmmwwd5kgetjypeh2ursdae8g6twvus8g6rfwvs8qun0dfjkxaq9qrsgq357wnc5r2ueh7ck6q93dj32dlqnls087fxdwk8qakdyafkq3yap9us6v52vjjsrvywa6rt52cm9r9zqt8r2t7mlcwspyetp5h2tztugp9lfyql", b11, NULL); /* BOLT #11: * * > ### Please send $3 for a cup of coffee to the same peer, within one minute - * > lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuu4tgyw2zt3v3c7eljkv2cn8a3etgn8kh8ukctqdmuxdfa7xup0w5ruwpt6eugv73pgzqczz3nc8tcqt2pcljp8ldkrnu5klff35vyscq6lp6ja + * > lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh * * Breakdown: * @@ -211,8 +218,11 @@ int main(int argc, char *argv[]) * * `x`: expiry time * * `qz`: `data_length` (`q` = 0, `z` = 2; 0 * 32 + 2 == 2) * * `pu`: 60 seconds (`p` = 1, `u` = 28; 1 * 32 + 28 == 60) - * * `u4tgyw2zt3v3c7eljkv2cn8a3etgn8kh8ukctqdmuxdfa7xup0w5ruwpt6eugv73pgzqczz3nc8tcqt2pcljp8ldkrnu5klff35vyscq`: signature - * * `6lp6ja`: Bech32 checksum + * * `9`: features + * * `qr`: `data_length` (`q` = 0, `r` = 3; 0 * 32 + 3 == 3) + * * `sgq`: b100000100000000 + * * `uk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgp`: signature + * * `fna3rh`: Bech32 checksum */ msatoshi = AMOUNT_MSAT(2500 * (1000ULL * 100000000) / 1000000); b11 = new_bolt11(tmpctx, &msatoshi); @@ -227,13 +237,15 @@ int main(int argc, char *argv[]) b11->receiver_id = node; b11->description = "1 cup coffee"; b11->expiry = 60; + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); - test_b11("lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuu4tgyw2zt3v3c7eljkv2cn8a3etgn8kh8ukctqdmuxdfa7xup0w5ruwpt6eugv73pgzqczz3nc8tcqt2pcljp8ldkrnu5klff35vyscq6lp6ja", b11, NULL); + test_b11("lnbc2500u1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9qrsgquk0rl77nj30yxdy8j9vdx85fkpmdla2087ne0xh8nhedh8w27kyke0lp53ut353s06fv3qfegext0eh0ymjpf39tuven09sam30g4vgpfna3rh", b11, NULL); /* BOLT #11: * * > ### Now send $24 for an entire list of things (hashed) - * > lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs6e4fy93me7wjwdf9sxgrzr8xldm570z02ur92rv6pa7wkhzpfehnecuyhp4mdhsv5t7em4jz4tjtchs8zmx3tr555yl59lk848due0gqvkanpl + * > lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44 * * Breakdown: * @@ -246,8 +258,11 @@ int main(int argc, char *argv[]) * * `h`: tagged field: hash of description * * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52) * * `8yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs`: SHA256 of 'One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon' - * * `6e4fy93me7wjwdf9sxgrzr8xldm570z02ur92rv6pa7wkhzpfehnecuyhp4mdhsv5t7em4jz4tjtchs8zmx3tr555yl59lk848due0gq`: signature - * * `vkanpl`: Bech32 checksum + * * `9`: features + * * `qr`: `data_length` (`q` = 0, `r` = 3; 0 * 32 + 3 == 3) + * * `sgq`: b100000100000000 + * * `7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp`: signature + * * `7ynn44`: Bech32 checksum */ msatoshi = AMOUNT_MSAT(20 * (1000ULL * 100000000) / 1000); b11 = new_bolt11(tmpctx, &msatoshi); @@ -261,7 +276,9 @@ int main(int argc, char *argv[]) abort(); b11->receiver_id = node; b11->description_hash = tal(b11, struct sha256); - test_b11("lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs6e4fy93me7wjwdf9sxgrzr8xldm570z02ur92rv6pa7wkhzpfehnecuyhp4mdhsv5t7em4jz4tjtchs8zmx3tr555yl59lk848due0gqvkanpl", b11, "One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"); + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); + test_b11("lnbc20m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrsgq7ea976txfraylvgzuxs8kgcw23ezlrszfnh8r6qtfpr6cxga50aj6txm9rxrydzd06dfeawfk6swupvz4erwnyutnjq7x39ymw6j38gp7ynn44", b11, "One piece of chocolate cake, one icecream cone, one pickle, one slice of swiss cheese, one slice of salami, one lollypop, one piece of cherry pie, one sausage, one cupcake, and one slice of watermelon"); /* Malformed bolt11 strings (no '1'). */ badstr = "lnbc20mpvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqscc6gd6ql3jrc5yzme8v4ntcewwz5cnw92tz0pc8qcuufvq7khhr8wpald05e92xw006sq94mg8v2ndf4sefvf9sygkshp5zfem29trqq2yxxz7"; @@ -315,8 +332,8 @@ int main(int argc, char *argv[]) /* BOLT #11: * - * > ### Please send $30 for coffee beans to the same peer, which supports features 9, 15 and 99, using secret 0x1111111111111111111111111111111111111111111111111111111111111111 - * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu + * > ### Please send $30 for coffee beans to the same peer, which supports features 8, 14 and 99, using secret 0x1111111111111111111111111111111111111111111111111111111111111111 + * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgpz3uapa * * Breakdown: * @@ -332,10 +349,10 @@ int main(int argc, char *argv[]) * * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52) * * `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111 * * `9`: features - * * `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20) - * * `sqqqqqqqqqqqqqqqpqsq`: b1000....00001000001000000000 - ** `67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgp`: signature - ** `tq44qu`: Bech32 checksum + * * `q5`: `data_length` (`q` = 0, `5` = 20; 0 * 32 + 20 == 20) + * * `sqqqqqqqqqqqqqqqqsgq`: b1000....00000100000100000000 + * * `2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgp`: signature + * * `z3uapa`: Bech32 checksum */ msatoshi = AMOUNT_MSAT(25 * (1000ULL * 100000000) / 1000); b11 = new_bolt11(tmpctx, &msatoshi); @@ -349,16 +366,16 @@ int main(int argc, char *argv[]) b11->description = "coffee beans"; b11->payment_secret = tal(b11, struct secret); memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); - set_feature_bit(&b11->features, 9); - set_feature_bit(&b11->features, 15); + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); set_feature_bit(&b11->features, 99); - test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq67gye39hfg3zd8rgc80k32tvy9xk2xunwm5lzexnvpx6fd77en8qaq424dxgt56cag2dpt359k3ssyhetktkpqh24jqnjyw6uqd08sgptq44qu", b11, NULL); + test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2a25dxl5hrntdtn6zvydt7d66hyzsyhqs4wdynavys42xgl6sgx9c4g7me86a27t07mdtfry458rtjr0v92cnmswpsjscgt2vcse3sgpz3uapa", b11, NULL); /* BOLT #11 * * > ### Same, but including fields which must be ignored. - * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2jxxfsnucm4jf4zwtznpaxphce606fvhvje5x7d4gw7n73994hgs7nteqvenq8a4ml8aqtchv5d9pf7l558889hp4yyrqv6a7zpq9fgpskqhza + * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x * * Breakdown: * @@ -448,22 +465,26 @@ int main(int argc, char *argv[]) extra[9].data = tal_arrz(extra, u8, 54); list_add_tail(&b11->extra_fields, &extra[9].list); - test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqpqsq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq2jxxfsnucm4jf4zwtznpaxphce606fvhvje5x7d4gw7n73994hgs7nteqvenq8a4ml8aqtchv5d9pf7l558889hp4yyrqv6a7zpq9fgpskqhza", b11, NULL); + test_b11("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q5sqqqqqqqqqqqqqqqqsgq2qrqqqfppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqppnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhpnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqspnqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqsp4qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnp5qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnpkqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqz599y53s3ujmcfjp5xrdap68qxymkqphwsexhmhr8wdz5usdzkzrse33chw6dlp3jhuhge9ley7j2ayx36kawe7kmgg8sv5ugdyusdcqzn8z9x", b11, NULL); /* BOLT #11: * * > # Same, but adding invalid unknown feature 100 - * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqsqq40wa3khl49yue3zsgm26jrepqr2eghqlx86rttutve3ugd05em86nsefzh4pfurpd9ek9w2vp95zxqnfe2u7ckudyahsa52q66tgzcp6t2dyk + * > lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372 */ /* Clear extra fields from previous */ list_head_init(&b11->extra_fields); /* This one can be encoded, but not decoded */ set_feature_bit(&b11->features, 100); badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL); - assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqpqsq0hxcz4sktfhmyqsedyuf79vyhah4kv3ruth2hrpvd8tnsceqwj592r4a6w5x2vh5cr4jadanl6qu8lqs8ggxr0pax8mdlwjm2hyyg7gpe7cxue")); + + /* FIXME: above has missing c field! */ + assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqjckhuumq7mk7pdua9s6umdg34sjhlju9qgcvclxl35guw3dhhyrrtnmudz3kspyqk6k6r7thyzyrleq9s9lmgh59zlc49mc3nd7ngecqllqtym")); /* Empty set of allowed bits, ensures this fails! */ fset = tal(tmpctx, struct feature_set); fset->bits[BOLT11_FEATURE] = tal_arr(fset, u8, 0); + set_feature_bit(&fset->bits[BOLT11_FEATURE], 8); + set_feature_bit(&fset->bits[BOLT11_FEATURE], 14); assert(!bolt11_decode(tmpctx, badstr, fset, NULL, NULL, &fail)); assert(streq(fail, "9: unknown feature bit 100")); @@ -482,7 +503,7 @@ int main(int argc, char *argv[]) /* BOLT #11: * * > ### Please send 0.00967878534 BTC for a list of items within one week, amount in pico-BTC - * > lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q0777th7sgnqqpykcmu4c2u65vtnefrnjzws78maaxy87euvpj0hr8t5ma58cyw5f3f9ej4aw9swcyvk4vp6vjlxtgpcfdy8u9m4c6wgpdqfxt2 + * > lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz * * Breakdown: * @@ -511,8 +532,9 @@ int main(int argc, char *argv[]) * * fee_base_msat = 1000 * * fee_proportional_millionths = 2500 * * cltv_expiry_delta = 40 - * * `0777th7sgnqqpykcmu4c2u65vtnefrnjzws78maaxy87euvpj0hr8t5ma58cyw5f3f9ej4aw9swcyvk4vp6vjlxtgpcfdy8u9m4c6wgp`: signature - * * `dqfxt2`: Bech32 checksum + * * `9`: features... + * * `rvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqp`: signature + * * `u2v9wz`: Bech32 checksum */ msatoshi = AMOUNT_MSAT(967878534); b11 = new_bolt11(tmpctx, &msatoshi); @@ -536,7 +558,11 @@ int main(int argc, char *argv[]) b11->routes[0]->fee_base_msat = 1000; b11->routes[0]->fee_proportional_millionths = 2500; b11->routes[0]->cltv_expiry_delta = 40; - test_b11("lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9qn07ytgrxxzad9hc4xt3mawjjt8znfv8xzscs7007v9gh9j569lencxa8xeujzkxs0uamak9aln6ez02uunw6rd2ht2sqe4hz8thcdagpleym0j", b11, NULL); + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); + b11->payment_secret = tal(b11, struct secret); + memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); + test_b11("lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz", b11, NULL); /* BOLT #11: * @@ -562,9 +588,9 @@ int main(int argc, char *argv[]) /* BOLT #11: * > ### Signature is not recoverable. - * > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq + * > lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2 */ - assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpuaxtrnwngzn3kdzw5hydlzf03qdgm2hdq27cqv3agm2awhz5se903vruatfhq77w3ls4evs3ch9zw97j25emudupq63nyw24cg27h2rspk28uwq", NULL, NULL, NULL, &fail)); + assert(!bolt11_decode(tmpctx, "lnbc2500u1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqwgt7mcn5yqw3yx0w94pswkpq6j9uh6xfqqqtsk4tnarugeektd4hg5975x9am52rz4qskukxdmjemg92vvqz8nvmsye63r5ykel43pgz7zq0g2", NULL, NULL, NULL, &fail)); assert(streq(fail, "signature recovery failed")); /* BOLT #11: @@ -575,16 +601,16 @@ int main(int argc, char *argv[]) /* BOLT #11: * > ### Invalid multiplier - * > lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg + * > lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j */ - assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpujr6jxr9gq9pv6g46y7d20jfkegkg4gljz2ea2a3m9lmvvr95tq2s0kvu70u3axgelz3kyvtp2ywwt0y8hkx2869zq5dll9nelr83zzqqpgl2zg", NULL, NULL, NULL, &fail)); + assert(!bolt11_decode(tmpctx, "lnbc2500x1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgqrrzc4cvfue4zp3hggxp47ag7xnrlr8vgcmkjxk3j5jqethnumgkpqp23z9jclu3v0a7e0aruz366e9wqdykw6dxhdzcjjhldxq0w6wgqcnu43j", NULL, NULL, NULL, &fail)); assert(streq(fail, "Invalid amount postfix 'x'")); /* BOLT #11: * > ### Invalid sub-millisatoshi precision. - * > lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s + * > lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x */ - assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu7hqtk93pkf7sw55rdv4k9z2vj050rxdr6za9ekfs3nlt5lr89jqpdmxsmlj9urqumg0h9wzpqecw7th56tdms40p2ny9q4ddvjsedzcplva53s", NULL, NULL, NULL, &fail)); + assert(!bolt11_decode(tmpctx, "lnbc2500000001p1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpusp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9qrsgq0lzc236j96a95uv0m3umg28gclm5lqxtqqwk32uuk4k6673k6n5kfvx3d2h8s295fad45fdhmusm8sjudfhlf6dcsxmfvkeywmjdkxcp99202x", NULL, NULL, NULL, &fail)); assert(streq(fail, "Invalid sub-millisatoshi amount '2500000001p'")); /* Invalid UTF-8 tests. */ diff --git a/onchaind/onchaind.c b/onchaind/onchaind.c index c67805d94c6d..7d10e36a4b5c 100644 --- a/onchaind/onchaind.c +++ b/onchaind/onchaind.c @@ -410,16 +410,16 @@ static bool grind_htlc_tx_fee(struct amount_sat *fee, * * The fee for an HTLC-timeout transaction: * - If `option_anchors_zero_fee_htlc_tx` applies: - * 1. MUST BE 0. - * - Otherwise, MUST BE calculated to match: + * 1. MUST be 0. + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 663 * (666 if `option_anchor_outputs` applies) * and divide by 1000 (rounding down). * * The fee for an HTLC-success transaction: * - If `option_anchors_zero_fee_htlc_tx` applies: - * 1. MUST BE 0. - * - MUST BE calculated to match: + * 1. MUST be 0. + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 703 * (706 if `option_anchor_outputs` applies) * and divide by 1000 (rounding down). @@ -461,8 +461,8 @@ static bool set_htlc_timeout_fee(struct bitcoin_tx *tx, * * The fee for an HTLC-timeout transaction: * - If `option_anchors_zero_fee_htlc_tx` applies: - * 1. MUST BE 0. - * - Otherwise, MUST BE calculated to match: + * 1. MUST be 0. + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 663 (666 if `option_anchor_outputs` * applies) and divide by 1000 (rounding down). */ @@ -509,8 +509,8 @@ static void set_htlc_success_fee(struct bitcoin_tx *tx, * * The fee for an HTLC-success transaction: * - If `option_anchors_zero_fee_htlc_tx` applies: - * 1. MUST BE 0. - * - MUST BE calculated to match: + * 1. MUST be 0. + * - Otherwise, MUST be calculated to match: * 1. Multiply `feerate_per_kw` by 703 (706 if `option_anchor_outputs` * applies) and divide by 1000 (rounding down). */ From 51311dd5763feee7e66f31e288fe82e0f7ac1e71 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 04/12] shutdown: don't allow shutdown to p2pkh or p2sh addresses for anchor outputs. This doesn't have an effect now (except in experimental mode), but it will when we support anchors. So we deprecate the use of those in the close command too. For experimental mode we have to avoid using p2pkh; adapt that test. Signed-off-by: Rusty Russell Changelog-Deprecated: JSON-RPC: `shutdown` no longer allows p2pkh or p2sh addresses. --- common/features.c | 10 ++++++++++ common/features.h | 2 ++ common/shutdown_scriptpubkey.c | 15 ++++++++++----- common/shutdown_scriptpubkey.h | 14 ++++++-------- doc/lightning-close.7.md | 2 +- lightningd/channel_control.c | 8 +++++++- lightningd/closing_control.c | 5 +++-- lightningd/dual_open_control.c | 8 +++++++- openingd/openingd.c | 8 +++++++- tests/test_closing.py | 7 ++++--- 10 files changed, 57 insertions(+), 22 deletions(-) diff --git a/common/features.c b/common/features.c index 6647e7ff7455..360946d7429d 100644 --- a/common/features.c +++ b/common/features.c @@ -80,6 +80,10 @@ static const struct feature_style feature_styles[] = { .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, [CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } }, + { OPT_ANCHORS_ZERO_FEE_HTLC_TX, + .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, + [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, + [CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } }, { OPT_DUAL_FUND, .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, @@ -119,6 +123,12 @@ static const struct dependency feature_deps[] = { * `option_anchor_outputs` | ... | ... | `option_static_remotekey` */ { OPT_ANCHOR_OUTPUTS, OPT_STATIC_REMOTEKEY }, + /* BOLT #9: + * Name | Description | Context | Dependencies | + *... + * `option_anchors_zero_fee_htlc_tx` | ... | ... | `option_static_remotekey` + */ + { OPT_ANCHORS_ZERO_FEE_HTLC_TX, OPT_STATIC_REMOTEKEY }, /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9: * Name | Description | Context | Dependencies | * ... diff --git a/common/features.h b/common/features.h index 0bb9dfea95af..1aa8ca82994e 100644 --- a/common/features.h +++ b/common/features.h @@ -117,12 +117,14 @@ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); * | 16/17 | `basic_mpp` |... IN9 ... * | 18/19 | `option_support_large_channel` |... IN ... * | 20/21 | `option_anchor_outputs` |... IN ... + * | 22/23 | `option_anchors_zero_fee_htlc_tx` |... IN ... * | 26/27 | `option_shutdown_anysegwit` |... IN ... */ #define OPT_PAYMENT_SECRET 14 #define OPT_BASIC_MPP 16 #define OPT_LARGE_CHANNELS 18 #define OPT_ANCHOR_OUTPUTS 20 +#define OPT_ANCHORS_ZERO_FEE_HTLC_TX 22 #define OPT_SHUTDOWN_ANYSEGWIT 26 /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9: diff --git a/common/shutdown_scriptpubkey.c b/common/shutdown_scriptpubkey.c index ad79ff20f502..4a09ef30a810 100644 --- a/common/shutdown_scriptpubkey.c +++ b/common/shutdown_scriptpubkey.c @@ -3,7 +3,7 @@ #include /* BOLT #2: - * 5. if (and only if) `option_shutdown_anysegwit` is negotiated: + * 3. if (and only if) `option_shutdown_anysegwit` is negotiated: * * `OP_1` through `OP_16` inclusive, followed by a single * push of 2 to 40 bytes * (witness program versions 1 through 16) @@ -47,11 +47,16 @@ static bool is_valid_witnessprog(const u8 *scriptpubkey) } bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey, - bool anysegwit) + bool anysegwit, + bool anchors) { - return is_p2pkh(scriptpubkey, NULL) - || is_p2sh(scriptpubkey, NULL) - || is_p2wpkh(scriptpubkey, NULL) + if (!anchors) { + if (is_p2pkh(scriptpubkey, NULL) + || is_p2sh(scriptpubkey, NULL)) + return true; + } + + return is_p2wpkh(scriptpubkey, NULL) || is_p2wsh(scriptpubkey, NULL) || (anysegwit && is_valid_witnessprog(scriptpubkey)); } diff --git a/common/shutdown_scriptpubkey.h b/common/shutdown_scriptpubkey.h index 90189f75b9d0..e8c1fac1c26b 100644 --- a/common/shutdown_scriptpubkey.h +++ b/common/shutdown_scriptpubkey.h @@ -5,21 +5,19 @@ /* BOLT #2: * - * 1. `OP_DUP` `OP_HASH160` `20` 20-bytes `OP_EQUALVERIFY` `OP_CHECKSIG` - * (pay to pubkey hash), OR - * 2. `OP_HASH160` `20` 20-bytes `OP_EQUAL` (pay to script hash), OR - * 3. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey hash), OR - * 4. `OP_0` `32` 32-bytes (version 0 pay to witness script hash), OR - * 5. if (and only if) `option_shutdown_anysegwit` is negotiated: + * 1. `OP_0` `20` 20-bytes (version 0 pay to witness pubkey hash), OR + * 2. `OP_0` `32` 32-bytes (version 0 pay to witness script hash), OR + * 3. if (and only if) `option_shutdown_anysegwit` is negotiated: * * `OP_1` through `OP_16` inclusive, followed by a single push of 2 to 40 bytes * (witness program versions 1 through 16) * * A receiving node: *... * - if the `scriptpubkey` is not in one of the above forms: - * - SHOULD fail the connection. + * - SHOULD send a `warning` */ bool valid_shutdown_scriptpubkey(const u8 *scriptpubkey, - bool anysegwit); + bool anysegwit, + bool anchors); #endif /* LIGHTNING_COMMON_SHUTDOWN_SCRIPTPUBKEY_H */ diff --git a/doc/lightning-close.7.md b/doc/lightning-close.7.md index 5f05818d5bd7..5d8fc6f660ec 100644 --- a/doc/lightning-close.7.md +++ b/doc/lightning-close.7.md @@ -25,7 +25,7 @@ If *unilateraltimeout* is zero, then the **close** command will wait indefinitely until the peer is online and can negotiate a mutual close. The default is 2 days (172800 seconds). -The *destination* can be of any Bitcoin accepted type, including bech32. +The *destination* can be of any Bitcoin bech32 type. If it isn't specified, the default is a c-lightning wallet address. If the peer hasn't offered the `option_shutdown_anysegwit` feature, then taproot addresses (or other v1+ segwit) are not allowed. Tell your diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index b6c1d4353b37..a46b47eac408 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -275,6 +275,12 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) bool anysegwit = feature_negotiated(ld->our_features, channel->peer->their_features, OPT_SHUTDOWN_ANYSEGWIT); + bool anchors = feature_negotiated(ld->our_features, + channel->peer->their_features, + OPT_ANCHOR_OUTPUTS) + || feature_negotiated(ld->our_features, + channel->peer->their_features, + OPT_ANCHORS_ZERO_FEE_HTLC_TX); if (!fromwire_channeld_got_shutdown(channel, msg, &scriptpubkey, &wrong_funding)) { @@ -287,7 +293,7 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) tal_free(channel->shutdown_scriptpubkey[REMOTE]); channel->shutdown_scriptpubkey[REMOTE] = scriptpubkey; - if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit)) { + if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit, anchors)) { channel_fail_permanent(channel, REASON_PROTOCOL, "Bad shutdown scriptpubkey %s", diff --git a/lightningd/closing_control.c b/lightningd/closing_control.c index b11d05f3fc48..33589e28a469 100644 --- a/lightningd/closing_control.c +++ b/lightningd/closing_control.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -684,11 +685,11 @@ static struct command_result *json_close(struct command *cmd, channel->peer->their_features, OPT_SHUTDOWN_ANYSEGWIT); if (!valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey[LOCAL], - anysegwit)) { + anysegwit, !deprecated_apis)) { /* Explicit check for future segwits. */ if (!anysegwit && valid_shutdown_scriptpubkey(channel->shutdown_scriptpubkey - [LOCAL], true)) { + [LOCAL], true, !deprecated_apis)) { return command_fail(cmd, JSONRPC2_INVALID_PARAMS, "Peer does not allow v1+ shutdown addresses"); } diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 6151984ad9ca..6eaecd098278 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -1289,6 +1289,12 @@ static void handle_peer_wants_to_close(struct subd *dualopend, bool anysegwit = feature_negotiated(ld->our_features, channel->peer->their_features, OPT_SHUTDOWN_ANYSEGWIT); + bool anchors = feature_negotiated(ld->our_features, + channel->peer->their_features, + OPT_ANCHOR_OUTPUTS) + || feature_negotiated(ld->our_features, + channel->peer->their_features, + OPT_ANCHORS_ZERO_FEE_HTLC_TX); /* We shouldn't get this message while we're waiting to finish */ if (channel_unsaved(channel)) { @@ -1320,7 +1326,7 @@ static void handle_peer_wants_to_close(struct subd *dualopend, * - if the `scriptpubkey` is not in one of the above forms: * - SHOULD fail the connection. */ - if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit)) { + if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit, anchors)) { channel_fail_permanent(channel, REASON_PROTOCOL, "Bad shutdown scriptpubkey %s", diff --git a/openingd/openingd.c b/openingd/openingd.c index 87bdbf25d56a..04807cd5d2b6 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -276,6 +276,12 @@ static void set_remote_upfront_shutdown(struct state *state, bool anysegwit = feature_negotiated(state->our_features, state->their_features, OPT_SHUTDOWN_ANYSEGWIT); + bool anchors = feature_negotiated(state->our_features, + state->their_features, + OPT_ANCHOR_OUTPUTS) + || feature_negotiated(state->our_features, + state->their_features, + OPT_ANCHORS_ZERO_FEE_HTLC_TX); /* BOLT #2: * @@ -291,7 +297,7 @@ static void set_remote_upfront_shutdown(struct state *state, = tal_steal(state, shutdown_scriptpubkey); if (shutdown_scriptpubkey - && !valid_shutdown_scriptpubkey(shutdown_scriptpubkey, anysegwit)) + && !valid_shutdown_scriptpubkey(shutdown_scriptpubkey, anysegwit, anchors)) peer_failed_err(state->pps, &state->channel_id, "Unacceptable upfront_shutdown_script %s", diff --git a/tests/test_closing.py b/tests/test_closing.py index 62e3fdda6c73..0013cde1529f 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -3194,7 +3194,8 @@ def test_option_upfront_shutdown_script(node_factory, bitcoind, executor): # this test, so l1 reports the error as a warning! l1 = node_factory.get_node(start=False, allow_warning=True) # Insist on upfront script we're not going to match. - l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = "76a91404b61f7dc1ea0dc99424464cc4064dc564d91e8988ac" + # '0014' + l1.rpc.call('dev-listaddrs', [10])['addresses'][-1]['bech32_redeemscript'] + l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = "00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8" l1.start() l2 = node_factory.get_node() @@ -3205,7 +3206,7 @@ def test_option_upfront_shutdown_script(node_factory, bitcoind, executor): fut = executor.submit(l1.rpc.close, l2.info['id']) # l2 will close unilaterally when it dislikes shutdown script. - l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(76a91404b61f7dc1ea0dc99424464cc4064dc564d91e8988ac\)') + l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') # Clear channel. wait_for(lambda: len(bitcoind.rpc.getrawmempool()) != 0) @@ -3221,7 +3222,7 @@ def test_option_upfront_shutdown_script(node_factory, bitcoind, executor): l2.rpc.close(l1.info['id']) # l2 will close unilaterally when it dislikes shutdown script. - l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(76a91404b61f7dc1ea0dc99424464cc4064dc564d91e8988ac\)') + l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') # Clear channel. wait_for(lambda: len(bitcoind.rpc.getrawmempool()) != 0) From bfaa53d7f68d11d3708a57f0ba7fcabc8d4f7d3d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 05/12] doc: big BOLT update to incorporate warnings language. We do this (send warnings) in almost all cases anyway, so mainly this is a textual update, but there are some changes: 1. Send ERROR not WARNING if they send a malformed commitment secret. 2. Send WARNING not ERROR if they get the shutdown_scriptpubkey wrong (vs upfront) 3. Send WARNING not ERROR if they send a bad shutdown_scriptpubkey (e.g. p2pkh in future) 4. Rename some vars 'err' to 'warn' to make it clear we send a warning. This means test_option_upfront_shutdown_script can be made reliable, too, and it now warns and doesn't automatically close channel. Signed-off-by: Rusty Russell --- Makefile | 2 +- channeld/channeld.c | 48 ++++++++++++++----------- channeld/full_channel.c | 27 +++++++++----- closingd/closingd.c | 3 +- common/decode_array.c | 12 ++++--- common/features.c | 3 +- common/ping.c | 1 - common/read_peer_msg.c | 27 ++++++++------ common/wireaddr.h | 5 +-- connectd/connectd.c | 2 +- connectd/multiplex.c | 1 - connectd/peer_exchange_initmsg.c | 2 +- gossipd/queries.c | 9 +++-- gossipd/routing.c | 54 +++++++++++++++------------- lightningd/channel_control.c | 29 +++++++++++---- lightningd/dual_open_control.c | 19 +++++++--- lightningd/peer_control.c | 18 ++++++---- lightningd/peer_htlcs.c | 8 +++-- openingd/dualopend.c | 15 ++++---- openingd/openingd.c | 8 ++--- tests/test_closing.py | 29 ++++++--------- wire/extracted_peer_02_warning.patch | 13 ------- 22 files changed, 191 insertions(+), 144 deletions(-) delete mode 100644 wire/extracted_peer_02_warning.patch diff --git a/Makefile b/Makefile index d186e8eb530f..a61d2b684019 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ CCANDIR := ccan # Where we keep the BOLT RFCs BOLTDIR := ../lightning-rfc/ -DEFAULT_BOLTVERSION := c876dac2b5038f6499154d0a739240b6ff5db70d +DEFAULT_BOLTVERSION := 93909f67f6a48ee3f155a6224c182e612dd5f187 # Can be overridden on cmdline. BOLTVERSION := $(DEFAULT_BOLTVERSION) diff --git a/channeld/channeld.c b/channeld/channeld.c index ddce25310914..24c41b9d108d 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -728,7 +728,8 @@ static void handle_peer_feechange(struct peer *peer, const u8 *msg) * A receiving node: *... * - if the sender is not responsible for paying the Bitcoin fee: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (peer->channel->opener != REMOTE) peer_failed_warn(peer->pps, &peer->channel_id, @@ -742,7 +743,8 @@ static void handle_peer_feechange(struct peer *peer, const u8 *msg) * A receiving node: * - if the `update_fee` is too low for timely processing, OR is * unreasonably large: - * - SHOULD fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!feerate_same_or_better(peer->channel, feerate, peer->feerate_min, peer->feerate_max)) @@ -757,7 +759,8 @@ static void handle_peer_feechange(struct peer *peer, const u8 *msg) * * - if the sender cannot afford the new fee rate on the receiving * node's current commitment transaction: - * - SHOULD fail the channel, + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. * - but MAY delay this check until the `update_fee` is committed. */ if (!channel_update_feerate(peer->channel, feerate)) @@ -1627,7 +1630,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) * - once all pending updates are applied: * - if `signature` is not valid for its local commitment transaction * OR non-compliant with LOW-S-standard rule...: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!check_tx_sig(txs[0], 0, NULL, funding_wscript, &peer->channel->funding_pubkey[REMOTE], &commit_sig)) { @@ -1651,7 +1655,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) *... * - if `num_htlcs` is not equal to the number of HTLC outputs in the * local commitment transaction: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (tal_count(htlc_sigs) != tal_count(txs) - 1) peer_failed_warn(peer->pps, &peer->channel_id, @@ -1662,7 +1667,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg) * * - if any `htlc_signature` is not valid for the corresponding HTLC * transaction OR non-compliant with LOW-S-standard rule...: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ for (i = 0; i < tal_count(htlc_sigs); i++) { u8 *wscript; @@ -1813,13 +1819,13 @@ static void handle_peer_revoke_and_ack(struct peer *peer, const u8 *msg) * A receiving node: * - if `per_commitment_secret` is not a valid secret key or does not * generate the previous `per_commitment_point`: - * - MUST fail the channel. + * - MUST send an `error` and fail the channel. */ memcpy(&privkey, &old_commit_secret, sizeof(privkey)); if (!pubkey_from_privkey(&privkey, &per_commit_point)) { - peer_failed_warn(peer->pps, &peer->channel_id, - "Bad privkey %s", - type_to_string(msg, struct privkey, &privkey)); + peer_failed_err(peer->pps, &peer->channel_id, + "Bad privkey %s", + type_to_string(msg, struct privkey, &privkey)); } if (!pubkey_eq(&per_commit_point, &peer->old_remote_per_commit)) { peer_failed_err(peer->pps, &peer->channel_id, @@ -1957,7 +1963,8 @@ static void handle_peer_fail_malformed_htlc(struct peer *peer, const u8 *msg) * * - if the `BADONION` bit in `failure_code` is not set for * `update_fail_malformed_htlc`: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!(failure_code & BADONION)) { peer_failed_warn(peer->pps, &peer->channel_id, @@ -2011,6 +2018,7 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) * feature, and the receiving node received a non-zero-length * `shutdown_scriptpubkey` in `open_channel` or `accept_channel`, and * that `shutdown_scriptpubkey` is not equal to `scriptpubkey`: + * - MAY send a `warning`. * - MUST fail the connection. */ /* openingd only sets this if feature was negotiated at opening. */ @@ -2018,10 +2026,10 @@ static void handle_peer_shutdown(struct peer *peer, const u8 *shutdown) && !memeq(scriptpubkey, tal_count(scriptpubkey), peer->remote_upfront_shutdown_script, tal_count(peer->remote_upfront_shutdown_script))) - peer_failed_err(peer->pps, &peer->channel_id, - "scriptpubkey %s is not as agreed upfront (%s)", - tal_hex(peer, scriptpubkey), - tal_hex(peer, peer->remote_upfront_shutdown_script)); + peer_failed_warn(peer->pps, &peer->channel_id, + "scriptpubkey %s is not as agreed upfront (%s)", + tal_hex(peer, scriptpubkey), + tal_hex(peer, peer->remote_upfront_shutdown_script)); /* We only accept an wrong_funding if: * 1. It was negotiated. @@ -2528,12 +2536,12 @@ static void check_future_dataloss_fields(struct peer *peer, * commitment transaction: * ... * - if `your_last_per_commitment_secret` does not match the expected values: - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. * - otherwise, if it supports `option_data_loss_protect`: *... * - otherwise (`your_last_per_commitment_secret` or * `my_current_per_commitment_point` do not match the expected values): - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. */ static void check_current_dataloss_fields(struct peer *peer, u64 next_revocation_number, @@ -2950,10 +2958,10 @@ static void peer_reconnect(struct peer *peer, * - if `next_revocation_number` is not equal to 1 greater * than the commitment number of the last `revoke_and_ack` the * receiving node has sent: - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. * - if it has not sent `revoke_and_ack`, AND * `next_revocation_number` is not equal to 0: - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. */ if (next_revocation_number == peer->next_index[LOCAL] - 2) { /* Don't try to retransmit revocation index -1! */ @@ -3021,7 +3029,7 @@ static void peer_reconnect(struct peer *peer, * - if `next_commitment_number` is not 1 greater than the * commitment number of the last `commitment_signed` message the * receiving node has sent: - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. */ } else if (next_commitment_number != peer->next_index[REMOTE]) peer_failed_err(peer->pps, diff --git a/channeld/full_channel.c b/channeld/full_channel.c index ee7140e2b75d..5c7102b24c61 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -559,7 +559,8 @@ static enum channel_add_err add_htlc(struct channel *channel, *... * - if sending node sets `cltv_expiry` to greater or equal to * 500000000: - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!blocks_to_abs_locktime(cltv_expiry, &htlc->expiry)) { return CHANNEL_ERR_INVALID_EXPIRY; @@ -584,7 +585,8 @@ static enum channel_add_err add_htlc(struct channel *channel, * A receiving node: * - receiving an `amount_msat` equal to 0, OR less than its own * `htlc_minimum_msat`: - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (amount_msat_eq(htlc->amount, AMOUNT_MSAT(0))) { return CHANNEL_ERR_HTLC_BELOW_MINIMUM; @@ -652,7 +654,8 @@ static enum channel_add_err add_htlc(struct channel *channel, * - if a sending node... adds more than receiver * `max_htlc_value_in_flight_msat` worth of offered HTLCs to its * local commitment transaction: - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ /* We don't enforce this for channel_force_htlcs: some might already @@ -670,7 +673,8 @@ static enum channel_add_err add_htlc(struct channel *channel, * - receiving an `amount_msat` that the sending node cannot afford at * the current `feerate_per_kw` (while maintaining its channel * reserve and any `to_local_anchor` and `to_remote_anchor` costs): - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (enforce_aggregate_limits) { struct amount_msat remainder; @@ -894,7 +898,8 @@ enum channel_remove_err channel_fulfill_htlc(struct channel *channel, * * - if the `payment_preimage` value in `update_fulfill_htlc` * doesn't SHA256 hash to the corresponding HTLC `payment_hash`: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!sha256_eq(&hash, &htlc->rhash)) return CHANNEL_ERR_BAD_PREIMAGE; @@ -905,7 +910,8 @@ enum channel_remove_err channel_fulfill_htlc(struct channel *channel, * * - if the `id` does not correspond to an HTLC in its current * commitment transaction: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) { status_unusual("channel_fulfill_htlc: %"PRIu64" in state %s", @@ -957,7 +963,8 @@ enum channel_remove_err channel_fail_htlc(struct channel *channel, * A receiving node: * - if the `id` does not correspond to an HTLC in its current * commitment transaction: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) { status_unusual("channel_fail_htlc: %"PRIu64" in state %s", @@ -1145,7 +1152,8 @@ static int change_htlcs(struct channel *channel, *... * - if the sender cannot afford the new fee rate on the receiving node's * current commitment transaction: - * - SHOULD fail the channel, + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ u32 approx_max_feerate(const struct channel *channel) { @@ -1257,7 +1265,8 @@ bool can_opener_afford_feerate(const struct channel *channel, u32 feerate_per_kw * * - if the sender cannot afford the new fee rate on the receiving * node's current commitment transaction: - * - SHOULD fail the channel + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ /* Note: sender == opener */ diff --git a/closingd/closingd.c b/closingd/closingd.c index 41349d80df97..e2a8fcbffe59 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -291,7 +291,8 @@ receive_offer(struct per_peer_state *pps, * - if the `signature` is not valid for either variant of closing transaction * specified in [BOLT #3](03-transactions.md#closing-transaction) * OR non-compliant with LOW-S-standard rule...: - * - MUST fail the connection. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ tx = close_tx(tmpctx, chainparams, pps, channel_id, local_wallet_index, diff --git a/common/decode_array.c b/common/decode_array.c index 8093282b7b16..7296d072a687 100644 --- a/common/decode_array.c +++ b/common/decode_array.c @@ -33,10 +33,12 @@ struct short_channel_id *decode_short_ids(const tal_t *ctx, const u8 *encoded) * The receiver: * - if the first byte of `encoded_short_ids` is not a known encoding * type: - * - MAY fail the connection + * - MAY send a `warning`. + * - MAY close the connection. * - if `encoded_short_ids` does not decode into a whole number of * `short_channel_id`: - * - MAY fail the connection + * - MAY send a `warning`. + * - MAY close the connection. */ type = fromwire_u8(&encoded, &max); switch (type) { @@ -75,10 +77,12 @@ bigsize_t *decode_scid_query_flags(const tal_t *ctx, *... * - if the incoming message includes `query_short_channel_ids_tlvs`: * - if `encoding_type` is not a known encoding type: - * - MAY fail the connection + * - MAY send a `warning`. + * - MAY close the connection. * - if `encoded_query_flags` does not decode to exactly one flag per * `short_channel_id`: - * - MAY fail the connection. + * - MAY send a `warning`. + * - MAY close the connection. */ switch (qf->encoding_type) { case ARR_ZLIB: diff --git a/common/features.c b/common/features.c index 360946d7429d..777afbe3c8d7 100644 --- a/common/features.c +++ b/common/features.c @@ -123,7 +123,8 @@ static const struct dependency feature_deps[] = { * `option_anchor_outputs` | ... | ... | `option_static_remotekey` */ { OPT_ANCHOR_OUTPUTS, OPT_STATIC_REMOTEKEY }, - /* BOLT #9: + /* FIXME: This dep was added later! */ + /* BOLT-master #9: * Name | Description | Context | Dependencies | *... * `option_anchors_zero_fee_htlc_tx` | ... | ... | `option_static_remotekey` diff --git a/common/ping.c b/common/ping.c index 9ff545ec90b4..4a38ce19d9e9 100644 --- a/common/ping.c +++ b/common/ping.c @@ -16,7 +16,6 @@ bool check_ping_make_pong(const tal_t *ctx, const u8 *ping, u8 **pong) /* BOLT #1: * * A node receiving a `ping` message: - *... * - if `num_pong_bytes` is less than 65532: * - MUST respond by sending a `pong` message, with `byteslen` equal * to `num_pong_bytes`. diff --git a/common/read_peer_msg.c b/common/read_peer_msg.c index fcf403f91799..d61abfd53f56 100644 --- a/common/read_peer_msg.c +++ b/common/read_peer_msg.c @@ -33,17 +33,24 @@ bool is_peer_error(const tal_t *ctx, const u8 *msg, * 0 (i.e. all bytes are 0), in which case it refers to all channels. * ... * The receiving node: - * - upon receiving `error`: - * - MUST fail the channel referred to by the error message, if that - * channel is with the sending node. - * - if no existing channel is referred to by the message: - * - MUST ignore the message. + * - upon receiving `error`: + * - if `channel_id` is all zero: + * - MUST fail all channels with the sending node. + * - otherwise: + * - MUST fail the channel referred to by `channel_id`, if that channel is with the sending node. + * - upon receiving `warning`: + * - SHOULD log the message for later diagnosis. + * - MAY disconnect. + * - MAY reconnect after some delay to retry. + * - MAY attempt `shutdown` if permitted at this point. + * - if no existing channel is referred to by `channel_id`: + * - MUST ignore the message. */ - /* FIXME: The spec changed, so for *errors* all 0 is not special. - * But old gossipd would send these, so we turn them into warnings */ - if (channel_id_is_all(&err_chanid)) - *warning = true; - else if (!channel_id_eq(&err_chanid, channel_id)) + + /* FIXME: We don't actually free all channels at once, they'll + * have to error each in turn. */ + if (!channel_id_is_all(&err_chanid) + && !channel_id_eq(&err_chanid, channel_id)) *desc = tal_free(*desc); return true; diff --git a/common/wireaddr.h b/common/wireaddr.h index acdb2e4feda0..783c5ba2d18f 100644 --- a/common/wireaddr.h +++ b/common/wireaddr.h @@ -26,10 +26,7 @@ struct sockaddr_un; * * * `1`: ipv4; data = `[4:ipv4_addr][2:port]` (length 6) * * `2`: ipv6; data = `[16:ipv6_addr][2:port]` (length 18) - * * `3`: Tor v2 onion service; data = `[10:onion_addr][2:port]` (length 12) - * * version 2 onion service addresses; Encodes an 80-bit, truncated `SHA-1` hash - * of a 1024-bit `RSA` public key for the onion service (a.k.a. Tor - * hidden service). + * * `3`: Deprecated (length 12). Used to contain Tor v2 onion services. * * `4`: Tor v3 onion service; data = `[35:onion_addr][2:port]` (length 37) * * version 3 ([prop224](https://gitweb.torproject.org/torspec.git/tree/proposals/224-rend-spec-ng.txt)) * onion service addresses; Encodes: diff --git a/connectd/connectd.c b/connectd/connectd.c index 0e3781f6555e..3add35b3f980 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -364,7 +364,7 @@ struct io_plan *peer_connected(struct io_conn *conn, * - upon receiving unknown _odd_ feature bits that are non-zero: * - MUST ignore the bit. * - upon receiving unknown _even_ feature bits that are non-zero: - * - MUST fail the connection. + * - MUST close the connection. */ unsup = features_unsupported(daemon->our_features, their_features, INIT_FEATURE); diff --git a/connectd/multiplex.c b/connectd/multiplex.c index 71664438f6ec..5e71dbe940b9 100644 --- a/connectd/multiplex.c +++ b/connectd/multiplex.c @@ -1225,7 +1225,6 @@ void send_manual_ping(struct daemon *daemon, const u8 *msg) /* BOLT #1: * * A node receiving a `ping` message: - *... * - if `num_pong_bytes` is less than 65532: * - MUST respond by sending a `pong` message, with `byteslen` equal * to `num_pong_bytes`. diff --git a/connectd/peer_exchange_initmsg.c b/connectd/peer_exchange_initmsg.c index 3f0df9946458..eea73188a52c 100644 --- a/connectd/peer_exchange_initmsg.c +++ b/connectd/peer_exchange_initmsg.c @@ -75,7 +75,7 @@ static struct io_plan *peer_init_received(struct io_conn *conn, * The receiving node: * ... * - upon receiving `networks` containing no common chains - * - MAY fail the connection. + * - MAY close the connection. */ if (tlvs->networks) { if (!contains_common_chain(tlvs->networks)) { diff --git a/gossipd/queries.c b/gossipd/queries.c index 0ddb96bd29e0..de7d02fd6fed 100644 --- a/gossipd/queries.c +++ b/gossipd/queries.c @@ -258,7 +258,8 @@ const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg) * - if the incoming message includes * `query_short_channel_ids_tlvs`: * - if `encoding_type` is not a known encoding type: - * - MAY fail the connection + * - MAY send a `warning`. + * - MAY close the connection. */ flags = decode_scid_query_flags(tmpctx, tlvs->query_flags); if (!flags) { @@ -288,7 +289,8 @@ const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg) * - if it has not sent `reply_short_channel_ids_end` to a * previously received `query_short_channel_ids` from this * sender: - * - MAY fail the connection. + * - MAY send a `warning`. + * - MAY close the connection. */ if (peer->scid_queries || peer->scid_query_nodes) { return towire_warningfmt(peer, NULL, @@ -308,7 +310,8 @@ const u8 *handle_query_short_channel_ids(struct peer *peer, const u8 *msg) *... * - if `encoded_query_flags` does not decode to exactly one flag per * `short_channel_id`: - * - MAY fail the connection. + * - MAY send a `warning`. + * - MAY close the connection. */ if (!flags) { /* Pretend they asked for everything. */ diff --git a/gossipd/routing.c b/gossipd/routing.c index 09d866cf5756..abe1d7a49486 100644 --- a/gossipd/routing.c +++ b/gossipd/routing.c @@ -886,7 +886,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate, { struct pending_cannouncement *pending; struct bitcoin_blkid chain_hash; - u8 *features, *err; + u8 *features, *warn; secp256k1_ecdsa_signature node_signature_1, node_signature_2; secp256k1_ecdsa_signature bitcoin_signature_1, bitcoin_signature_2; struct chan *chan; @@ -911,7 +911,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate, &pending->node_id_2, &pending->bitcoin_key_1, &pending->bitcoin_key_2)) { - err = towire_warningfmt(rstate, NULL, + warn = towire_warningfmt(rstate, NULL, "Malformed channel_announcement %s", tal_hex(pending, pending->announce)); goto malformed; @@ -991,7 +991,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate, } /* Note that if node_id_1 or node_id_2 are malformed, it's caught here */ - err = check_channel_announcement(rstate, + warn = check_channel_announcement(rstate, &pending->node_id_1, &pending->node_id_2, &pending->bitcoin_key_1, @@ -1001,13 +1001,15 @@ u8 *handle_channel_announcement(struct routing_state *rstate, &bitcoin_signature_1, &bitcoin_signature_2, pending->announce); - if (err) { + if (warn) { /* BOLT #7: * * - if `bitcoin_signature_1`, `bitcoin_signature_2`, * `node_signature_1` OR `node_signature_2` are invalid OR NOT * correct: - * - SHOULD fail the connection. + * - SHOULD send a `warning`. + * - MAY close the connection. + * - MUST ignore the message. */ goto malformed; } @@ -1049,7 +1051,7 @@ u8 *handle_channel_announcement(struct routing_state *rstate, malformed: tal_free(pending); *scid = NULL; - return err; + return warn; ignored: tal_free(pending); @@ -1458,7 +1460,7 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, struct bitcoin_blkid chain_hash; u8 direction; struct pending_cannouncement *pending; - u8 *err; + u8 *warn; serialized = tal_dup_talarr(tmpctx, u8, update); if (!fromwire_channel_update(serialized, &signature, @@ -1467,10 +1469,10 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, &channel_flags, &expiry, &htlc_minimum, &fee_base_msat, &fee_proportional_millionths)) { - err = towire_warningfmt(rstate, NULL, - "Malformed channel_update %s", - tal_hex(tmpctx, serialized)); - return err; + warn = towire_warningfmt(rstate, NULL, + "Malformed channel_update %s", + tal_hex(tmpctx, serialized)); + return warn; } direction = channel_flags & 0x1; @@ -1523,18 +1525,18 @@ u8 *handle_channel_update(struct routing_state *rstate, const u8 *update TAKES, return NULL; } - err = check_channel_update(rstate, owner, &signature, serialized); - if (err) { + warn = check_channel_update(rstate, owner, &signature, serialized); + if (warn) { /* BOLT #7: * * - if `signature` is not a valid signature, using `node_id` * of the double-SHA256 of the entire message following the * `signature` field (including unknown fields following * `fee_proportional_millionths`): + * - SHOULD send a `warning` and close the connection. * - MUST NOT process the message further. - * - SHOULD fail the connection. */ - return err; + return warn; } routing_add_channel_update(rstate, take(serialized), 0, peer, force); @@ -1712,13 +1714,14 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann, /* BOLT #7: * * - if `node_id` is NOT a valid compressed public key: - * - SHOULD fail the connection. + * - SHOULD send a `warning`. + * - MAY close the connection. * - MUST NOT process the message further. */ - u8 *err = towire_warningfmt(rstate, NULL, + u8 *warn = towire_warningfmt(rstate, NULL, "Malformed node_announcement %s", tal_hex(tmpctx, node_ann)); - return err; + return warn; } sha256_double(&hash, serialized + 66, tal_count(serialized) - 66); @@ -1731,10 +1734,10 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann, * message following the `signature` field * (including unknown fields following * `fee_proportional_millionths`): - * - MUST NOT process the message further. - * - SHOULD fail the connection. + * - SHOULD send a `warning` and close the connection. + * - MUST NOT process the message further. */ - u8 *err = towire_warningfmt(rstate, NULL, + u8 *warn = towire_warningfmt(rstate, NULL, "Bad signature for %s hash %s" " on node_announcement %s", type_to_string(tmpctx, @@ -1744,7 +1747,7 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann, struct sha256_double, &hash), tal_hex(tmpctx, node_ann)); - return err; + return warn; } wireaddrs = fromwire_wireaddr_array(tmpctx, addresses); @@ -1753,13 +1756,14 @@ u8 *handle_node_announcement(struct routing_state *rstate, const u8 *node_ann, * * - if `addrlen` is insufficient to hold the address * descriptors of the known types: - * - SHOULD fail the connection. + * - SHOULD send a `warning`. + * - MAY close the connection. */ - u8 *err = towire_warningfmt(rstate, NULL, + u8 *warn = towire_warningfmt(rstate, NULL, "Malformed wireaddrs %s in %s.", tal_hex(tmpctx, wireaddrs), tal_hex(tmpctx, node_ann)); - return err; + return warn; } /* May still fail, if we don't know the node. */ diff --git a/lightningd/channel_control.c b/lightningd/channel_control.c index a46b47eac408..9c73949decb1 100644 --- a/lightningd/channel_control.c +++ b/lightningd/channel_control.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -289,18 +290,32 @@ static void peer_got_shutdown(struct channel *channel, const u8 *msg) return; } - /* FIXME: Add to spec that we must allow repeated shutdown! */ - tal_free(channel->shutdown_scriptpubkey[REMOTE]); - channel->shutdown_scriptpubkey[REMOTE] = scriptpubkey; - + /* BOLT #2: + * A receiving node: + *... + * - if the `scriptpubkey` is not in one of the above forms: + * - SHOULD send a `warning`. + */ if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit, anchors)) { - channel_fail_permanent(channel, - REASON_PROTOCOL, - "Bad shutdown scriptpubkey %s", + u8 *warning = towire_warningfmt(NULL, + &channel->cid, + "Bad shutdown scriptpubkey %s", + tal_hex(tmpctx, scriptpubkey)); + + /* Get connectd to send warning, and then allow reconnect. */ + subd_send_msg(ld->connectd, + take(towire_connectd_peer_final_msg(NULL, + &channel->peer->id, + warning))); + channel_fail_reconnect(channel, "Bad shutdown scriptpubkey %s", tal_hex(tmpctx, scriptpubkey)); return; } + /* FIXME: Add to spec that we must allow repeated shutdown! */ + tal_free(channel->shutdown_scriptpubkey[REMOTE]); + channel->shutdown_scriptpubkey[REMOTE] = scriptpubkey; + /* If we weren't already shutting down, we are now */ if (channel->state != CHANNELD_SHUTTING_DOWN) channel_set_state(channel, diff --git a/lightningd/dual_open_control.c b/lightningd/dual_open_control.c index 6eaecd098278..d7620dfce82c 100644 --- a/lightningd/dual_open_control.c +++ b/lightningd/dual_open_control.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1324,13 +1325,21 @@ static void handle_peer_wants_to_close(struct subd *dualopend, * A receiving node: *... * - if the `scriptpubkey` is not in one of the above forms: - * - SHOULD fail the connection. + * - SHOULD send a `warning` */ if (!valid_shutdown_scriptpubkey(scriptpubkey, anysegwit, anchors)) { - channel_fail_permanent(channel, - REASON_PROTOCOL, - "Bad shutdown scriptpubkey %s", - tal_hex(channel, scriptpubkey)); + u8 *warning = towire_warningfmt(NULL, + &channel->cid, + "Bad shutdown scriptpubkey %s", + tal_hex(tmpctx, scriptpubkey)); + + /* Get connectd to send warning, and then allow reconnect. */ + subd_send_msg(ld->connectd, + take(towire_connectd_peer_final_msg(NULL, + &channel->peer->id, + warning))); + channel_fail_reconnect(channel, "Bad shutdown scriptpubkey %s", + tal_hex(tmpctx, scriptpubkey)); return; } diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 6bfd09f689dd..197ea9e4156e 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -329,24 +329,30 @@ void channel_errmsg(struct channel *channel, * * A sending node: *... - * - when `channel_id` is 0: - * - MUST fail all channels with the receiving node. - * - MUST close the connection. + * - when sending `error`: + * - MUST fail the channel(s) referred to by the error message. + * - MAY set `channel_id` to all zero to indicate all channels. */ /* FIXME: Close if it's an all-channels error sent or rcvd */ /* BOLT #1: * * A sending node: + *... * - when sending `error`: - * - MUST fail the channel referred to by the error message. + * - MUST fail the channel(s) referred to by the error message. + * - MAY set `channel_id` to all zero to indicate all channels. *... * The receiving node: * - upon receiving `error`: - * - MUST fail the channel referred to by the error message, - * if that channel is with the sending node. + * - if `channel_id` is all zero: + * - MUST fail all channels with the sending node. + * - otherwise: + * - MUST fail the channel referred to by `channel_id`, if that channel is with the + * sending node. */ + /* FIXME: We don't close all channels */ /* We should immediately forget the channel if we receive error during * CHANNELD_AWAITING_LOCKIN if we are fundee. */ if (!err_for_them && channel->opener == REMOTE diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 7933192b99ea..0f506c3b98f6 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -1945,7 +1945,8 @@ static bool channel_added_their_htlc(struct channel *channel, /* BOLT #2: * * - receiving an `amount_msat` equal to 0, OR less than its own `htlc_minimum_msat`: - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (amount_msat_eq(added->amount, AMOUNT_MSAT(0)) || amount_msat_less(added->amount, channel->our_config.htlc_minimum)) { @@ -2280,7 +2281,8 @@ void peer_got_revoke(struct channel *channel, const u8 *msg) * * - if the `per_commitment_secret` was not generated by the protocol * in [BOLT #3](03-transactions.md#per-commitment-secret-requirements): - * - MAY fail the channel. + * - MAY send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!wallet_shachain_add_hash(ld->wallet, &channel->their_shachain, @@ -2488,6 +2490,7 @@ void htlcs_notify_new_block(struct lightningd *ld, u32 height) * * - if an HTLC which it offered is in either node's current * commitment transaction, AND is past this timeout deadline: + * - SHOULD send an `error` to the receiving peer (if connected). * - MUST fail the channel. */ /* FIXME: use db to look this up in one go (earliest deadline per-peer) */ @@ -2532,6 +2535,7 @@ void htlcs_notify_new_block(struct lightningd *ld, u32 height) *... * - if an HTLC it has fulfilled is in either node's current commitment * transaction, AND is past this fulfillment deadline: + * - SHOULD send an `error` to the offering peer (if connected). * - MUST fail the channel. */ do { diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 0f95e3645dc3..2bf7d60106c3 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -1202,8 +1202,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state) &err, &warning)) { /* BOLT #1: * - * - if no existing channel is referred to by the - * message: + * - if no existing channel is referred to by `channel_id`: * - MUST ignore the message. */ /* In this case, is_peer_error returns true, but sets @@ -1850,13 +1849,14 @@ static u8 *accepter_commits(struct state *state, * The recipient: * - if `signature` is incorrect OR non-compliant with LOW-S-standard * rule...: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey, &remote_sig)) { /* BOLT #1: * - * ### The `error` Message + * ### The `error` and `warning` Messages *... * - when failure was caused by an invalid signature check: * - SHOULD include the raw, hex-encoded transaction in reply @@ -2575,14 +2575,15 @@ static u8 *opener_commits(struct state *state, * The recipient: * - if `signature` is incorrect OR non-compliant with LOW-S-standard * rule...: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (!check_tx_sig(local_commit, 0, NULL, wscript, &state->their_funding_pubkey, &remote_sig)) { /* BOLT #1: * - * ### The `error` Message + * ### The `error` and `warning` Messages *... * - when failure was caused by an invalid signature check: * - SHOULD include the raw, hex-encoded transaction in reply @@ -3588,7 +3589,7 @@ static void do_reconnect_dance(struct state *state) /* BOLT #2: * - if it has not sent `revoke_and_ack`, AND * `next_revocation_number` is not equal to 0: - * - SHOULD fail the channel. + * - SHOULD send an `error` and fail the channel. */ /* It's possible that we've opened an outdated copy of the * database, and the peer is very much ahead of us. diff --git a/openingd/openingd.c b/openingd/openingd.c index 04807cd5d2b6..5a83ae1c1c9e 100644 --- a/openingd/openingd.c +++ b/openingd/openingd.c @@ -192,8 +192,7 @@ static u8 *opening_negotiate_msg(const tal_t *ctx, struct state *state, &err, &warning)) { /* BOLT #1: * - * - if no existing channel is referred to by the - * message: + * - if no existing channel is referred to by `channel_id`: * - MUST ignore the message. */ /* In this case, is_peer_error returns true, but sets @@ -1107,7 +1106,8 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) * The recipient: * - if `signature` is incorrect OR non-compliant with LOW-S-standard * rule...: - * - MUST fail the channel. + * - MUST send a `warning` and close the connection, or send an + * `error` and fail the channel. */ local_commit = initial_channel_tx(state, &wscript, state->channel, &state->first_per_commitment_point[LOCAL], @@ -1125,7 +1125,7 @@ static u8 *fundee_channel(struct state *state, const u8 *open_channel_msg) &theirsig)) { /* BOLT #1: * - * ### The `error` Message + * ### The `error` and `warning` Messages *... * - when failure was caused by an invalid signature check: * - SHOULD include the raw, hex-encoded transaction in reply diff --git a/tests/test_closing.py b/tests/test_closing.py index 0013cde1529f..36c510b63cbd 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -1,5 +1,4 @@ from fixtures import * # noqa: F401,F403 -from flaky import flaky from pyln.client import RpcError, Millisatoshi from shutil import copyfile from pyln.testing.utils import SLOW_MACHINE @@ -3186,31 +3185,27 @@ def test_shutdown(node_factory): l1.rpc.stop() -@flaky @pytest.mark.developer("needs to set upfront_shutdown_script") def test_option_upfront_shutdown_script(node_factory, bitcoind, executor): - # There's a workaround in channeld, that it treats incoming errors - # before both sides are locked in as warnings; this happens in - # this test, so l1 reports the error as a warning! l1 = node_factory.get_node(start=False, allow_warning=True) # Insist on upfront script we're not going to match. # '0014' + l1.rpc.call('dev-listaddrs', [10])['addresses'][-1]['bech32_redeemscript'] l1.daemon.env["DEV_OPENINGD_UPFRONT_SHUTDOWN_SCRIPT"] = "00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8" l1.start() - l2 = node_factory.get_node() + l2 = node_factory.get_node(allow_warning=True) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fundchannel(l2, 1000000, False) - # This will block, as l12 will send an error but l2 will retry. + # This will block, as l1 will send a warning but l2 will retry. fut = executor.submit(l1.rpc.close, l2.info['id']) - # l2 will close unilaterally when it dislikes shutdown script. - l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') + # l2 will send a warning when it dislikes shutdown script. + l1.daemon.wait_for_log(r'WARNING.*scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') - # Clear channel. - wait_for(lambda: len(bitcoind.rpc.getrawmempool()) != 0) - bitcoind.generate_block(1) + # Close from l2's side and clear channel. + l2.rpc.close(l1.info['id'], unilateraltimeout=1) + bitcoind.generate_block(1, wait_for_mempool=1) fut.result(TIMEOUT) wait_for(lambda: [c['state'] for c in only_one(l1.rpc.listpeers()['peers'])['channels']] == ['ONCHAIN']) wait_for(lambda: [c['state'] for c in only_one(l2.rpc.listpeers()['peers'])['channels']] == ['ONCHAIN']) @@ -3219,14 +3214,12 @@ def test_option_upfront_shutdown_script(node_factory, bitcoind, executor): l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.fundchannel(l2, 1000000, False) - l2.rpc.close(l1.info['id']) + l2.rpc.close(l1.info['id'], unilateraltimeout=5) - # l2 will close unilaterally when it dislikes shutdown script. - l1.daemon.wait_for_log(r'scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') + # l2 will send warning unilaterally when it dislikes shutdown script. + l1.daemon.wait_for_log(r'WARNING.*scriptpubkey .* is not as agreed upfront \(00143d43d226bcc27019ade52d7a3dc52a7ac1be28b8\)') - # Clear channel. - wait_for(lambda: len(bitcoind.rpc.getrawmempool()) != 0) - bitcoind.generate_block(1) + bitcoind.generate_block(1, wait_for_mempool=1) wait_for(lambda: [c['state'] for c in only_one(l1.rpc.listpeers()['peers'])['channels']] == ['ONCHAIN', 'ONCHAIN']) wait_for(lambda: [c['state'] for c in only_one(l2.rpc.listpeers()['peers'])['channels']] == ['ONCHAIN', 'ONCHAIN']) diff --git a/wire/extracted_peer_02_warning.patch b/wire/extracted_peer_02_warning.patch deleted file mode 100644 index 6dc9e7c5bdac..000000000000 --- a/wire/extracted_peer_02_warning.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- wire/peer_exp_wire.csv 2021-01-14 11:00:27.526336550 +1030 -+++ - 2021-01-21 15:31:37.071118999 +1030 -@@ -10,6 +10,10 @@ - msgdata,error,channel_id,channel_id, - msgdata,error,len,u16, - msgdata,error,data,byte,len -+msgtype,warning,1 -+msgdata,warning,channel_id,channel_id, -+msgdata,warning,len,u16, -+msgdata,warning,data,byte,len - msgtype,ping,18 - msgdata,ping,num_pong_bytes,u16, - msgdata,ping,byteslen,u16, From 42f5df5f0018c479d81fff7ea130a050da93e7d8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 06/12] bolt11: support payment_metadata. Signed-off-by: Rusty Russell --- Makefile | 2 +- common/bolt11.c | 53 +++++++++++++++++++++++++-- common/bolt11.h | 3 ++ common/bolt11_json.c | 2 + common/features.c | 10 ++++- common/features.h | 2 + common/test/run-bolt11.c | 46 +++++++++++++++++++++++ devtools/bolt11-cli.c | 4 ++ doc/lightning-decode.7.md | 3 +- doc/lightning-decodepay.7.md | 3 +- doc/schemas/decode.schema.json | 6 +++ doc/schemas/decodepay.schema.json | 4 ++ lightningd/lightningd.c | 1 + tests/test_pay.py | 6 +++ wire/extracted_onion_01_offers.patch | 4 +- wire/extracted_onion_exp_enctlv.patch | 4 +- wire/onion_wire.csv | 2 + 17 files changed, 145 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index a61d2b684019..a835e78d8e54 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ CCANDIR := ccan # Where we keep the BOLT RFCs BOLTDIR := ../lightning-rfc/ -DEFAULT_BOLTVERSION := 93909f67f6a48ee3f155a6224c182e612dd5f187 +DEFAULT_BOLTVERSION := f6c4d7604150986894bcb46d67c5c88680740b12 # Can be overridden on cmdline. BOLTVERSION := $(DEFAULT_BOLTVERSION) diff --git a/common/bolt11.c b/common/bolt11.c index b33ac132ec1c..a4cc1df49b04 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -516,6 +516,33 @@ static char *decode_9(struct bolt11 *b11, return NULL; } +/* BOLT #11: + * + * `m` (27): `data_length` variable. Additional metadata to attach to + * the payment. Note that the size of this field is limited by the + * maximum hop payload size. Long metadata fields reduce the maximum + * route length. + */ +static char *decode_m(struct bolt11 *b11, + struct hash_u5 *hu5, + u5 **data, size_t *data_len, + size_t data_length, + bool *have_m) +{ + size_t mlen = (data_length * 5) / 8; + + if (*have_m) + return unknown_field(b11, hu5, data, data_len, 'm', + data_length); + + b11->metadata = tal_arr(b11, u8, mlen); + pull_bits_certain(hu5, data, data_len, b11->metadata, + data_length * 5, false); + + *have_m = true; + return NULL; +} + struct bolt11 *new_bolt11(const tal_t *ctx, const struct amount_msat *msat TAKES) { @@ -535,6 +562,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx, */ b11->min_final_cltv_expiry = 18; b11->payment_secret = NULL; + b11->metadata = NULL; if (msat) b11->msat = tal_dup(b11, struct amount_msat, msat); @@ -557,7 +585,7 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, struct bolt11 *b11 = new_bolt11(ctx, NULL); struct hash_u5 hu5; bool have_p = false, have_d = false, have_h = false, - have_x = false, have_c = false, have_s = false; + have_x = false, have_c = false, have_s = false, have_m = false; *have_n = false; b11->routes = tal_arr(b11, struct route_info *, 0); @@ -760,6 +788,10 @@ struct bolt11 *bolt11_decode_nosig(const tal_t *ctx, const char *str, problem = decode_s(b11, &hu5, &data, &data_len, data_length, &have_s); break; + case 'm': + problem = decode_m(b11, &hu5, &data, &data_len, + data_length, &have_m); + break; default: unknown_field(b11, &hu5, &data, &data_len, bech32_charset[type], data_length); @@ -936,6 +968,11 @@ static void encode_p(u5 **data, const struct sha256 *hash) push_field(data, 'p', hash, 256); } +static void encode_m(u5 **data, const u8 *metadata) +{ + push_field(data, 'm', metadata, tal_bytelen(metadata) * CHAR_BIT); +} + static void encode_d(u5 **data, const char *description) { push_field(data, 'd', description, strlen(description) * CHAR_BIT); @@ -1011,13 +1048,20 @@ static void encode_r(u5 **data, const struct route_info *r) tal_free(rinfo); } -static void maybe_encode_9(u5 **data, const u8 *features) +static void maybe_encode_9(u5 **data, const u8 *features, + bool have_payment_metadata) { u5 *f5 = tal_arr(NULL, u5, 0); for (size_t i = 0; i < tal_count(features) * CHAR_BIT; i++) { if (!feature_is_set(features, i)) continue; + + /* Don't set option_payment_metadata unless we acually use it */ + if (!have_payment_metadata + && COMPULSORY_FEATURE(i) == OPT_PAYMENT_METADATA) + continue; + /* We expand it out so it makes a BE 5-bit/btye bitfield */ set_feature_bit(&f5, (i / 5) * 8 + (i % 5)); } @@ -1136,6 +1180,9 @@ char *bolt11_encode_(const tal_t *ctx, if (b11->expiry != DEFAULT_X) encode_x(&data, b11->expiry); + if (b11->metadata) + encode_m(&data, b11->metadata); + /* BOLT #11: * - MUST include one `c` field (`min_final_cltv_expiry`). */ @@ -1150,7 +1197,7 @@ char *bolt11_encode_(const tal_t *ctx, for (size_t i = 0; i < tal_count(b11->routes); i++) encode_r(&data, b11->routes[i]); - maybe_encode_9(&data, b11->features); + maybe_encode_9(&data, b11->features, b11->metadata != NULL); list_for_each(&b11->extra_fields, extra, list) if (!encode_extra(&data, extra)) diff --git a/common/bolt11.h b/common/bolt11.h index 3dea30b82f35..19b87f78fc8c 100644 --- a/common/bolt11.h +++ b/common/bolt11.h @@ -76,6 +76,9 @@ struct bolt11 { /* Features bitmap, if any. */ u8 *features; + /* Optional metadata to send with payment. */ + u8 *metadata; + struct list_head extra_fields; }; diff --git a/common/bolt11_json.c b/common/bolt11_json.c index 4fc1dacec925..b2280c47d157 100644 --- a/common/bolt11_json.c +++ b/common/bolt11_json.c @@ -66,6 +66,8 @@ void json_add_bolt11(struct json_stream *response, b11->payment_secret); if (b11->features) json_add_hex_talarr(response, "features", b11->features); + if (b11->metadata) + json_add_hex_talarr(response, "payment_metadata", b11->metadata); if (tal_count(b11->fallbacks)) { json_array_start(response, "fallbacks"); for (size_t i = 0; i < tal_count(b11->fallbacks); i++) diff --git a/common/features.c b/common/features.c index 777afbe3c8d7..e95d631e8964 100644 --- a/common/features.c +++ b/common/features.c @@ -97,6 +97,14 @@ static const struct feature_style feature_styles[] = { .copy_style = { [INIT_FEATURE] = FEATURE_REPRESENT, [NODE_ANNOUNCE_FEATURE] = FEATURE_REPRESENT, [CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } }, + { OPT_PAYMENT_METADATA, + .copy_style = { [INIT_FEATURE] = FEATURE_DONT_REPRESENT, + [NODE_ANNOUNCE_FEATURE] = FEATURE_DONT_REPRESENT, + /* Note: we don't actually set this in invoices, since + * we don't need to use it, but if we don't set it here + * we refuse to parse it. */ + [BOLT11_FEATURE] = FEATURE_REPRESENT, + [CHANNEL_FEATURE] = FEATURE_DONT_REPRESENT } }, }; struct dependency { @@ -416,7 +424,7 @@ const char *feature_name(const tal_t *ctx, size_t f) "option_provide_peer_backup", /* https://github.com/lightningnetwork/lightning-rfc/pull/881 */ NULL, NULL, - NULL, + "option_payment_metadata", NULL, /* 50/51 */ NULL, "option_keysend", diff --git a/common/features.h b/common/features.h index 1aa8ca82994e..3bea463565c8 100644 --- a/common/features.h +++ b/common/features.h @@ -119,6 +119,7 @@ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); * | 20/21 | `option_anchor_outputs` |... IN ... * | 22/23 | `option_anchors_zero_fee_htlc_tx` |... IN ... * | 26/27 | `option_shutdown_anysegwit` |... IN ... + * | 48/49 | `option_payment_metadata` |... 9 ... */ #define OPT_PAYMENT_SECRET 14 #define OPT_BASIC_MPP 16 @@ -126,6 +127,7 @@ const char *fmt_featurebits(const tal_t *ctx, const u8 *featurebits); #define OPT_ANCHOR_OUTPUTS 20 #define OPT_ANCHORS_ZERO_FEE_HTLC_TX 22 #define OPT_SHUTDOWN_ANYSEGWIT 26 +#define OPT_PAYMENT_METADATA 48 /* BOLT-f53ca2301232db780843e894f55d95d512f297f9 #9: * | 28/29 | `option_dual_fund` | ... IN9 ... diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 4ed5e8369fe3..488b848cdd62 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -564,6 +564,52 @@ int main(int argc, char *argv[]) memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); test_b11("lnbc9678785340p1pwmna7lpp5gc3xfm08u9qy06djf8dfflhugl6p7lgza6dsjxq454gxhj9t7a0sd8dgfkx7cmtwd68yetpd5s9xar0wfjn5gpc8qhrsdfq24f5ggrxdaezqsnvda3kkum5wfjkzmfqf3jkgem9wgsyuctwdus9xgrcyqcjcgpzgfskx6eqf9hzqnteypzxz7fzypfhg6trddjhygrcyqezcgpzfysywmm5ypxxjemgw3hxjmn8yptk7untd9hxwg3q2d6xjcmtv4ezq7pqxgsxzmnyyqcjqmt0wfjjq6t5v4khxsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsxqyjw5qcqp2rzjq0gxwkzc8w6323m55m4jyxcjwmy7stt9hwkwe2qxmy8zpsgg7jcuwz87fcqqeuqqqyqqqqlgqqqqn3qq9q9qrsgqrvgkpnmps664wgkp43l22qsgdw4ve24aca4nymnxddlnp8vh9v2sdxlu5ywdxefsfvm0fq3sesf08uf6q9a2ke0hc9j6z6wlxg5z5kqpu2v9wz", b11, NULL); + /* BOLT #11: + * > ### Please send 0.01 BTC with payment metadata 0x01fafaf0 + * > lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc + * + * Breakdown: + * + * * `lnbc`: prefix, Lightning on Bitcoin mainnet + * * `10m`: amount (10 milli-bitcoin) + * * `1`: Bech32 separator + * * `pvjluez`: timestamp (1496314658) + * * `p`: payment hash + * * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52) + * * `qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypq`: payment hash 0001020304050607080900010203040506070809000102030405060708090102 + * * `d`: short description + * * `p9`: `data_length` (`p` = 1, `9` = 5; 1 * 32 + 5 == 37) + * * `wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2`: 'payment metadata inside' + * * `m`: metadata + * * `q8`: `data_length` (`q` = 0, `8` = 7; 0 * 32 + 7 == 7) + * * `q8a04uq`: 0x01fafaf0 + * * `s`: payment secret + * * `p5`: `data_length` (`p` = 1, `5` = 20; 1 * 32 + 20 == 52) + * * `zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs`: 0x1111111111111111111111111111111111111111111111111111111111111111 + * * `9`: features + * * `q2`: `data_length` (`q` = 0, `2` = 10; 0 * 32 + 10 == 10) + * * `gqqqqqqsgq`: [b01000000000000000000000000000000000100000100000000] = 8 + 14 + 48 + * * `7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqp`: signature + * * `d05wjc`: Bech32 checksum + */ + msatoshi = AMOUNT_MSAT(1000000000); + b11 = new_bolt11(tmpctx, &msatoshi); + b11->chain = chainparams_for_network("bitcoin"); + b11->timestamp = 1496314658; + if (!hex_decode("0001020304050607080900010203040506070809000102030405060708090102", + strlen("0001020304050607080900010203040506070809000102030405060708090102"), + &b11->payment_hash, sizeof(b11->payment_hash))) + abort(); + b11->receiver_id = node; + b11->description = "payment metadata inside"; + b11->metadata = tal_hexdata(b11, "01fafaf0", strlen("01fafaf0")); + set_feature_bit(&b11->features, 8); + set_feature_bit(&b11->features, 14); + set_feature_bit(&b11->features, 48); + b11->payment_secret = tal(b11, struct secret); + memset(b11->payment_secret, 0x11, sizeof(*b11->payment_secret)); + test_b11("lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc", b11, NULL); + /* BOLT #11: * * > ### Bech32 checksum is invalid. diff --git a/devtools/bolt11-cli.c b/devtools/bolt11-cli.c index cb644baab72e..018d0e8af7f8 100644 --- a/devtools/bolt11-cli.c +++ b/devtools/bolt11-cli.c @@ -163,6 +163,10 @@ int main(int argc, char *argv[]) printf("\n"); } + if (b11->metadata) + printf("metadata: %s\n", + tal_hex(ctx, b11->metadata)); + list_for_each(&b11->extra_fields, extra, list) { char *data = tal_arr(ctx, char, tal_count(extra->data)+1); diff --git a/doc/lightning-decode.7.md b/doc/lightning-decode.7.md index 81d8a62b9453..de4dc749d058 100644 --- a/doc/lightning-decode.7.md +++ b/doc/lightning-decode.7.md @@ -143,6 +143,7 @@ If **type** is "bolt11 invoice", and **valid** is *true*: - **description_hash** (hex, optional): the hash of the description, in place of *description* (always 64 characters) - **payment_secret** (hex, optional): the secret to hand to the payee node (always 64 characters) - **features** (hex, optional): the features bitmap for this invoice + - **payment_metadata** (hex, optional): the payment_metadata to put in the payment - **fallbacks** (array of objects, optional): onchain addresses: - **type** (string): the address type (if known) (one of "P2PKH", "P2SH", "P2WPKH", "P2WSH") - **hex** (hex): Raw encoded address @@ -180,4 +181,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:d05b5fc1bf230b3bbd03e2023fb0c6bbefb700f7c3cfb43512da48dbce45f005) +[comment]: # ( SHA256STAMP:6ccf1b9195e64f897f65198a81c47bbd7e16387e4bdc74d624e2ec04a24e9873) diff --git a/doc/lightning-decodepay.7.md b/doc/lightning-decodepay.7.md index bbdc75c04892..300d80451737 100644 --- a/doc/lightning-decodepay.7.md +++ b/doc/lightning-decodepay.7.md @@ -29,6 +29,7 @@ On success, an object is returned, containing: - **description_hash** (hex, optional): the hash of the description, in place of *description* (always 64 characters) - **payment_secret** (hex, optional): the secret to hand to the payee node (always 64 characters) - **features** (hex, optional): the features bitmap for this invoice +- **payment_metadata** (hex, optional): the payment_metadata to put in the payment - **fallbacks** (array of objects, optional): onchain addresses: - **type** (string): the address type (if known) (one of "P2PKH", "P2SH", "P2WPKH", "P2WSH") - **hex** (hex): Raw encoded address @@ -69,4 +70,4 @@ RESOURCES Main web site: -[comment]: # ( SHA256STAMP:d92e1197708fff40f8ad71ccec3c0d8122d8088da1803c02bb042b09dbf2ee33) +[comment]: # ( SHA256STAMP:17cb6c66c75e907f3a2583d702aec2fc6e5a7b6026d05a3ed9957304799c9aef) diff --git a/doc/schemas/decode.schema.json b/doc/schemas/decode.schema.json index 808ef8f4313d..2c84e820bd54 100644 --- a/doc/schemas/decode.schema.json +++ b/doc/schemas/decode.schema.json @@ -746,6 +746,8 @@ ], "additionalProperties": false, "properties": { + "type": {}, + "valid": {}, "currency": { "type": "string", "description": "the BIP173 name for the currency" @@ -804,6 +806,10 @@ "type": "hex", "description": "the features bitmap for this invoice" }, + "payment_metadata": { + "type": "hex", + "description": "the payment_metadata to put in the payment" + }, "fallbacks": { "type": "array", "description": "onchain addresses", diff --git a/doc/schemas/decodepay.schema.json b/doc/schemas/decodepay.schema.json index 15fd12298657..0823f7afa454 100644 --- a/doc/schemas/decodepay.schema.json +++ b/doc/schemas/decodepay.schema.json @@ -70,6 +70,10 @@ "type": "hex", "description": "the features bitmap for this invoice" }, + "payment_metadata": { + "type": "hex", + "description": "the payment_metadata to put in the payment" + }, "fallbacks": { "type": "array", "description": "onchain addresses", diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index c55e861d2a2b..bb4a1ac44ad1 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -823,6 +823,7 @@ static struct feature_set *default_features(const tal_t *ctx) OPTIONAL_FEATURE(OPT_GOSSIP_QUERIES_EX), OPTIONAL_FEATURE(OPT_STATIC_REMOTEKEY), OPTIONAL_FEATURE(OPT_SHUTDOWN_ANYSEGWIT), + OPTIONAL_FEATURE(OPT_PAYMENT_METADATA), #if EXPERIMENTAL_FEATURES OPTIONAL_FEATURE(OPT_ANCHOR_OUTPUTS), OPTIONAL_FEATURE(OPT_QUIESCE), diff --git a/tests/test_pay.py b/tests/test_pay.py index 96a65f9716b1..f8682643c036 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5236,3 +5236,9 @@ def test_pay_manual_exclude(node_factory, bitcoind): # Exclude direct channel id with pytest.raises(RpcError, match=r'is not reachable directly and all routehints were unusable.'): l2.rpc.pay(inv, exclude=[scid23]) + + +def test_pay_bolt11_metadata(node_factory, bitcoind): + l1 = node_factory.get_node() + + l1.rpc.decode('lnbcrt10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqcqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqrk6hdutpaetmm3afjn0vfczgeyv0cy739rr939kwd4h5j3khxcskhgf59eaqy8wyq82tsnaqc5y32ed4jg34jw7rmeva9u6kfhymawgptmy5f6') diff --git a/wire/extracted_onion_01_offers.patch b/wire/extracted_onion_01_offers.patch index 90c0cb6c41ac..898c1373df3d 100644 --- a/wire/extracted_onion_01_offers.patch +++ b/wire/extracted_onion_01_offers.patch @@ -1,9 +1,9 @@ --- wire/extracted_onion_wire_csv 2020-03-25 10:24:12.861645774 +1030 +++ - 2020-03-26 13:47:13.498294435 +1030 @@ -8,6 +8,30 @@ - tlvtype,tlv_payload,payment_data,8 - tlvdata,tlv_payload,payment_data,payment_secret,byte,32 tlvdata,tlv_payload,payment_data,total_msat,tu64, + tlvtype,tlv_payload,payment_metadata,16 + tlvdata,tlv_payload,payment_metadata,payment_metadata,byte,... +tlvtype,obs2_onionmsg_payload,reply_path,2 +tlvdata,obs2_onionmsg_payload,reply_path,first_node_id,point, +tlvdata,obs2_onionmsg_payload,reply_path,blinding,point, diff --git a/wire/extracted_onion_exp_enctlv.patch b/wire/extracted_onion_exp_enctlv.patch index 1897193b8c8b..da51d82268bc 100644 --- a/wire/extracted_onion_exp_enctlv.patch +++ b/wire/extracted_onion_exp_enctlv.patch @@ -2,10 +2,12 @@ +++ - 2020-03-20 15:11:55.763880895 +1030 --- wire/onion_exp_wire.csv.~1~ 2021-11-17 10:56:59.947630815 +1030 +++ wire/onion_exp_wire.csv 2021-11-17 10:59:39.304581244 +1030 -@@ -8,6 +8,10 @@ +@@ -8,8 +8,12 @@ tlvtype,tlv_payload,payment_data,8 tlvdata,tlv_payload,payment_data,payment_secret,byte,32 tlvdata,tlv_payload,payment_data,total_msat,tu64, + tlvtype,tlv_payload,payment_metadata,16 + tlvdata,tlv_payload,payment_metadata,payment_metadata,byte,... +tlvtype,tlv_payload,encrypted_recipient_data,10 +tlvdata,tlv_payload,encrypted_recipient_data,encrypted_data,byte,... +tlvtype,tlv_payload,blinding_point,12 diff --git a/wire/onion_wire.csv b/wire/onion_wire.csv index 28c58724d8b5..9f255bdaf017 100644 --- a/wire/onion_wire.csv +++ b/wire/onion_wire.csv @@ -8,6 +8,8 @@ tlvdata,tlv_payload,short_channel_id,short_channel_id,short_channel_id, tlvtype,tlv_payload,payment_data,8 tlvdata,tlv_payload,payment_data,payment_secret,byte,32 tlvdata,tlv_payload,payment_data,total_msat,tu64, +tlvtype,tlv_payload,payment_metadata,16 +tlvdata,tlv_payload,payment_metadata,payment_metadata,byte,... tlvtype,obs2_onionmsg_payload,reply_path,2 tlvdata,obs2_onionmsg_payload,reply_path,first_node_id,point, tlvdata,obs2_onionmsg_payload,reply_path,blinding,point, From 5f9d49222c1980e8a89d1d2e4659a4f91e1b1593 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 07/12] lightningd: metadata received support (log and decline). Signed-off-by: Rusty Russell --- common/onion.c | 7 +++++++ common/onion.h | 1 + lightningd/peer_htlcs.c | 31 +++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/common/onion.c b/common/onion.c index 5fdcf757905a..5f3f71bc4c4a 100644 --- a/common/onion.c +++ b/common/onion.c @@ -241,6 +241,7 @@ struct onion_payload *onion_decode(const tal_t *ctx, p->amt_to_forward = fromwire_amount_msat(&cursor, &max); p->outgoing_cltv = fromwire_u32(&cursor, &max); p->payment_secret = NULL; + p->payment_metadata = NULL; p->blinding = NULL; /* We can't handle blinding with a legacy payload */ if (blinding) @@ -365,6 +366,12 @@ struct onion_payload *onion_decode(const tal_t *ctx, *p->total_msat = amount_msat(tlv->payment_data->total_msat); } + if (tlv->payment_metadata) + p->payment_metadata + = tal_dup_talarr(p, u8, tlv->payment_metadata); + else + p->payment_metadata = NULL; + p->tlv = tal_steal(p, tlv); return p; diff --git a/common/onion.h b/common/onion.h index 6f3045faf57c..828a6735df1c 100644 --- a/common/onion.h +++ b/common/onion.h @@ -19,6 +19,7 @@ struct onion_payload { struct amount_msat *total_msat; struct short_channel_id *forward_channel; struct secret *payment_secret; + u8 *payment_metadata; /* If blinding is set, blinding_ss is the shared secret.*/ struct pubkey *blinding; diff --git a/lightningd/peer_htlcs.c b/lightningd/peer_htlcs.c index 0f506c3b98f6..763ce23a4fb1 100644 --- a/lightningd/peer_htlcs.c +++ b/lightningd/peer_htlcs.c @@ -363,7 +363,8 @@ static void handle_localpay(struct htlc_in *hin, struct amount_msat amt_to_forward, u32 outgoing_cltv_value, struct amount_msat total_msat, - const struct secret *payment_secret) + const struct secret *payment_secret, + const u8 *payment_metadata) { const u8 *failmsg; struct lightningd *ld = hin->key.channel->peer->ld; @@ -424,6 +425,27 @@ static void handle_localpay(struct htlc_in *hin, goto fail; } + /* We don't expect payment_metadata; reject here */ + if (payment_metadata) { + log_debug(hin->key.channel->log, + "Unexpected payment_metadata %s", + tal_hex(tmpctx, payment_metadata)); + /* BOLT #4: + * 1. type: PERM|22 (`invalid_onion_payload`) + * 2. data: + * * [`bigsize`:`type`] + * * [`u16`:`offset`] + * + * The decrypted onion per-hop payload was not understood by the processing node + * or is incomplete. If the failure can be narrowed down to a specific tlv type in + * the payload, the erring node may include that `type` and its byte `offset` in + * the decrypted byte stream. + */ + failmsg = towire_invalid_onion_payload(NULL, TLV_TLV_PAYLOAD_PAYMENT_METADATA, + /* FIXME: offset? */ 0); + goto fail; + } + htlc_set_add(ld, hin, total_msat, payment_secret); return; @@ -1033,6 +1055,10 @@ static void htlc_accepted_hook_serialize(struct htlc_accepted_hook_payload *p, json_add_secret(s, "payment_secret", p->payload->payment_secret); } + if (p->payload->payment_metadata) { + json_add_hex_talarr(s, "payment_metadata", + p->payload->payment_metadata); + } } json_add_hex_talarr(s, "next_onion", p->next_onion); json_add_secret(s, "shared_secret", hin->shared_secret); @@ -1082,7 +1108,8 @@ htlc_accepted_hook_final(struct htlc_accepted_hook_payload *request STEALS) request->payload->amt_to_forward, request->payload->outgoing_cltv, *request->payload->total_msat, - request->payload->payment_secret); + request->payload->payment_secret, + request->payload->payment_metadata); tal_free(request); } From 0550f6f5d46905af902f553a0e424f1bdf1f36fd Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 08/12] sendpay: add payment_metadata argument. And document the missing arguments. Signed-off-by: Rusty Russell --- common/onion.c | 4 +++- common/onion.h | 5 +++-- contrib/pyln-client/pyln/client/lightning.py | 3 ++- devtools/onion.c | 2 +- doc/lightning-sendpay.7.md | 13 ++++++++++++- lightningd/pay.c | 12 ++++++++---- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/common/onion.c b/common/onion.c index 5f3f71bc4c4a..45325e25ec17 100644 --- a/common/onion.c +++ b/common/onion.c @@ -71,7 +71,8 @@ u8 *onion_final_hop(const tal_t *ctx, struct amount_msat total_msat, const struct pubkey *blinding, const u8 *enctlv, - const struct secret *payment_secret) + const struct secret *payment_secret, + const u8 *payment_metadata) { struct tlv_tlv_payload *tlv = tlv_tlv_payload_new(tmpctx); struct tlv_tlv_payload_payment_data tlv_pdata; @@ -102,6 +103,7 @@ u8 *onion_final_hop(const tal_t *ctx, tlv_pdata.total_msat = total_msat.millisatoshis; /* Raw: TLV convert */ tlv->payment_data = &tlv_pdata; } + tlv->payment_metadata = cast_const(u8 *, payment_metadata); #if EXPERIMENTAL_FEATURES tlv->blinding_point = cast_const(struct pubkey *, blinding); tlv->encrypted_recipient_data = cast_const(u8 *, enctlv); diff --git a/common/onion.h b/common/onion.h index 828a6735df1c..839fa5048f03 100644 --- a/common/onion.h +++ b/common/onion.h @@ -36,14 +36,15 @@ u8 *onion_nonfinal_hop(const tal_t *ctx, const struct pubkey *blinding, const u8 *enctlv); -/* Note that this can fail if we supply payment_secret and !use_tlv! */ +/* Note that this can fail if we supply payment_secret or payment_metadata and !use_tlv! */ u8 *onion_final_hop(const tal_t *ctx, struct amount_msat forward, u32 outgoing_cltv, struct amount_msat total_msat, const struct pubkey *blinding, const u8 *enctlv, - const struct secret *payment_secret); + const struct secret *payment_secret, + const u8 *payment_metadata); /** * onion_payload_length: measure payload length in decrypted onion. diff --git a/contrib/pyln-client/pyln/client/lightning.py b/contrib/pyln-client/pyln/client/lightning.py index f7567fcf5c4b..52e5c3fe34a9 100644 --- a/contrib/pyln-client/pyln/client/lightning.py +++ b/contrib/pyln-client/pyln/client/lightning.py @@ -1128,7 +1128,7 @@ def plugin_rescan(self): } return self.call("plugin", payload) - def sendpay(self, route, payment_hash, label=None, msatoshi=None, bolt11=None, payment_secret=None, partid=None, groupid=None): + def sendpay(self, route, payment_hash, label=None, msatoshi=None, bolt11=None, payment_secret=None, partid=None, groupid=None, payment_metadata=None): """ Send along {route} in return for preimage of {payment_hash}. """ @@ -1141,6 +1141,7 @@ def sendpay(self, route, payment_hash, label=None, msatoshi=None, bolt11=None, p "payment_secret": payment_secret, "partid": partid, "groupid": groupid, + "payment_metadata": payment_metadata, } return self.call("sendpay", payload) diff --git a/devtools/onion.c b/devtools/onion.c index f750bedd4454..82e5129cb6a6 100644 --- a/devtools/onion.c +++ b/devtools/onion.c @@ -80,7 +80,7 @@ static void do_generate(int argc, char **argv, take(onion_final_hop(NULL, amt, i, amt, NULL, NULL, - NULL))); + NULL, NULL))); else sphinx_add_hop(sp, &path[i], take(onion_nonfinal_hop(NULL, diff --git a/doc/lightning-sendpay.7.md b/doc/lightning-sendpay.7.md index c8d782154490..ec7aec712a12 100644 --- a/doc/lightning-sendpay.7.md +++ b/doc/lightning-sendpay.7.md @@ -5,7 +5,7 @@ SYNOPSIS -------- **sendpay** *route* *payment\_hash* [*label*] [*msatoshi*] -[*bolt11*] [*payment_secret*] [*partid*] +[*bolt11*] [*payment_secret*] [*partid*] [*localofferid*] [*groupid*] [*payment_metadata*] DESCRIPTION ----------- @@ -44,6 +44,16 @@ partial payments with the same *payment_hash*. The *msatoshi* amount *payment_hash* must be equal, and **sendpay** will fail if there are already *msatoshi* worth of payments pending. +The *localofferid* value indicates that this payment is being made for a local +send_invoice offer: this ensures that we only send a payment for a single-use +offer once. + +*groupid* allows you to attach a number which appears in **listsendpays** so +payments can be identified as part of a logical group. The *pay* plugin uses +this to identify one attempt at a MPP payment, for example. + +*payment_metadata* is placed in the final onion hop TLV. + Once a payment has succeeded, calls to **sendpay** with the same *payment\_hash* but a different *msatoshi* or destination will fail; this prevents accidental multiple payments. Calls to **sendpay** with @@ -94,6 +104,7 @@ The following error codes may occur: will be routing failure object. - 204: Failure along route; retry a different route. The *data* field of the error will be routing failure object. +- 212: *localofferid* refers to an invalid, or used, local offer. A routing failure object has the fields below: - *erring\_index*. The index of the node along the route that reported diff --git a/lightningd/pay.c b/lightningd/pay.c index 58463ee10da7..9e29f92d09ed 100644 --- a/lightningd/pay.c +++ b/lightningd/pay.c @@ -1122,7 +1122,8 @@ send_payment(struct lightningd *ld, const char *label TAKES, const char *invstring TAKES, const struct sha256 *local_offer_id, - const struct secret *payment_secret) + const struct secret *payment_secret, + const u8 *payment_metadata) { unsigned int base_expiry; struct onionpacket *packet; @@ -1174,7 +1175,7 @@ send_payment(struct lightningd *ld, route[i].amount, base_expiry + route[i].delay, total_msat, route[i].blinding, route[i].enctlv, - payment_secret); + payment_secret, payment_metadata); if (!onion) { return command_fail(cmd, PAY_DESTINATION_PERM_FAIL, "Destination does not support" @@ -1422,7 +1423,8 @@ static struct command_result *json_sendpay(struct command *cmd, const char *invstring, *label; u64 *partid, *group; struct secret *payment_secret; - struct sha256 *local_offer_id = NULL; + struct sha256 *local_offer_id; + u8 *payment_metadata; /* For generating help, give new-style. */ if (!param(cmd, buffer, params, @@ -1436,6 +1438,7 @@ static struct command_result *json_sendpay(struct command *cmd, p_opt_def("partid", param_u64, &partid, 0), p_opt("localofferid", param_sha256, &local_offer_id), p_opt("groupid", param_u64, &group), + p_opt("payment_metadata", param_bin_from_hex, &payment_metadata), NULL)) return command_param_failed(); @@ -1485,7 +1488,8 @@ static struct command_result *json_sendpay(struct command *cmd, route, final_amount, msat ? *msat : final_amount, - label, invstring, local_offer_id, payment_secret); + label, invstring, local_offer_id, + payment_secret, payment_metadata); } static const struct json_command sendpay_command = { From 1b0be2937b85b18741e9abffef6d1122a8b7bbb4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 09/12] plugins/pay: send payment_metadata if provided in invoice. Signed-off-by: Rusty Russell Changelog-Added: Protocol: `pay` (and decode, etc) supports bolt11 payment_metadata a-la https://github.com/lightning/bolts/pull/912 --- plugins/keysend.c | 1 + plugins/libplugin-pay.c | 14 ++++++++++---- plugins/libplugin-pay.h | 3 +++ plugins/pay.c | 15 +++++++++++++++ tests/test_pay.py | 21 +++++++++++++++++++-- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/plugins/keysend.c b/plugins/keysend.c index 7dff550b289a..22ae85e3b77e 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -179,6 +179,7 @@ static struct command_result *json_keysend(struct command *cmd, const char *buf, p->json_toks = params; p->destination = tal_steal(p, destination); p->payment_secret = NULL; + p->payment_metadata = NULL; p->amount = *msat; p->routes = tal_steal(p, hints); // 22 is the Rust-Lightning default and the highest minimum we know of. diff --git a/plugins/libplugin-pay.c b/plugins/libplugin-pay.c index f3f9d496d696..1c8779f411bf 100644 --- a/plugins/libplugin-pay.c +++ b/plugins/libplugin-pay.c @@ -1581,7 +1581,7 @@ static struct command_result *payment_createonion_success(struct command *cmd, /* Temporary serialization method for the tlv_payload.data until we rework the * API that is generated from the specs to use the setter/getter interface. */ static void tlvstream_set_tlv_payload_data(struct tlv_field **stream, - struct secret *payment_secret, + const struct secret *payment_secret, u64 total_msat) { u8 *ser = tal_arr(NULL, u8, 0); @@ -1596,7 +1596,8 @@ static void payment_add_hop_onion_payload(struct payment *p, struct route_hop *node, struct route_hop *next, bool final, - struct secret *payment_secret) + struct secret *payment_secret, + const u8 *payment_metadata) { struct createonion_request *cr = p->createonion_request; u32 cltv = p->start_block + next->delay + 1; @@ -1627,6 +1628,11 @@ static void payment_add_hop_onion_payload(struct payment *p, fields, payment_secret, root->amount.millisatoshis); /* Raw: TLV payload generation*/ } + if (payment_metadata != NULL) { + assert(final); + tlvstream_set_raw(fields, TLV_TLV_PAYLOAD_PAYMENT_METADATA, + payment_metadata, tal_bytelen(payment_metadata)); + } } static void payment_compute_onion_payloads(struct payment *p) @@ -1665,7 +1671,7 @@ static void payment_compute_onion_payloads(struct payment *p) * i+1 */ payment_add_hop_onion_payload(p, &cr->hops[i], &p->route[i], &p->route[i + 1], false, - NULL); + NULL, NULL); tal_append_fmt(&routetxt, "%s -> ", type_to_string(tmpctx, struct short_channel_id, &p->route[i].scid)); @@ -1675,7 +1681,7 @@ static void payment_compute_onion_payloads(struct payment *p) payment_add_hop_onion_payload( p, &cr->hops[hopcount - 1], &p->route[hopcount - 1], &p->route[hopcount - 1], true, - root->payment_secret); + root->payment_secret, root->payment_metadata); tal_append_fmt(&routetxt, "%s", type_to_string(tmpctx, struct short_channel_id, &p->route[hopcount - 1].scid)); diff --git a/plugins/libplugin-pay.h b/plugins/libplugin-pay.h index e1f14da44f73..86aea238c464 100644 --- a/plugins/libplugin-pay.h +++ b/plugins/libplugin-pay.h @@ -180,6 +180,9 @@ struct payment { /* Payment secret, from the invoice if any. */ struct secret *payment_secret; + /* Payment metadata, from the invoice if any. */ + u8 *payment_metadata; + u64 groupid; u32 partid; u32 next_partid; diff --git a/plugins/pay.c b/plugins/pay.c index 7d08e1731e43..9dfedfc25e3f 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -108,6 +108,9 @@ struct pay_command { /* Payment secret, if specified by invoice. */ const char *payment_secret; + /* Payment metadata, if specified by invoice. */ + const char *payment_metadata; + /* Description, if any. */ const char *label; @@ -849,6 +852,8 @@ static struct command_result *getroute_done(struct command *cmd, json_add_string(req->js, "label", pc->label); if (pc->payment_secret) json_add_string(req->js, "payment_secret", pc->payment_secret); + if (pc->payment_metadata) + json_add_string(req->js, "payment_metadata", pc->payment_metadata); return send_outreq(cmd->plugin, req); } @@ -1368,6 +1373,11 @@ static struct command_result *json_pay(struct command *cmd, sizeof(*b11->payment_secret)); else pc->payment_secret = NULL; + if (b11->metadata) + pc->payment_metadata = tal_hex(pc, b11->metadata); + else + pc->payment_metadata = NULL; + /* We try first without using routehint */ pc->current_routehint = NULL; pc->routehints = filter_routehints(pc, b11->routes); @@ -2380,6 +2390,10 @@ static struct command_result *json_paymod(struct command *cmd, p->payment_hash = tal_dup(p, struct sha256, &b11->payment_hash); p->payment_secret = tal_dup_or_null(p, struct secret, b11->payment_secret); + if (b11->metadata) + p->payment_metadata = tal_dup_talarr(p, u8, b11->metadata); + else + p->payment_metadata = NULL; /* FIXME: libplugin-pay plays with this array, and there are many FIXMEs * about it. But it looks like a leak, so we suppress it here. */ p->routes = notleak_with_children(tal_steal(p, b11->routes)); @@ -2439,6 +2453,7 @@ static struct command_result *json_paymod(struct command *cmd, BUILD_ASSERT(sizeof(*p->payment_secret) == sizeof(merkle)); } + p->payment_metadata = NULL; p->routes = NULL; /* FIXME: paths! */ if (b12->cltv) diff --git a/tests/test_pay.py b/tests/test_pay.py index f8682643c036..1778d6b83bfc 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -5238,7 +5238,24 @@ def test_pay_manual_exclude(node_factory, bitcoind): l2.rpc.pay(inv, exclude=[scid23]) +@unittest.skipIf(TEST_NETWORK != 'regtest', "Invoice is network specific") def test_pay_bolt11_metadata(node_factory, bitcoind): - l1 = node_factory.get_node() + l1, l2 = node_factory.line_graph(2) + + # BOLT #11: + # > ### Please send 0.01 BTC with payment metadata 0x01fafaf0 + # > lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc + + b11 = l1.rpc.decode('lnbc10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgq7hf8he7ecf7n4ffphs6awl9t6676rrclv9ckg3d3ncn7fct63p6s365duk5wrk202cfy3aj5xnnp5gs3vrdvruverwwq7yzhkf5a3xqpd05wjc') + assert b11['payment_metadata'] == '01fafaf0' + + # I previously hacked lightningd to add "this is metadata" to metadata. + # After CI started failing, I *also* hacked it to set expiry to BIGNUM. + inv = "lnbcrt1230n1p3yzgcxsp5q8g040f9rl9mu2unkjuj0vn262s6nyrhz5hythk3ueu2lfzahmzspp5ve584t0cv27hwmy0cx9ca8uwyqyfw9y9dm3r8vus9fv36r2l9yjsdq8v3jhxccmq6w35xjueqd9ejqmt9w3skgct5vyxqxra2q2qcqp99q2sqqqqqysgqfw6efxpzk5x5vfj8se46yg667x5cvhyttnmuqyk0q7rmhx3gs249qhtdggnek8c5adm2pztkjddlwyn2art2zg9xap2ckczzl3fzz4qqsej6mf" + # Make l2 "know" about this invoice. + l2.rpc.invoice(msatoshi='123000', label='label1', description='desc', preimage='00' * 32) + + with pytest.raises(RpcError, match=r'WIRE_INVALID_ONION_PAYLOAD'): + l1.rpc.pay(inv) - l1.rpc.decode('lnbcrt10m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdp9wpshjmt9de6zqmt9w3skgct5vysxjmnnd9jx2mq8q8a04uqcqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q2gqqqqqqsgqrk6hdutpaetmm3afjn0vfczgeyv0cy739rr939kwd4h5j3khxcskhgf59eaqy8wyq82tsnaqc5y32ed4jg34jw7rmeva9u6kfhymawgptmy5f6') + l2.daemon.wait_for_log("Unexpected payment_metadata {}".format(b'this is metadata'.hex())) From 8d9bd172e23966766f1358341d05848090ce0bb1 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 10/12] doc: update BOLTs to latest master. Just typo fixes and the like. Signed-off-by: Rusty Russell --- Makefile | 2 +- channeld/channeld.c | 12 +++++------- channeld/full_channel.c | 3 ++- closingd/closingd.c | 4 +++- common/features.c | 3 +-- hsmd/libhsmd.c | 6 +++--- openingd/dualopend.c | 4 ++-- wallet/wallet.c | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index a835e78d8e54..dd1eb972274e 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ CCANDIR := ccan # Where we keep the BOLT RFCs BOLTDIR := ../lightning-rfc/ -DEFAULT_BOLTVERSION := f6c4d7604150986894bcb46d67c5c88680740b12 +DEFAULT_BOLTVERSION := e60d594abf436e768116684080997a8d4f960263 # Can be overridden on cmdline. BOLTVERSION := $(DEFAULT_BOLTVERSION) diff --git a/channeld/channeld.c b/channeld/channeld.c index 24c41b9d108d..72cd437bfdd2 100644 --- a/channeld/channeld.c +++ b/channeld/channeld.c @@ -1107,7 +1107,7 @@ static struct bitcoin_signature *unraw_sigs(const tal_t *ctx, *... * * if `option_anchors` applies to this commitment * transaction, `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is - * used. + * used as described in [BOLT #5] */ if (option_anchor_outputs) sigs[i].sighash_type = SIGHASH_SINGLE|SIGHASH_ANYONECANPAY; @@ -2468,8 +2468,7 @@ static void resend_commitment(struct peer *peer, struct changed_htlc *last) /* BOLT #2: * * A receiving node: - * - if `option_static_remotekey` or `option_anchors` applies to the - * commitment transaction: + * - if `option_static_remotekey` applies to the commitment transaction: * - if `next_revocation_number` is greater than expected above, AND * `your_last_per_commitment_secret` is correct for that * `next_revocation_number` minus 1: @@ -2515,7 +2514,7 @@ static void check_future_dataloss_fields(struct peer *peer, /* BOLT #2: * - MUST NOT broadcast its commitment transaction. - * - SHOULD fail the channel. + * - SHOULD send an `error` to request the peer to fail the channel. * - SHOULD store `my_current_per_commitment_point` to * retrieve funds should the sending node broadcast its * commitment transaction on-chain. @@ -2532,8 +2531,7 @@ static void check_future_dataloss_fields(struct peer *peer, /* BOLT #2: * * A receiving node: - * - if `option_static_remotekey` or `option_anchors` applies to the - * commitment transaction: + * - if `option_static_remotekey` applies to the commitment transaction: * ... * - if `your_last_per_commitment_secret` does not match the expected values: * - SHOULD send an `error` and fail the channel. @@ -2797,7 +2795,7 @@ static void peer_reconnect(struct peer *peer, * of the next `commitment_signed` it expects to receive. * - MUST set `next_revocation_number` to the commitment number * of the next `revoke_and_ack` message it expects to receive. - * - if `option_static_remotekey` or `option_anchors` applies to the commitment transaction: + * - if `option_static_remotekey` applies to the commitment transaction: * - MUST set `my_current_per_commitment_point` to a valid point. * - otherwise: * - MUST set `my_current_per_commitment_point` to its commitment diff --git a/channeld/full_channel.c b/channeld/full_channel.c index 5c7102b24c61..87e736bb34ee 100644 --- a/channeld/full_channel.c +++ b/channeld/full_channel.c @@ -617,7 +617,8 @@ static enum channel_add_err add_htlc(struct channel *channel, * * - if a sending node adds more than receiver `max_accepted_htlcs` * HTLCs to its local commitment transaction... - * - SHOULD fail the channel. + * - SHOULD send a `warning` and close the connection, or send an + * `error` and fail the channel. */ if (htlc_count + 1 > channel->config[recipient].max_accepted_htlcs) { return CHANNEL_ERR_TOO_MANY_HTLCS; diff --git a/closingd/closingd.c b/closingd/closingd.c index e2a8fcbffe59..30739e0a5486 100644 --- a/closingd/closingd.c +++ b/closingd/closingd.c @@ -707,8 +707,10 @@ static void do_quickclose(struct amount_sat offer[NUM_SIDES], /* BOLT #2: * - if the message contains a `fee_range`: * - if there is no overlap between that and its own `fee_range`: - * - SHOULD fail the connection + * - SHOULD send a warning + * - MUST fail the channel if it doesn't receive a satisfying `fee_range` after a reasonable amount of time */ + /* (Note we satisfy the "MUST fail" by our close command unilteraltimeout) */ if (!get_overlap(our_feerange, their_feerange, &overlap)) { peer_failed_warn(pps, channel_id, "Unable to agree on a feerate." diff --git a/common/features.c b/common/features.c index e95d631e8964..bd7db0bfb4a1 100644 --- a/common/features.c +++ b/common/features.c @@ -131,8 +131,7 @@ static const struct dependency feature_deps[] = { * `option_anchor_outputs` | ... | ... | `option_static_remotekey` */ { OPT_ANCHOR_OUTPUTS, OPT_STATIC_REMOTEKEY }, - /* FIXME: This dep was added later! */ - /* BOLT-master #9: + /* BOLT #9: * Name | Description | Context | Dependencies | *... * `option_anchors_zero_fee_htlc_tx` | ... | ... | `option_static_remotekey` diff --git a/hsmd/libhsmd.c b/hsmd/libhsmd.c index b8e230718bab..6a5e349623d6 100644 --- a/hsmd/libhsmd.c +++ b/hsmd/libhsmd.c @@ -1124,7 +1124,7 @@ static u8 *handle_sign_local_htlc_tx(struct hsmd_client *c, const u8 *msg_in) * ## HTLC-Timeout and HTLC-Success Transactions *... * * if `option_anchors` applies to this commitment transaction, - * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used. + * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used as described in [BOLT #5] */ sign_tx_input(tx, 0, NULL, wscript, &htlc_privkey, &htlc_pubkey, option_anchor_outputs @@ -1177,7 +1177,7 @@ static u8 *handle_sign_remote_htlc_tx(struct hsmd_client *c, const u8 *msg_in) * ## HTLC-Timeout and HTLC-Success Transactions *... * * if `option_anchors` applies to this commitment transaction, - * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used. + * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used as described in [BOLT #5] */ sign_tx_input(tx, 0, NULL, wscript, &htlc_privkey, &htlc_pubkey, option_anchor_outputs @@ -1446,7 +1446,7 @@ static u8 *handle_sign_remote_htlc_to_us(struct hsmd_client *c, * ## HTLC-Timeout and HTLC-Success Transactions *... * * if `option_anchors` applies to this commitment transaction, - * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used. + * `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used as described in [BOLT #5] */ return handle_sign_to_us_tx( c, msg_in, tx, &privkey, wscript, diff --git a/openingd/dualopend.c b/openingd/dualopend.c index 2bf7d60106c3..737e9fb70aad 100644 --- a/openingd/dualopend.c +++ b/openingd/dualopend.c @@ -3458,7 +3458,7 @@ static u8 *handle_funding_depth(struct state *state, u8 *msg) /* BOLT #2: * * A receiving node: - * - if `option_static_remotekey` or `option_anchors` applies to the commitment transaction: + * - if `option_static_remotekey` applies to the commitment transaction: * - if `next_revocation_number` is greater than expected above, AND * `your_last_per_commitment_secret` is correct for that * `next_revocation_number` minus 1: @@ -3504,7 +3504,7 @@ check_future_dataloss_fields(struct state *state, /* BOLT #2: * - MUST NOT broadcast its commitment transaction. - * - SHOULD fail the channel. + * - SHOULD send an `error` to request the peer to fail the channel. */ wire_sync_write(REQ_FD, take(towire_dualopend_fail_fallen_behind(NULL))); diff --git a/wallet/wallet.c b/wallet/wallet.c index 93e52b54a594..bf0710b0f352 100644 --- a/wallet/wallet.c +++ b/wallet/wallet.c @@ -869,7 +869,7 @@ wallet_htlc_sigs_load(const tal_t *ctx, struct wallet *w, u64 channelid, *... * * if `option_anchors` applies to this commitment * transaction, `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is - * used. + * used as described in [BOLT #5] */ if (option_anchor_outputs) sig.sighash_type = SIGHASH_SINGLE|SIGHASH_ANYONECANPAY; From f3506854b3fc30603265c5a307c4e8bd2eff9b23 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 11/12] bolt11: reorder invoice production to match test vectors. After this, we can exactly reproduce the vectors (in DEVELOPER mode). 1. Move payment_metadata position to match test vector. 2. Create flag to suppress `c` field production. 3. Some vectors put secret before payment_hash, hack that in. Signed-off-by: Rusty Russell --- common/bolt11.c | 42 ++++++++++++++++++++++++++++++++++------ common/bolt11.h | 5 +++++ common/test/run-bolt11.c | 20 ++++++++++++------- 3 files changed, 54 insertions(+), 13 deletions(-) diff --git a/common/bolt11.c b/common/bolt11.c index a4cc1df49b04..29fd34fef066 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -11,6 +11,25 @@ #include #include +#if DEVELOPER +bool dev_bolt11_no_c_generation; + +/* For test vectors, older ones put p before s. */ +static bool modern_order(const struct bolt11 *b11) +{ + if (!b11->description) + return true; + if (streq(b11->description, + "Blockstream Store: 88.85 USD for Blockstream Ledger Nano S x 1, \"Back In My Day\" Sticker x 2, \"I Got Lightning Working\" Sticker x 2 and 1 more items")) + return false; + if (streq(b11->description, "coffee beans")) + return false; + if (streq(b11->description, "payment metadata inside")) + return false; + return true; +} +#endif + struct multiplier { const char letter; /* We can't represent p postfix to msat, so we multiply this by 10 */ @@ -996,6 +1015,8 @@ static void encode_x(u5 **data, u64 expiry) static void encode_c(u5 **data, u16 min_final_cltv_expiry) { + if (IFDEV(dev_bolt11_no_c_generation, false)) + return; push_varlen_field(data, 'c', min_final_cltv_expiry); } @@ -1154,6 +1175,13 @@ char *bolt11_encode_(const tal_t *ctx, */ push_varlen_uint(&data, b11->timestamp, 35); + /* This is a hack to match the test vectors, *some* of which + * order differently! */ + if (IFDEV(modern_order(b11), true)) { + if (b11->payment_secret) + encode_s(&data, b11->payment_secret); + } + /* BOLT #11: * * if a writer offers more than one of any field type, @@ -1174,23 +1202,25 @@ char *bolt11_encode_(const tal_t *ctx, else if (b11->description) encode_d(&data, b11->description); + if (b11->metadata) + encode_m(&data, b11->metadata); + if (n_field) encode_n(&data, &b11->receiver_id); + if (IFDEV(!modern_order(b11), false)) { + if (b11->payment_secret) + encode_s(&data, b11->payment_secret); + } + if (b11->expiry != DEFAULT_X) encode_x(&data, b11->expiry); - if (b11->metadata) - encode_m(&data, b11->metadata); - /* BOLT #11: * - MUST include one `c` field (`min_final_cltv_expiry`). */ encode_c(&data, b11->min_final_cltv_expiry); - if (b11->payment_secret) - encode_s(&data, b11->payment_secret); - for (size_t i = 0; i < tal_count(b11->fallbacks); i++) encode_f(&data, b11->fallbacks[i]); diff --git a/common/bolt11.h b/common/bolt11.h index 19b87f78fc8c..b561cf569ffc 100644 --- a/common/bolt11.h +++ b/common/bolt11.h @@ -125,4 +125,9 @@ char *bolt11_encode_(const tal_t *ctx, secp256k1_ecdsa_recoverable_signature *rsig), \ (arg)) +#if DEVELOPER +/* Flag for tests to suppress `min_final_cltv_expiry` field generation, to match test vectors */ +extern bool dev_bolt11_no_c_generation; +#endif + #endif /* LIGHTNING_COMMON_BOLT11_H */ diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 488b848cdd62..d4b2f6aa48c9 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -49,7 +49,6 @@ static void test_b11(const char *b11str, { struct bolt11 *b11; char *fail; - char *reproduce; struct bolt11_field *b11_extra, *expect_extra; b11 = bolt11_decode(tmpctx, b11str, NULL, hashed_desc, @@ -115,20 +114,22 @@ static void test_b11(const char *b11str, assert(!expect_extra); /* FIXME: Spec changed to require c fields, but test vectors don't! */ - if (b11->min_final_cltv_expiry == 18) - return; + +#if DEVELOPER + char *reproduce; + + dev_bolt11_no_c_generation = (b11->min_final_cltv_expiry == 18); /* Also blockstream store example signature doesn't match? */ /* Re-encode to check */ reproduce = bolt11_encode(tmpctx, b11, false, test_sign, NULL); -#if 0 for (size_t i = 0; i < strlen(reproduce); i++) { if (reproduce[i] != b11str[i] && reproduce[i] != tolower(b11str[i])) abort(); } -#endif assert(strlen(reproduce) == strlen(b11str)); +#endif } int main(int argc, char *argv[]) @@ -478,8 +479,13 @@ int main(int argc, char *argv[]) set_feature_bit(&b11->features, 100); badstr = bolt11_encode(tmpctx, b11, false, test_sign, NULL); - /* FIXME: above has missing c field! */ - assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpjsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqjckhuumq7mk7pdua9s6umdg34sjhlju9qgcvclxl35guw3dhhyrrtnmudz3kspyqk6k6r7thyzyrleq9s9lmgh59zlc49mc3nd7ngecqllqtym")); + /* Needs DEVELOPER to munge this into BOLT example order! */ +#if DEVELOPER + assert(streq(badstr, "lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeessp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygs9q4psqqqqqqqqqqqqqqqqsgqtqyx5vggfcsll4wu246hz02kp85x4katwsk9639we5n5yngc3yhqkm35jnjw4len8vrnqnf5ejh0mzj9n3vz2px97evektfm2l6wqccp3y7372")); +#else + assert(streq(badstr, "lnbc25m1pvjluezsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5vdhkven9v5sxyetpdeescqpj9q4psqqqqqqqqqqqqqqqqsgqf0nf0agw8xncpemlreh8wl0z5exhz3pky094lu7pf62nvcxq2vljzhhw69xfdftrgm0jklut3h25nlsfw5prz4c0pjy46xyer0k85hqpnathfq")); +#endif + /* Empty set of allowed bits, ensures this fails! */ fset = tal(tmpctx, struct feature_set); fset->bits[BOLT11_FEATURE] = tal_arr(fset, u8, 0); From 91932be70543707d6e51909c1aac9cb5669f9806 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 31 Mar 2022 19:40:50 +1030 Subject: [PATCH 12/12] pytest: fix flake in test_multichan. I have a separate branch which fixes this race properly, but it's not anything to do with this PR. Signed-off-by: Rusty Russell --- tests/test_connection.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_connection.py b/tests/test_connection.py index 4e5eb8be1753..bc7855e97dc2 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -3893,7 +3893,11 @@ def test_multichan(node_factory, executor, bitcoind): # Restart with multiple channels works. l3.restart() - l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + # FIXME: race against autoconnect can cause spurious failure (but we connect!) + try: + l3.rpc.connect(l2.info['id'], 'localhost', l2.port) + except RpcError: + wait_for(lambda: only_one(l3.rpc.listpeers(l2.info['id'])['peers'])['connected']) inv = l3.rpc.invoice(100000000, "invoice4", "invoice4") l1.rpc.pay(inv['bolt11'])