From 0610f66c34e227c9c3e247f1a383a91f9654586d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 12 Dec 2017 11:04:07 +1030 Subject: [PATCH] bolt11: handle r value fee spec change. We don't use it yet, but now we'll decode correctly. See: https://github.com/lightningnetwork/lightning-rfc/pull/317 lightning-rfc commit: ef053c09431442697ab46e83f9d3f86e3510a18e Signed-off-by: Rusty Russell --- common/bolt11.c | 9 ++++++--- common/bolt11.h | 5 +++-- common/test/run-bolt11.c | 12 ++++++------ devtools/bolt11-cli.c | 5 +++-- lightningd/invoice.c | 6 ++++-- lightningd/test/run-find_my_path.c | 2 +- tests/test_lightningd.py | 23 +++++++++++++---------- 7 files changed, 36 insertions(+), 26 deletions(-) diff --git a/common/bolt11.c b/common/bolt11.c index 213079f3d..c2f57bd87 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -378,7 +378,8 @@ static bool fromwire_route_info(const u8 **cursor, size_t *max, { fromwire_pubkey(cursor, max, &route_info->pubkey); fromwire_short_channel_id(cursor, max, &route_info->short_channel_id); - route_info->fee = fromwire_u64(cursor, max); + route_info->fee_base_msat = fromwire_u32(cursor, max); + route_info->fee_proportional_millionths = fromwire_u32(cursor, max); route_info->cltv_expiry_delta = fromwire_u16(cursor, max); return *cursor != NULL; } @@ -387,7 +388,8 @@ static void towire_route_info(u8 **pptr, const struct route_info *route_info) { towire_pubkey(pptr, &route_info->pubkey); towire_short_channel_id(pptr, &route_info->short_channel_id); - towire_u64(pptr, route_info->fee); + towire_u32(pptr, route_info->fee_base_msat); + towire_u32(pptr, route_info->fee_proportional_millionths); towire_u16(pptr, route_info->cltv_expiry_delta); } @@ -399,7 +401,8 @@ static void towire_route_info(u8 **pptr, const struct route_info *route_info) * * * `pubkey` (264 bits) * * `short_channel_id` (64 bits) - * * `fee` (64 bits, big-endian) + * * `fee_base_msat` (32 bits, big-endian) + * * `fee_proportional_millionths` (32 bits, big-endian) * * `cltv_expiry_delta` (16 bits, big-endian) */ static char *decode_r(struct bolt11 *b11, diff --git a/common/bolt11.h b/common/bolt11.h index 76829232f..42316958a 100644 --- a/common/bolt11.h +++ b/common/bolt11.h @@ -22,14 +22,15 @@ struct bolt11_field { /* BOLT #11: * * `pubkey` (264 bits) * * `short_channel_id` (64 bits) - * * `fee` (64 bits, big-endian) + * * `fee_base_msat` (32 bits, big-endian) + * * `fee_proportional_millionths` (32 bits, big-endian) * * `cltv_expiry_delta` (16 bits, big-endian) */ struct route_info { struct pubkey pubkey; struct short_channel_id short_channel_id; - u64 fee; + u32 fee_base_msat, fee_proportional_millionths; u16 cltv_expiry_delta; }; diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index e0e1fe313..c6217119f 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -17,9 +17,9 @@ void fromwire_short_channel_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, /* Generated stub for fromwire_u16 */ u16 fromwire_u16(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) { fprintf(stderr, "fromwire_u16 called!\n"); abort(); } -/* Generated stub for fromwire_u64 */ -u64 fromwire_u64(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) -{ fprintf(stderr, "fromwire_u64 called!\n"); abort(); } +/* Generated stub for fromwire_u32 */ +u32 fromwire_u32(const u8 **cursor UNNEEDED, size_t *max UNNEEDED) +{ fprintf(stderr, "fromwire_u32 called!\n"); abort(); } /* Generated stub for towire_pubkey */ void towire_pubkey(u8 **pptr UNNEEDED, const struct pubkey *pubkey UNNEEDED) { fprintf(stderr, "towire_pubkey called!\n"); abort(); } @@ -30,9 +30,9 @@ void towire_short_channel_id(u8 **pptr UNNEEDED, /* Generated stub for towire_u16 */ void towire_u16(u8 **pptr UNNEEDED, u16 v UNNEEDED) { fprintf(stderr, "towire_u16 called!\n"); abort(); } -/* Generated stub for towire_u64 */ -void towire_u64(u8 **pptr UNNEEDED, u64 v UNNEEDED) -{ fprintf(stderr, "towire_u64 called!\n"); abort(); } +/* Generated stub for towire_u32 */ +void towire_u32(u8 **pptr UNNEEDED, u32 v UNNEEDED) +{ fprintf(stderr, "towire_u32 called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ static struct privkey privkey; diff --git a/devtools/bolt11-cli.c b/devtools/bolt11-cli.c index 811bb1ab0..00bd49ac0 100644 --- a/devtools/bolt11-cli.c +++ b/devtools/bolt11-cli.c @@ -142,12 +142,13 @@ int main(int argc, char *argv[]) for (i = 0; i < tal_count(b11->routes); i++) { printf("route: (node/chanid/fee/expirydelta) "); for (size_t n = 0; n < tal_count(b11->routes[i]); n++) { - printf(" %s/%s/%"PRIu64"/%u", + printf(" %s/%s/%u/%u/%u", type_to_string(ctx, struct pubkey, &b11->routes[i][n].pubkey), type_to_string(ctx, struct short_channel_id, &b11->routes[i][n].short_channel_id), - b11->routes[i][n].fee, + b11->routes[i][n].fee_base_msat, + b11->routes[i][n].fee_proportional_millionths, b11->routes[i][n].cltv_expiry_delta); } printf("\n"); diff --git a/lightningd/invoice.c b/lightningd/invoice.c index 685a49110..b31943566 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -547,8 +547,10 @@ static void json_decodepay(struct command *cmd, "short_channel_id", &b11->routes[i][n] .short_channel_id); - json_add_u64(response, "fee", - b11->routes[i][n].fee); + json_add_u64(response, "fee_base_msat", + b11->routes[i][n].fee_base_msat); + json_add_u64(response, "fee_proportional_millionths", + b11->routes[i][n].fee_proportional_millionths); json_add_num(response, "cltv_expiry_delta", b11->routes[i][n] .cltv_expiry_delta); diff --git a/lightningd/test/run-find_my_path.c b/lightningd/test/run-find_my_path.c index 7a6a297be..d76d90987 100644 --- a/lightningd/test/run-find_my_path.c +++ b/lightningd/test/run-find_my_path.c @@ -79,7 +79,7 @@ void subd_shutdown(struct subd *subd UNNEEDED, unsigned int seconds UNNEEDED) void timer_expired(tal_t *ctx UNNEEDED, struct timer *timer UNNEEDED) { fprintf(stderr, "timer_expired called!\n"); abort(); } /* Generated stub for txfilter_add_derkey */ -void txfilter_add_derkey(struct txfilter *filter UNNEEDED, u8 derkey[33]) +void txfilter_add_derkey(struct txfilter *filter UNNEEDED, u8 derkey[PUBKEY_DER_LEN]) { fprintf(stderr, "txfilter_add_derkey called!\n"); abort(); } /* Generated stub for txfilter_new */ struct txfilter *txfilter_new(const tal_t *ctx UNNEEDED) diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 408c26cd0..1a0c4c948 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -464,7 +464,7 @@ class LightningDTests(BaseLightningDTests): assert b11['fallback']['addr'] == 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP' # > ### On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 - # > lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzqfnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cqd5m7tf + # > lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj # # Breakdown: # @@ -475,14 +475,15 @@ class LightningDTests(BaseLightningDTests): # * `p`: payment hash... # * `h`: tagged field: hash of description... # * `f`: tagged field: fallback address - # * `pp`: `data_length` (`p` = 1. 1 * 32 + 1 == 33) - # * `3qjmp7lwpagxun9pygexvgpjdc4jdj85f`: `3` = 17, so P2PKH address + # * `pp`: `data_length` (`p` = 1. 1 * 32 + 1 == 33) + # * `3` = 17, so P2PKH address + # * `qjmp7lwpagxun9pygexvgpjdc4jdj85f`: 160 bit P2PKH address # * `r`: tagged field: route information - # * `9y`: `data_length` (`9` = 5, `y` = 4. 5 * 32 + 4 = 164) - # `q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzq`: pubkey `029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255`, `short_channel_id` 0102030405060708, `fee` 20 millisatoshi, `cltv_expiry_delta` 3. pubkey `039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255`, `short_channel_id` 030405060708090a, `fee` 30 millisatoshi, `cltv_expiry_delta` 4. - # * `fnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cq`: signature - # * `d5m7tf`: Bech32 checksum - b11 = l1.rpc.decodepay('lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzqfnlkwydm8rg30gjku7wmxmk06sevjp53fmvrcfegvwy7d5443jvyhxsel0hulkstws7vqv400q4j3wgpk4crg49682hr4scqvmad43cqd5m7tf', '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') + # * `9y`: `data_length` (`9` = 5, `y` = 4. 5 * 32 + 4 = 164) + # `q20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqqqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqqqqqqq7qqzq`: pubkey `029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255`, `short_channel_id` 0102030405060708, `fee_base_msat` 1 millisatoshi, `fee_proportional_millionths` 20, `cltv_expiry_delta` 3. pubkey `039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255`, `short_channel_id` 030405060708090a, `fee_base_msat` 2 millisatoshi, `fee_proportional_millionths` 30, `cltv_expiry_delta` 4. + # * `j9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qq`: signature + # * `dhhwkj`: Bech32 checksum + b11 = l1.rpc.decodepay('lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj', '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') assert b11['currency'] == 'bc' assert b11['msatoshi'] == 20 * 10**11 // 1000 assert b11['timestamp'] == 1496314658 @@ -496,13 +497,15 @@ class LightningDTests(BaseLightningDTests): assert b11['routes'][0][0]['pubkey'] == '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255' # 0x010203:0x040506:0x0708 assert b11['routes'][0][0]['short_channel_id'] == '66051:263430:1800' - assert b11['routes'][0][0]['fee'] == 20 + assert b11['routes'][0][0]['fee_base_msat'] == 1 + assert b11['routes'][0][0]['fee_proportional_millionths'] == 20 assert b11['routes'][0][0]['cltv_expiry_delta'] == 3 assert b11['routes'][0][1]['pubkey'] == '039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255' # 0x030405:0x060708:0x090a assert b11['routes'][0][1]['short_channel_id'] == '197637:395016:2314' - assert b11['routes'][0][1]['fee'] == 30 + assert b11['routes'][0][1]['fee_base_msat'] == 2 + assert b11['routes'][0][1]['fee_proportional_millionths'] == 30 assert b11['routes'][0][1]['cltv_expiry_delta'] == 4 # > ### On mainnet, with fallback (P2SH) address 3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX