Browse Source

common/json_tok: expose routines to parse addresses.

These are currently inside lightningd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
keysend
Rusty Russell 5 years ago
committed by Christian Decker
parent
commit
31b2865791
  1. 111
      common/json_tok.c
  2. 15
      common/json_tok.h
  3. 9
      common/test/run-param.c
  4. 107
      lightningd/json.c
  5. 16
      lightningd/json.h
  6. 6
      lightningd/test/run-jsonrpc.c

111
common/json_tok.c

@ -1,9 +1,14 @@
#include <bitcoin/address.h>
#include <bitcoin/base58.h>
#include <bitcoin/chainparams.h>
#include <bitcoin/feerate.h>
#include <bitcoin/script.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/json_escape/json_escape.h>
#include <ccan/str/hex/hex.h>
#include <ccan/tal/str/str.h>
#include <common/amount.h>
#include <common/bech32.h>
#include <common/channel_id.h>
#include <common/json_command.h>
#include <common/json_helpers.h>
@ -379,3 +384,109 @@ struct command_result *param_feerate_val(struct command *cmd,
return NULL;
}
/**
* segwit_addr_net_decode - Try to decode a Bech32 address and detect
* testnet/mainnet/regtest/signet
*
* This processes the address and returns a string if it is a Bech32
* address specified by BIP173. The string is set whether it is
* testnet ("tb"), mainnet ("bc"), regtest ("bcrt"), or signet ("sb")
* It does not check, witness version and program size restrictions.
*
* Out: witness_version: Pointer to an int that will be updated to contain
* the witness program version (between 0 and 16 inclusive).
* witness_program: Pointer to a buffer of size 40 that will be updated
* to contain the witness program bytes.
* witness_program_len: Pointer to a size_t that will be updated to
* contain the length of bytes in witness_program.
* In: addrz: Pointer to the null-terminated address.
* Returns string containing the human readable segment of bech32 address
*/
static const char *segwit_addr_net_decode(int *witness_version,
uint8_t *witness_program,
size_t *witness_program_len,
const char *addrz,
const struct chainparams *chainparams)
{
if (segwit_addr_decode(witness_version, witness_program,
witness_program_len, chainparams->bip173_name,
addrz))
return chainparams->bip173_name;
else
return NULL;
}
enum address_parse_result
json_to_address_scriptpubkey(const tal_t *ctx,
const struct chainparams *chainparams,
const char *buffer,
const jsmntok_t *tok, const u8 **scriptpubkey)
{
struct bitcoin_address destination;
int witness_version;
/* segwit_addr_net_decode requires a buffer of size 40, and will
* not write to the buffer if the address is too long, so a buffer
* of fixed size 40 will not overflow. */
uint8_t witness_program[40];
size_t witness_program_len;
char *addrz;
const char *bip173;
bool parsed;
bool right_network;
u8 addr_version;
parsed =
ripemd160_from_base58(&addr_version, &destination.addr,
buffer + tok->start, tok->end - tok->start);
if (parsed) {
if (addr_version == chainparams->p2pkh_version) {
*scriptpubkey = scriptpubkey_p2pkh(ctx, &destination);
return ADDRESS_PARSE_SUCCESS;
} else if (addr_version == chainparams->p2sh_version) {
*scriptpubkey =
scriptpubkey_p2sh_hash(ctx, &destination.addr);
return ADDRESS_PARSE_SUCCESS;
} else {
return ADDRESS_PARSE_WRONG_NETWORK;
}
/* Insert other parsers that accept pointer+len here. */
}
/* Generate null-terminated address. */
addrz = tal_dup_arr(ctx, char, buffer + tok->start, tok->end - tok->start, 1);
addrz[tok->end - tok->start] = '\0';
bip173 = segwit_addr_net_decode(&witness_version, witness_program,
&witness_program_len, addrz, chainparams);
if (bip173) {
bool witness_ok = false;
if (witness_version == 0 && (witness_program_len == 20 ||
witness_program_len == 32)) {
witness_ok = true;
}
/* Insert other witness versions here. */
if (witness_ok) {
*scriptpubkey = scriptpubkey_witness_raw(ctx, witness_version,
witness_program, witness_program_len);
parsed = true;
right_network = streq(bip173, chainparams->bip173_name);
}
}
/* Insert other parsers that accept null-terminated string here. */
tal_free(addrz);
if (parsed) {
if (right_network)
return ADDRESS_PARSE_SUCCESS;
else
return ADDRESS_PARSE_WRONG_NETWORK;
}
return ADDRESS_PARSE_UNRECOGNIZED;
}

