From 31b28657916f4d97b34f4c444c08c61f7c6b484c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 8 Jul 2020 06:20:26 +0930 Subject: [PATCH] common/json_tok: expose routines to parse addresses. These are currently inside lightningd. Signed-off-by: Rusty Russell --- common/json_tok.c | 111 ++++++++++++++++++++++++++++++++++ common/json_tok.h | 15 +++++ common/test/run-param.c | 9 +++ lightningd/json.c | 107 -------------------------------- lightningd/json.h | 16 ----- lightningd/test/run-jsonrpc.c | 6 ++ 6 files changed, 141 insertions(+), 123 deletions(-) diff --git a/common/json_tok.c b/common/json_tok.c index 1fd62a853..9ebe56b46 100644 --- a/common/json_tok.c +++ b/common/json_tok.c @@ -1,9 +1,14 @@ +#include +#include +#include #include +#include #include #include #include #include #include +#include #include #include #include @@ -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; +} diff --git a/common/json_tok.h b/common/json_tok.h index 1a13b1c2d..958bc796b 100644 --- a/common/json_tok.h +++ b/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 */ diff --git a/common/test/run-param.c b/common/test/run-param.c index 03fe21cfb..34bd94046 100644 --- a/common/test/run-param.c +++ b/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: */ diff --git a/lightningd/json.c b/lightningd/json.c index 2f49cde3c..4d032307c 100644 --- a/lightningd/json.c +++ b/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, diff --git a/lightningd/json.h b/lightningd/json.h index 33189975f..998f6202f 100644 --- a/lightningd/json.h +++ b/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, diff --git a/lightningd/test/run-jsonrpc.c b/lightningd/test/run-jsonrpc.c index 4fca70a54..e1acfd305 100644 --- a/lightningd/test/run-jsonrpc.c +++ b/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)