From e26d294b60fea497bb3b05d03348dafe56873511 Mon Sep 17 00:00:00 2001 From: ZmnSCPxj Date: Mon, 11 Dec 2017 03:43:11 +0000 Subject: [PATCH] Add support for withdrawing to BECH32 addresses. Fixes: #428 --- wallet/walletrpc.c | 83 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/wallet/walletrpc.c b/wallet/walletrpc.c index 116ae48fd..b76baaedc 100644 --- a/wallet/walletrpc.c +++ b/wallet/walletrpc.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -69,6 +70,51 @@ static void wallet_withdrawal_broadcast(struct bitcoind *bitcoind, } } +/** + * segwit_addr_net_decode - Try to decode a Bech32 address and detect + * testnet/mainnet + * + * This processes the address and returns true if it is a Bech32 + * address specified by BIP173. If it returns true, then *testnet is + * set whether it is testnet "tb" address or false if mainnet "bc" + * address. It does not check, witness version and program size + * restrictions. + * + * Out: testnet: Pointer to a bool that will be updated to true if the + * address is testnet, or false if mainnet. + * 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 true if successful, false if fail (on fail, none of the out + * parameters are modified). + */ +static bool segwit_addr_net_decode(bool *testnet, int *witness_version, + uint8_t *witness_program, + size_t *witness_program_len, + const char *addrz) +{ + /* segwit_addr_decode itself expects a prog buffer (which we pass + * witness_program as) of size 40, so segwit_addr_net_decode + * inherits that requirement. It will not write to that buffer + * if the input address is too long, so no buffer overflow risk. */ + if (segwit_addr_decode(witness_version, + witness_program, witness_program_len, + "bc", addrz)) { + *testnet = false; + return true; + } else if (segwit_addr_decode(witness_version, + witness_program, witness_program_len, + "tb", addrz)) { + *testnet = true; + return true; + } + return false; +} + /** * scriptpubkey_from_address - Determine scriptpubkey from a given address * @@ -82,8 +128,18 @@ static u8 *scriptpubkey_from_address(const tal_t *cxt, bool *testnet, { struct bitcoin_address p2pkh_destination; struct ripemd160 p2sh_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; + bool witness_ok; u8 *script = NULL; + char *addrz; + bool my_testnet; + if (bitcoin_from_base58(testnet, &p2pkh_destination, addr, addrlen)) { script = scriptpubkey_p2pkh(cxt, &p2pkh_destination); @@ -91,8 +147,33 @@ static u8 *scriptpubkey_from_address(const tal_t *cxt, bool *testnet, addr, addrlen)) { script = scriptpubkey_p2sh_hash(cxt, &p2sh_destination); } - /* TODO Insert other supported addresses here. */ + /* Insert other parsers that accept pointer+len here. */ + + if (script) return script; + + /* Generate null-terminated address. */ + addrz = tal_dup_arr(cxt, char, addr, addrlen, 1); + addrz[addrlen] = '\0'; + + if (segwit_addr_net_decode(&my_testnet, &witness_version, + witness_program, &witness_program_len, + addrz)) { + 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) { + *testnet = my_testnet; + script = scriptpubkey_witness_raw(cxt, witness_version, + witness_program, + witness_program_len); + } + } + /* Insert other parsers that accept null-terminated string here. */ + tal_free(addrz); return script; }