mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 05:12:45 +01:00
bolt11: allow multiple fallback addresses.
We can have more than one; eg we might offer both bech32 and a p2sh address, and in future we might offer v1 segwit, etc. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
5b7fcab766
commit
09c4203767
@ -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,
|
||||
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]);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)))
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: lightning-decodepay
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||
.\" 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
|
||||
|
@ -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.
|
||||
|
@ -2,12 +2,12 @@
|
||||
.\" Title: lightning-invoice
|
||||
.\" Author: [see the "AUTHOR" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||
.\" 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\&.
|
||||
|
@ -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
|
||||
------------
|
||||
|
||||
|
@ -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,23 +242,42 @@ 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 if (fallback_parse == ADDRESS_PARSE_WRONG_NETWORK) {
|
||||
command_fail(cmd, "Fallback address does not match our network %s",
|
||||
get_chainparams(cmd->ld)->network_name);
|
||||
} else {
|
||||
command_fail(cmd, "fallback is deprecated: use fallbacks");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
struct sha256 rhash;
|
||||
|
||||
@ -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)) {
|
||||
|
@ -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')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user