15
common/json_tok.h

@ -136,4 +136,19 @@ struct command_result *param_feerate_val(struct command *cmd,
const jsmntok_t *tok,
u32 **feerate_per_kw);
enum address_parse_result {
/* Not recognized as an onchain address */
ADDRESS_PARSE_UNRECOGNIZED,
/* Recognized as an onchain address, but targets wrong network */
ADDRESS_PARSE_WRONG_NETWORK,
/* Recognized and succeeds */
ADDRESS_PARSE_SUCCESS,
};
/* Return result of address parsing and fills in *scriptpubkey
* allocated off ctx if ADDRESS_PARSE_SUCCESS
*/
enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx,
const struct chainparams *chainparams,
const char *buffer,
const jsmntok_t *tok, const u8 **scriptpubkey);
#endif /* LIGHTNING_COMMON_JSON_TOK_H */

9
common/test/run-param.c

@ -50,6 +50,15 @@ bool json_to_node_id(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct pubkey *pubkey UNNEEDED)
{ fprintf(stderr, "json_to_pubkey called!\n"); abort(); }
/* Generated stub for segwit_addr_decode */
int segwit_addr_decode(
int* ver UNNEEDED,
uint8_t* prog UNNEEDED,
size_t* prog_len UNNEEDED,
const char* hrp UNNEEDED,
const char* addr
)
{ fprintf(stderr, "segwit_addr_decode called!\n"); abort(); }
/* AUTOGENERATED MOCKS END */
/* We do this lightningd-style: */

107
lightningd/json.c

