diff --git a/common/bolt11.c b/common/bolt11.c index 00d9d98ee..9aef0e444 100644 --- a/common/bolt11.c +++ b/common/bolt11.c @@ -313,13 +313,10 @@ static char *decode_n(struct bolt11 *b11, static char *decode_f(struct bolt11 *b11, struct hash_u5 *hu5, u5 **data, size_t *data_len, - size_t data_length, bool *have_f) + size_t data_length) { u64 version; - - if (*have_f) - return unknown_field(b11, hu5, data, data_len, 'f', - data_length); + u8 *fallback; if (!pull_uint(hu5, data, data_len, &version, 5)) return tal_fmt(b11, "f: data_length %zu short", data_length); @@ -339,8 +336,7 @@ static char *decode_f(struct bolt11 *b11, pull_bits_certain(hu5, data, data_len, &pkhash, data_length*5, false); - b11->fallback = scriptpubkey_p2pkh(b11, &pkhash); - return NULL; + fallback = scriptpubkey_p2pkh(b11, &pkhash); } else if (version == 18) { /* Pay to pubkey script hash (P2SH) */ struct ripemd160 shash; @@ -350,7 +346,7 @@ static char *decode_f(struct bolt11 *b11, pull_bits_certain(hu5, data, data_len, &shash, data_length*5, false); - b11->fallback = scriptpubkey_p2sh_hash(b11, &shash); + fallback = scriptpubkey_p2sh_hash(b11, &shash); } else if (version < 17) { u8 *f = tal_arr(b11, u8, data_length * 5 / 8); if (version == 0) { @@ -361,14 +357,20 @@ static char *decode_f(struct bolt11 *b11, } pull_bits_certain(hu5, data, data_len, f, data_length * 5, false); - b11->fallback = scriptpubkey_witness_raw(b11, version, - f, tal_len(f)); + fallback = scriptpubkey_witness_raw(b11, version, + f, tal_len(f)); tal_free(f); } else return unknown_field(b11, hu5, data, data_len, 'f', data_length); - *have_f = true; + if (b11->fallbacks == NULL) + b11->fallbacks = tal_arr(b11, const u8 *, 1); + else + tal_resize(&b11->fallbacks, tal_count(b11->fallbacks) + 1); + + b11->fallbacks[tal_count(b11->fallbacks)-1] + = tal_steal(b11->fallbacks, fallback); return NULL; } @@ -441,7 +443,7 @@ struct bolt11 *new_bolt11(const tal_t *ctx, u64 *msatoshi) list_head_init(&b11->extra_fields); b11->description = NULL; b11->description_hash = NULL; - b11->fallback = NULL; + b11->fallbacks = NULL; b11->routes = NULL; b11->msatoshi = NULL; b11->expiry = DEFAULT_X; @@ -465,7 +467,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, struct hash_u5 hu5; struct sha256 hash; bool have_p = false, have_n = false, have_d = false, have_h = false, - have_x = false, have_f = false, have_c = false; + have_x = false, have_c = false; b11->routes = tal_arr(b11, struct route_info *, 0); @@ -617,8 +619,7 @@ struct bolt11 *bolt11_decode(const tal_t *ctx, const char *str, case 'f': problem = decode_f(b11, &hu5, &data, - &data_len, data_length, - &have_f); + &data_len, data_length); break; case 'r': problem = decode_r(b11, &hu5, &data, &data_len, @@ -948,8 +949,8 @@ char *bolt11_encode_(const tal_t *ctx, if (b11->min_final_cltv_expiry != DEFAULT_C) encode_c(&data, b11->min_final_cltv_expiry); - if (b11->fallback) - encode_f(&data, b11->fallback); + for (size_t i = 0; i < tal_count(b11->fallbacks); i++) + encode_f(&data, b11->fallbacks[i]); for (size_t i = 0; i < tal_count(b11->routes); i++) encode_r(&data, b11->routes[i]); diff --git a/common/bolt11.h b/common/bolt11.h index 805eb841f..6435e6733 100644 --- a/common/bolt11.h +++ b/common/bolt11.h @@ -52,8 +52,8 @@ struct bolt11 { /* How many blocks final hop requires. */ u32 min_final_cltv_expiry; - /* If non-NULL, indicates a fallback address to pay to. */ - const u8 *fallback; + /* If non-NULL, indicates fallback addresses to pay to. */ + const u8 **fallbacks; /* If non-NULL: array of route arrays */ struct route_info **routes; diff --git a/common/test/run-bolt11.c b/common/test/run-bolt11.c index 874e831f3..a30d1dd68 100644 --- a/common/test/run-bolt11.c +++ b/common/test/run-bolt11.c @@ -91,12 +91,11 @@ static void test_b11(const char *b11str, assert(b11->expiry == expect_b11->expiry); assert(b11->min_final_cltv_expiry == expect_b11->min_final_cltv_expiry); - if (!b11->fallback) - assert(!expect_b11->fallback); - else - assert(memeq(b11->fallback, tal_len(b11->fallback), - expect_b11->fallback, - tal_len(expect_b11->fallback))); + assert(tal_count(b11->fallbacks) == tal_count(expect_b11->fallbacks)); + for (size_t i = 0; i < tal_count(b11->fallbacks); i++) + assert(memeq(b11->fallbacks[i], tal_len(b11->fallbacks[i]), + expect_b11->fallbacks[i], + tal_len(expect_b11->fallbacks[i]))); /* FIXME: compare routes. */ assert(tal_count(b11->routes) == tal_count(expect_b11->routes)); diff --git a/contrib/pylightning/lightning/lightning.py b/contrib/pylightning/lightning/lightning.py index 0503eb57e..c57a3dec1 100644 --- a/contrib/pylightning/lightning/lightning.py +++ b/contrib/pylightning/lightning/lightning.py @@ -150,7 +150,7 @@ class LightningRpc(UnixDomainSocketRpc): } return self.call("listchannels", payload) - def invoice(self, msatoshi, label, description, expiry=None, fallback=None): + def invoice(self, msatoshi, label, description, expiry=None, fallbacks=None): """ Create an invoice for {msatoshi} with {label} and {description} with optional {expiry} seconds (default 1 hour) @@ -160,7 +160,7 @@ class LightningRpc(UnixDomainSocketRpc): "label": label, "description": description, "expiry": expiry, - "fallback": fallback + "fallbacks": fallbacks } return self.call("invoice", payload) diff --git a/devtools/bolt11-cli.c b/devtools/bolt11-cli.c index 7b5cd66fa..4a703680d 100644 --- a/devtools/bolt11-cli.c +++ b/devtools/bolt11-cli.c @@ -111,27 +111,27 @@ int main(int argc, char *argv[]) tal_hexstr(ctx, b11->description_hash, sizeof(*b11->description_hash))); - if (tal_len(b11->fallback)) { + for (i = 0; i < tal_count(b11->fallbacks); i++) { struct bitcoin_address pkh; struct ripemd160 sh; struct sha256 wsh; - printf("fallback: %s\n", tal_hex(ctx, b11->fallback)); - if (is_p2pkh(b11->fallback, &pkh)) { + printf("fallback: %s\n", tal_hex(ctx, b11->fallbacks[i])); + if (is_p2pkh(b11->fallbacks[i], &pkh)) { printf("fallback-P2PKH: %s\n", bitcoin_to_base58(ctx, b11->chain->testnet, &pkh)); - } else if (is_p2sh(b11->fallback, &sh)) { + } else if (is_p2sh(b11->fallbacks[i], &sh)) { printf("fallback-P2SH: %s\n", p2sh_to_base58(ctx, b11->chain->testnet, &sh)); - } else if (is_p2wpkh(b11->fallback, &pkh)) { + } else if (is_p2wpkh(b11->fallbacks[i], &pkh)) { char out[73 + strlen(b11->chain->bip173_name)]; if (segwit_addr_encode(out, b11->chain->bip173_name, 0, (const u8 *)&pkh, sizeof(pkh))) printf("fallback-P2WPKH: %s\n", out); - } else if (is_p2wsh(b11->fallback, &wsh)) { + } else if (is_p2wsh(b11->fallbacks[i], &wsh)) { char out[73 + strlen(b11->chain->bip173_name)]; if (segwit_addr_encode(out, b11->chain->bip173_name, 0, (const u8 *)&wsh, sizeof(wsh))) diff --git a/doc/lightning-decodepay.7 b/doc/lightning-decodepay.7 index 2d90f1ad5..77fcde74b 100644 --- a/doc/lightning-decodepay.7 +++ b/doc/lightning-decodepay.7 @@ -2,12 +2,12 @@ .\" Title: lightning-decodepay .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 01/13/2018 +.\" Date: 04/05/2018 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "LIGHTNING\-DECODEPAY" "7" "01/13/2018" "\ \&" "\ \&" +.TH "LIGHTNING\-DECODEPAY" "7" "04/05/2018" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -138,7 +138,7 @@ The following fields are optional: .sp -1 .IP \(bu 2.3 .\} -\fIfallback\fR: fallback address object containing a +\fIfallbacks\fR: array of fallback address object containing a \fIhex\fR string, and both \fItype\fR diff --git a/doc/lightning-decodepay.7.txt b/doc/lightning-decodepay.7.txt index bb156f0f6..c867a1bd7 100644 --- a/doc/lightning-decodepay.7.txt +++ b/doc/lightning-decodepay.7.txt @@ -33,7 +33,7 @@ by BOLT11: The following fields are optional: - 'msatoshi': the number of millisatoshi requested (if any). -- 'fallback': fallback address object containing a 'hex' string, and +- 'fallbacks': array of fallback address object containing a 'hex' string, and both 'type' and 'addr' if it is recognized as one of 'P2PKH', 'P2SH', 'P2WPKH', or 'P2WSH'. - 'routes': an array of routes. Each route is an arrays of objects, each containing 'pubkey', 'short_channel_id', 'fee_base_msat', 'fee_proportional_millionths' and 'cltv_expiry_delta'. - 'extra': an array of objects representing unknown fields, each with one-character 'tag' and a 'data' bech32 string. diff --git a/doc/lightning-invoice.7 b/doc/lightning-invoice.7 index 4358c4498..859b1bc58 100644 --- a/doc/lightning-invoice.7 +++ b/doc/lightning-invoice.7 @@ -2,12 +2,12 @@ .\" Title: lightning-invoice .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 03/28/2018 +.\" Date: 04/06/2018 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "LIGHTNING\-INVOICE" "7" "03/28/2018" "\ \&" "\ \&" +.TH "LIGHTNING\-INVOICE" "7" "04/06/2018" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -31,7 +31,7 @@ lightning-invoice \- Protocol for accepting payments\&. .SH "SYNOPSIS" .sp -\fBinvoice\fR \fImsatoshi\fR \fIlabel\fR \fIdescription\fR [\fIexpiry\fR] +\fBinvoice\fR \fImsatoshi\fR \fIlabel\fR \fIdescription\fR [\fIexpiry\fR] [\fIfallbacks\fR] .SH "DESCRIPTION" .sp The \fBinvoice\fR RPC command creates the expectation of a payment of a given amount of milli\-satoshi: it returns a unique token which another lightning daemon can use to pay this invoice\&. @@ -43,6 +43,8 @@ The \fIlabel\fR must be a unique string or number (which is treated as a string, The \fIdescription\fR is a short description of purpose of payment, e\&.g\&. \fI1 cup of coffee\fR\&. This value is encoded into the BOLT11 invoice and is viewable by any node you send this invoice to\&. It must be UTF\-8, and cannot use \fI\eu\fR JSON escape codes\&. .sp The \fIexpiry\fR is optionally the number of seconds the invoice is valid for\&. If no value is provided the default of 3600 (1 Hour) is used\&. +.sp +The \fIfallbacks\fR array is one or more fallback addresses to include in the invoice (in order from most\-preferred to least): note that these arrays are not currently tracked to fulfill the invoice\&. .SH "RETURN VALUE" .sp On success, a hash is returned as \fIpayment_hash\fR to be given to the payer, and the \fIexpiry_time\fR as a UNIX timestamp\&. It also returns a BOLT11 invoice as \fIbolt11\fR to be given to the payer\&. On failure, an error is returned and no invoice is created\&. If the lightning process fails before responding, the caller should use lightning\-listinvoice(7) to query whether this invoice was created or not\&. diff --git a/doc/lightning-invoice.7.txt b/doc/lightning-invoice.7.txt index 3edae8d63..1f21859d5 100644 --- a/doc/lightning-invoice.7.txt +++ b/doc/lightning-invoice.7.txt @@ -8,7 +8,7 @@ lightning-invoice - Protocol for accepting payments. SYNOPSIS -------- -*invoice* 'msatoshi' 'label' 'description' ['expiry'] +*invoice* 'msatoshi' 'label' 'description' ['expiry'] ['fallbacks'] DESCRIPTION ----------- @@ -32,6 +32,10 @@ UTF-8, and cannot use '\u' JSON escape codes. The 'expiry' is optionally the number of seconds the invoice is valid for. If no value is provided the default of 3600 (1 Hour) is used. +The 'fallbacks' array is one or more fallback addresses to include in +the invoice (in order from most-preferred to least): note that these +arrays are not currently tracked to fulfill the invoice. + RETURN VALUE ------------ diff --git a/lightningd/invoice.c b/lightningd/invoice.c index c774a27d1..5f0e33bca 100644 --- a/lightningd/invoice.c +++ b/lightningd/invoice.c @@ -127,21 +127,43 @@ static struct json_escaped *json_tok_label(const tal_t *ctx, tok->end - tok->start); } +static bool parse_fallback(struct command *cmd, + const char *buffer, const jsmntok_t *fallback, + const u8 **fallback_script) + +{ + enum address_parse_result fallback_parse; + + fallback_parse + = json_tok_address_scriptpubkey(cmd, + get_chainparams(cmd->ld), + buffer, fallback, + fallback_script); + if (fallback_parse == ADDRESS_PARSE_UNRECOGNIZED) { + command_fail(cmd, "Fallback address not valid"); + return false; + } else if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) { + command_fail(cmd, "Fallback address does not match our network %s", + get_chainparams(cmd->ld)->network_name); + return false; + } + return true; +} + static void json_invoice(struct command *cmd, const char *buffer, const jsmntok_t *params) { struct invoice invoice; struct invoice_details details; - jsmntok_t *msatoshi, *label, *desctok, *exp, *fallback; + jsmntok_t *msatoshi, *label, *desctok, *exp, *fallback, *fallbacks; u64 *msatoshi_val; const struct json_escaped *label_val, *desc; const char *desc_val; - enum address_parse_result fallback_parse; struct json_result *response = new_json_result(cmd); struct wallet *wallet = cmd->ld->wallet; struct bolt11 *b11; char *b11enc; - const u8 *fallback_script; + const u8 **fallback_scripts = NULL; u64 expiry = 3600; bool result; @@ -151,6 +173,7 @@ static void json_invoice(struct command *cmd, "description", &desctok, "?expiry", &exp, "?fallback", &fallback, + "?fallbacks", &fallbacks, NULL)) { return; } @@ -219,21 +242,40 @@ static void json_invoice(struct command *cmd, return; } - /* fallback address */ + /* fallback addresses */ if (fallback) { - fallback_parse - = json_tok_address_scriptpubkey(cmd, - get_chainparams(cmd->ld), - buffer, fallback, - &fallback_script); - if (fallback_parse == ADDRESS_PARSE_UNRECOGNIZED) { - command_fail(cmd, "Fallback address not valid"); + if (deprecated_apis) { + fallback_scripts = tal_arr(cmd, const u8 *, 1); + if (!parse_fallback(cmd, buffer, fallback, + &fallback_scripts[0])) + return; + } else { + command_fail(cmd, "fallback is deprecated: use fallbacks"); return; - } else if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) { - command_fail(cmd, "Fallback address does not match our network %s", - get_chainparams(cmd->ld)->network_name); + } + } + + if (fallbacks) { + const jsmntok_t *i, *end = json_next(fallbacks); + size_t n = 0; + + if (fallback) { + command_fail(cmd, "Cannot use fallback and fallbacks"); return; } + + if (fallbacks->type != JSMN_ARRAY) { + command_fail(cmd, "fallback must be an array"); + return; + } + fallback_scripts = tal_arr(cmd, const u8 *, n); + for (i = fallbacks + 1; i < end; i = json_next(i)) { + tal_resize(&fallback_scripts, n+1); + if (!parse_fallback(cmd, buffer, i, + &fallback_scripts[n])) + return; + n++; + } } struct preimage r; @@ -253,8 +295,8 @@ static void json_invoice(struct command *cmd, b11->expiry = expiry; b11->description = tal_steal(b11, desc_val); b11->description_hash = NULL; - if (fallback) - b11->fallback = tal_steal(b11, fallback_script); + if (fallback_scripts) + b11->fallbacks = tal_steal(b11, fallback_scripts); /* FIXME: add private routes if necessary! */ b11enc = bolt11_encode(cmd, b11, false, hsm_sign_b11, cmd->ld); @@ -623,6 +665,41 @@ static const struct json_command waitinvoice_command = { }; AUTODATA(json_command, &waitinvoice_command); +static void json_add_fallback(struct json_result *response, + const char *fieldname, + const u8 *fallback, + const struct chainparams *chain) +{ + struct bitcoin_address pkh; + struct ripemd160 sh; + struct sha256 wsh; + + json_object_start(response, fieldname); + if (is_p2pkh(fallback, &pkh)) { + json_add_string(response, "type", "P2PKH"); + json_add_string(response, "addr", + bitcoin_to_base58(tmpctx, chain->testnet, &pkh)); + } else if (is_p2sh(fallback, &sh)) { + json_add_string(response, "type", "P2SH"); + json_add_string(response, "addr", + p2sh_to_base58(tmpctx, chain->testnet, &sh)); + } else if (is_p2wpkh(fallback, &pkh)) { + char out[73 + strlen(chain->bip173_name)]; + json_add_string(response, "type", "P2WPKH"); + if (segwit_addr_encode(out, chain->bip173_name, 0, + (const u8 *)&pkh, sizeof(pkh))) + json_add_string(response, "addr", out); + } else if (is_p2wsh(fallback, &wsh)) { + char out[73 + strlen(chain->bip173_name)]; + json_add_string(response, "type", "P2WSH"); + if (segwit_addr_encode(out, chain->bip173_name, 0, + (const u8 *)&wsh, sizeof(wsh))) + json_add_string(response, "addr", out); + } + json_add_hex(response, "hex", fallback, tal_len(fallback)); + json_object_end(response); +} + static void json_decodepay(struct command *cmd, const char *buffer, const jsmntok_t *params) { @@ -675,40 +752,15 @@ static void json_decodepay(struct command *cmd, sizeof(*b11->description_hash)); json_add_num(response, "min_final_cltv_expiry", b11->min_final_cltv_expiry); - if (tal_len(b11->fallback)) { - struct bitcoin_address pkh; - struct ripemd160 sh; - struct sha256 wsh; - - json_object_start(response, "fallback"); - if (is_p2pkh(b11->fallback, &pkh)) { - json_add_string(response, "type", "P2PKH"); - json_add_string(response, "addr", - bitcoin_to_base58(cmd, - b11->chain->testnet, - &pkh)); - } else if (is_p2sh(b11->fallback, &sh)) { - json_add_string(response, "type", "P2SH"); - json_add_string(response, "addr", - p2sh_to_base58(cmd, - b11->chain->testnet, - &sh)); - } else if (is_p2wpkh(b11->fallback, &pkh)) { - char out[73 + strlen(b11->chain->bip173_name)]; - json_add_string(response, "type", "P2WPKH"); - if (segwit_addr_encode(out, b11->chain->bip173_name, 0, - (const u8 *)&pkh, sizeof(pkh))) - json_add_string(response, "addr", out); - } else if (is_p2wsh(b11->fallback, &wsh)) { - char out[73 + strlen(b11->chain->bip173_name)]; - json_add_string(response, "type", "P2WSH"); - if (segwit_addr_encode(out, b11->chain->bip173_name, 0, - (const u8 *)&wsh, sizeof(wsh))) - json_add_string(response, "addr", out); - } - json_add_hex(response, "hex", - b11->fallback, tal_len(b11->fallback)); - json_object_end(response); + if (tal_count(b11->fallbacks)) { + if (deprecated_apis) + json_add_fallback(response, "fallback", + b11->fallbacks[0], b11->chain); + json_array_start(response, "fallbacks"); + for (size_t i = 0; i < tal_count(b11->fallbacks); i++) + json_add_fallback(response, NULL, + b11->fallbacks[i], b11->chain); + json_array_end(response); } if (tal_count(b11->routes)) { diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 7fc2b1503..81ac1e277 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -429,9 +429,10 @@ class LightningDTests(BaseLightningDTests): l1 = self.node_factory.get_node() l2 = self.node_factory.get_node() - addr = l2.rpc.newaddr('bech32')['address'] + addr1 = l2.rpc.newaddr('bech32')['address'] + addr2 = l2.rpc.newaddr('p2sh-segwit')['address'] before = int(time.time()) - inv = l1.rpc.invoice(123000, 'label', 'description', '3700', addr) + inv = l1.rpc.invoice(123000, 'label', 'description', '3700', [addr1, addr2]) after = int(time.time()) b11 = l1.rpc.decodepay(inv['bolt11']) assert b11['currency'] == 'bcrt' @@ -441,8 +442,11 @@ class LightningDTests(BaseLightningDTests): assert b11['description'] == 'description' assert b11['expiry'] == 3700 assert b11['payee'] == l1.info['id'] - assert b11['fallback']['addr'] == addr - assert b11['fallback']['type'] == 'P2WPKH' + assert len(b11['fallbacks']) == 2 + assert b11['fallbacks'][0]['addr'] == addr1 + assert b11['fallbacks'][0]['type'] == 'P2WPKH' + assert b11['fallbacks'][1]['addr'] == addr2 + assert b11['fallbacks'][1]['type'] == 'P2SH' # Check pay_index is null outputs = l1.db_query('SELECT pay_index IS NULL AS q FROM invoices WHERE label="label";') @@ -721,8 +725,8 @@ class LightningDTests(BaseLightningDTests): assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102' assert b11['expiry'] == 3600 assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad' - assert b11['fallback']['type'] == 'P2PKH' - assert b11['fallback']['addr'] == 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP' + assert b11['fallbacks'][0]['type'] == 'P2PKH' + assert b11['fallbacks'][0]['addr'] == 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP' # > ### On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 # > lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj @@ -751,8 +755,8 @@ class LightningDTests(BaseLightningDTests): assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102' assert b11['expiry'] == 3600 assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad' - assert b11['fallback']['type'] == 'P2PKH' - assert b11['fallback']['addr'] == '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T' + assert b11['fallbacks'][0]['type'] == 'P2PKH' + assert b11['fallbacks'][0]['addr'] == '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T' assert len(b11['routes']) == 1 assert len(b11['routes'][0]) == 2 assert b11['routes'][0][0]['pubkey'] == '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255' @@ -792,8 +796,8 @@ class LightningDTests(BaseLightningDTests): assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102' assert b11['expiry'] == 3600 assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad' - assert b11['fallback']['type'] == 'P2SH' - assert b11['fallback']['addr'] == '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX' + assert b11['fallbacks'][0]['type'] == 'P2SH' + assert b11['fallbacks'][0]['addr'] == '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX' # > ### On mainnet, with fallback (P2WPKH) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4 # > lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7kepvrhrm9s57hejg0p662ur5j5cr03890fa7k2pypgttmh4897d3raaq85a293e9jpuqwl0rnfuwzam7yr8e690nd2ypcq9hlkdwdvycqa0qza8 @@ -817,8 +821,8 @@ class LightningDTests(BaseLightningDTests): assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102' assert b11['expiry'] == 3600 assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad' - assert b11['fallback']['type'] == 'P2WPKH' - assert b11['fallback']['addr'] == 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4' + assert b11['fallbacks'][0]['type'] == 'P2WPKH' + assert b11['fallbacks'][0]['addr'] == 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4' # > ### On mainnet, with fallback (P2WSH) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3 # > lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q28j0v3rwgy9pvjnd48ee2pl8xrpxysd5g44td63g6xcjcu003j3qe8878hluqlvl3km8rm92f5stamd3jw763n3hck0ct7p8wwj463cql26ava @@ -842,8 +846,8 @@ class LightningDTests(BaseLightningDTests): assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102' assert b11['expiry'] == 3600 assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad' - assert b11['fallback']['type'] == 'P2WSH' - assert b11['fallback']['addr'] == 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3' + assert b11['fallbacks'][0]['type'] == 'P2WSH' + assert b11['fallbacks'][0]['addr'] == 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3' self.assertRaises(ValueError, l1.rpc.decodepay, '1111111')