Browse Source

Add support for withdrawing to BECH32 addresses.

Fixes: #428
ppa-0.6.1
ZmnSCPxj 7 years ago
committed by Rusty Russell
parent
commit
e26d294b60
  1. 83
      wallet/walletrpc.c

83
wallet/walletrpc.c

@ -2,6 +2,7 @@
#include <bitcoin/base58.h>
#include <bitcoin/script.h>
#include <ccan/tal/str/str.h>
#include <common/bech32.h>
#include <common/key_derive.h>
#include <common/status.h>
#include <common/utxo.h>
@ -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;
}

Loading…
Cancel
Save