@ -123,113 +123,6 @@ json_tok_channel_id(const char *buffer, const jsmntok_t *tok,
cid, sizeof(*cid));
}
/**
* segwit_addr_net_decode - Try to decode a Bech32 address and detect
* testnet/mainnet/regtest/signet
*
* This processes the address and returns a string if it is a Bech32
* address specified by BIP173. The string is set whether it is
* testnet ("tb"), mainnet ("bc"), regtest ("bcrt"), or signet ("sb")
* It does not check, witness version and program size restrictions.
*
* Out: witness_version: Pointer to an int that will be updated to contain
* the witness program version (between 0 and 16 inclusive).
* witness_program: Pointer to a buffer of size 40 that will be updated
* to contain the witness program bytes.
* witness_program_len: Pointer to a size_t that will be updated to
* contain the length of bytes in witness_program.
* In: addrz: Pointer to the null-terminated address.
* Returns string containing the human readable segment of bech32 address
*/
static const char *segwit_addr_net_decode(int *witness_version,
uint8_t *witness_program,
size_t *witness_program_len,
const char *addrz,
const struct chainparams *chainparams)
{
if (segwit_addr_decode(witness_version, witness_program,
witness_program_len, chainparams->bip173_name,
addrz))
return chainparams->bip173_name;
else
return NULL;
}
enum address_parse_result
json_to_address_scriptpubkey(const tal_t *ctx,
const struct chainparams *chainparams,
const char *buffer,
const jsmntok_t *tok, const u8 **scriptpubkey)
{
struct bitcoin_address destination;
int witness_version;
/* segwit_addr_net_decode requires a buffer of size 40, and will
* not write to the buffer if the address is too long, so a buffer
* of fixed size 40 will not overflow. */
uint8_t witness_program[40];
size_t witness_program_len;
char *addrz;
const char *bip173;
bool parsed;
bool right_network;
u8 addr_version;
parsed =
ripemd160_from_base58(&addr_version, &destination.addr,
buffer + tok->start, tok->end - tok->start);
if (parsed) {
if (addr_version == chainparams->p2pkh_version) {
*scriptpubkey = scriptpubkey_p2pkh(ctx, &destination);
return ADDRESS_PARSE_SUCCESS;
} else if (addr_version == chainparams->p2sh_version) {
*scriptpubkey =
scriptpubkey_p2sh_hash(ctx, &destination.addr);
return ADDRESS_PARSE_SUCCESS;
} else {
return ADDRESS_PARSE_WRONG_NETWORK;
}
/* Insert other parsers that accept pointer+len here. */
}
/* Generate null-terminated address. */
addrz = tal_dup_arr(ctx, char, buffer + tok->start, tok->end - tok->start, 1);
addrz[tok->end - tok->start] = '\0';
bip173 = segwit_addr_net_decode(&witness_version, witness_program,
&witness_program_len, addrz, chainparams);
if (bip173) {
bool witness_ok = false;
if (witness_version == 0 && (witness_program_len == 20 ||
witness_program_len == 32)) {
witness_ok = true;
}
/* Insert other witness versions here. */
if (witness_ok) {
*scriptpubkey = scriptpubkey_witness_raw(ctx, witness_version,
witness_program, witness_program_len);
parsed = true;
right_network = streq(bip173, chainparams->bip173_name);
}
}
/* Insert other parsers that accept null-terminated string here. */
tal_free(addrz);
if (parsed) {
if (right_network)
return ADDRESS_PARSE_SUCCESS;
else
return ADDRESS_PARSE_WRONG_NETWORK;
}
return ADDRESS_PARSE_UNRECOGNIZED;
}
struct command_result *param_bitcoin_address(struct command *cmd,
const char *name,
const char *buffer,

16
lightningd/json.h

@ -56,22 +56,6 @@ struct command_result *param_feerate(struct command *cmd, const char *name,
bool json_tok_channel_id(const char *buffer, const jsmntok_t *tok,
struct channel_id *cid);
enum address_parse_result {
/* Not recognized as an onchain address */
ADDRESS_PARSE_UNRECOGNIZED,
/* Recognized as an onchain address, but targets wrong network */
ADDRESS_PARSE_WRONG_NETWORK,
/* Recognized and succeeds */
ADDRESS_PARSE_SUCCESS,
};
/* Return result of address parsing and fills in *scriptpubkey
* allocated off ctx if ADDRESS_PARSE_SUCCESS
*/
enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx,
const struct chainparams *chainparams,
const char *buffer,
const jsmntok_t *tok, const u8 **scriptpubkey);
struct command_result *param_bitcoin_address(struct command *cmd,
const char *name,
const char *buffer,

6
lightningd/test/run-jsonrpc.c

@ -29,6 +29,12 @@ void fromwire_node_id(const u8 **cursor UNNEEDED, size_t *max UNNEEDED, struct n
void json_add_sha256(struct json_stream *result UNNEEDED, const char *fieldname UNNEEDED,
const struct sha256 *hash UNNEEDED)
{ fprintf(stderr, "json_add_sha256 called!\n"); abort(); }
/* Generated stub for json_to_address_scriptpubkey */
enum address_parse_result json_to_address_scriptpubkey(const tal_t *ctx UNNEEDED,
const struct chainparams *chainparams UNNEEDED,
const char *buffer UNNEEDED,
const jsmntok_t *tok UNNEEDED, const u8 **scriptpubkey UNNEEDED)
{ fprintf(stderr, "json_to_address_scriptpubkey called!\n"); abort(); }
/* Generated stub for json_to_pubkey */
bool json_to_pubkey(const char *buffer UNNEEDED, const jsmntok_t *tok UNNEEDED,
struct pubkey *pubkey UNNEEDED)

Loading…
Cancel
Save