newaddr: support getting both bech32 and p2sh addresses.

Higher layers consume less addresses this way.

Fixes: #2390
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2019-03-04 13:43:20 +10:30 committed by Christian Decker
parent 5518c7cba8
commit 3e67c09d5e
5 changed files with 56 additions and 31 deletions

View File

@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- JSON API: `newaddr` outputs `bech32` or `p2sh-segwit`, or both with new `all` parameter (#2390)
### Changed
### Deprecated

View File

@ -2,12 +2,12 @@
.\" Title: lightning-newaddr
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
.\" Date: 07/23/2018
.\" Date: 02/23/2019
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "LIGHTNING\-NEWADDR" "7" "07/23/2018" "\ \&" "\ \&"
.TH "LIGHTNING\-NEWADDR" "7" "02/23/2019" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -38,12 +38,12 @@ The \fBnewaddr\fR RPC command generates a new address which can subsequently be
.sp
The funding transaction needs to be confirmed before funds can be used\&.
.sp
\fIaddresstype\fR specifies the type of address wanted; i\&.e\&. p2sh\-segwit (e\&.g\&. 2MxaozoqWwiUcuD9KKgUSrLFDafLqimT9Ta on bitcoin testnet or 3MZxzq3jBSKNQ2e7dzneo9hy4FvNzmMmt3 on bitcoin mainnet) or bech32 (e\&.g\&. tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg on bitcoin testnet or bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej on bitcoin mainnet)\&.
\fIaddresstype\fR specifies the type of address wanted; i\&.e\&. \fIp2sh\-segwit\fR (e\&.g\&. 2MxaozoqWwiUcuD9KKgUSrLFDafLqimT9Ta on bitcoin testnet or 3MZxzq3jBSKNQ2e7dzneo9hy4FvNzmMmt3 on bitcoin mainnet) or \fIbech32 \*(Aq (e\&.g\&. tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg on bitcoin testnet or bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej on bitcoin mainnet)\&. The special value \*(Aqall\fR generates both address types for the same underlying key\&.
.sp
If not specified the address generated is bech32\&.
.SH "RETURN VALUE"
.sp
On success, a new address will be returned\&.
On success, a \fIbech32\fR address and/or a \fIp2sh\-segwit\fR address will be returned\&.
.SH "ERRORS"
.sp
If an unrecognized address type is requested an error message will be returned\&.

View File

@ -19,16 +19,17 @@ subsequently be used to fund channels managed by the c-lightning node.
The funding transaction needs to be confirmed before funds can be used.
'addresstype' specifies the type of address wanted; i.e.
p2sh-segwit (e.g. 2MxaozoqWwiUcuD9KKgUSrLFDafLqimT9Ta on bitcoin testnet
or 3MZxzq3jBSKNQ2e7dzneo9hy4FvNzmMmt3 on bitcoin mainnet) or bech32
'p2sh-segwit' (e.g. 2MxaozoqWwiUcuD9KKgUSrLFDafLqimT9Ta on bitcoin testnet
or 3MZxzq3jBSKNQ2e7dzneo9hy4FvNzmMmt3 on bitcoin mainnet) or 'bech32 '
(e.g. tb1qu9j4lg5f9rgjyfhvfd905vw46eg39czmktxqgg on bitcoin testnet or
bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej on bitcoin mainnet).
The special value 'all' generates both address types for the same underlying key.
If not specified the address generated is bech32.
RETURN VALUE
------------
On success, a new address will be returned.
On success, a 'bech32' address and/or a 'p2sh-segwit' address will be returned.
ERRORS
------

View File

@ -1232,3 +1232,16 @@ def test_bad_onion(node_factory, bitcoind):
assert err.value.error['data']['failcode'] == WIRE_INVALID_ONION_HMAC
assert err.value.error['data']['erring_node'] == mangled_nodeid
assert err.value.error['data']['erring_channel'] == route[1]['channel']
def test_newaddr(node_factory):
l1 = node_factory.get_node()
p2sh = l1.rpc.newaddr('p2sh-segwit')
assert 'bech32' not in p2sh
assert p2sh['p2sh-segwit'].startswith('2')
bech32 = l1.rpc.newaddr('bech32')
assert 'p2sh-segwit' not in bech32
assert bech32['bech32'].startswith('bcrt1')
both = l1.rpc.newaddr('all')
assert both['p2sh-segwit'].startswith('2')
assert both['bech32'].startswith('bcrt1')

View File

@ -266,25 +266,31 @@ encode_scriptpubkey_to_addr(const tal_t *ctx,
return out;
}
/* Extract a bool indicating "p2sh-segwit" or "bech32" */
enum addrtype {
ADDR_P2SH_SEGWIT = 1,
ADDR_BECH32 = 2,
ADDR_ALL = (ADDR_P2SH_SEGWIT + ADDR_BECH32)
};
/* Extract bool indicating "p2sh-segwit" or "bech32" */
static struct command_result *param_newaddr(struct command *cmd,
const char *name,
const char *buffer,
const jsmntok_t *tok,
bool **is_p2wpkh)
enum addrtype **addrtype)
{
*is_p2wpkh = tal(cmd, bool);
if (json_tok_streq(buffer, tok, "p2sh-segwit")) {
**is_p2wpkh = false;
return NULL;
}
if (json_tok_streq(buffer, tok, "bech32")) {
**is_p2wpkh = true;
return NULL;
}
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"'%s' should be 'bech32' or 'p2sh-segwit', not '%.*s'",
name, tok->end - tok->start, buffer + tok->start);
*addrtype = tal(cmd, enum addrtype);
if (json_tok_streq(buffer, tok, "p2sh-segwit"))
**addrtype = ADDR_P2SH_SEGWIT;
else if (json_tok_streq(buffer, tok, "bech32"))
**addrtype = ADDR_BECH32;
else if (json_tok_streq(buffer, tok, "all"))
**addrtype = ADDR_ALL;
else
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
"'%s' should be 'bech32', 'p2sh-segwit' or 'all', not '%.*s'",
name, tok->end - tok->start, buffer + tok->start);
return NULL;
}
static struct command_result *json_newaddr(struct command *cmd,
@ -295,12 +301,12 @@ static struct command_result *json_newaddr(struct command *cmd,
struct json_stream *response;
struct ext_key ext;
struct pubkey pubkey;
bool *is_p2wpkh;
enum addrtype *addrtype;
s64 keyidx;
char *out;
char *p2sh, *bech32;
if (!param(cmd, buffer, params,
p_opt_def("addresstype", param_newaddr, &is_p2wpkh, true),
p_opt_def("addresstype", param_newaddr, &addrtype, ADDR_BECH32),
NULL))
return command_param_failed();
@ -321,17 +327,20 @@ static struct command_result *json_newaddr(struct command *cmd,
txfilter_add_derkey(cmd->ld->owned_txfilter, ext.pub_key);
out = encode_pubkey_to_addr(cmd, cmd->ld,
&pubkey, !*is_p2wpkh,
NULL);
if (!out) {
p2sh = encode_pubkey_to_addr(cmd, cmd->ld, &pubkey, true, NULL);
bech32 = encode_pubkey_to_addr(cmd, cmd->ld, &pubkey, false, NULL);
if (!p2sh || !bech32) {
return command_fail(cmd, LIGHTNINGD,
"p2wpkh address encoding failure.");
}
response = json_stream_success(cmd);
json_object_start(response, NULL);
json_add_string(response, "address", out);
json_add_string(response, "address", bech32 ? bech32 : p2sh);
if (*addrtype & ADDR_BECH32)
json_add_string(response, "bech32", bech32);
if (*addrtype & ADDR_P2SH_SEGWIT)
json_add_string(response, "p2sh-segwit", p2sh);
json_object_end(response);
return command_success(cmd, response);
}
@ -339,8 +348,8 @@ static struct command_result *json_newaddr(struct command *cmd,
static const struct json_command newaddr_command = {
"newaddr",
json_newaddr,
"Get a new {bech32, p2sh-segwit} address to fund a channel (default is bech32)", false,
"Generates a new address that belongs to the internal wallet. Funds sent to these addresses will be managed by lightningd. Use `withdraw` to withdraw funds to an external wallet."
"Get a new {bech32, p2sh-segwit} (or all) address to fund a channel (default is bech32)", false,
"Generates a new address (or both) that belongs to the internal wallet. Funds sent to these addresses will be managed by lightningd. Use `withdraw` to withdraw funds to an external wallet."
};
AUTODATA(json_command, &newaddr_command);