From aab51ae9b4c896af7f8810e555960b223a01f4ee Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Feb 2018 12:29:57 +1100 Subject: [PATCH] Implement native bech32 segwit address support. --- src/libckpool.c | 83 ++++++++++++++++++++++++++++++++++++++++-------- src/stratifier.c | 14 ++------ 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/src/libckpool.c b/src/libckpool.c index e828c4a9..21f77753 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -1730,9 +1730,54 @@ char *http_base64(const char *src) return (str); } +static const int8_t charset_rev[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 15, -1, 10, 17, 21, 20, 26, 30, 7, 5, -1, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1, + -1, 29, -1, 24, 13, 25, 9, 8, 23, -1, 18, 22, 31, 27, 19, -1, + 1, 0, 3, 16, 11, 28, 12, 14, 6, 4, 2, -1, -1, -1, -1, -1 +}; + /* It's assumed that there is no chance of sending invalid chars to these * functions as they should have been checked beforehand. */ -static void address_to_pubkeytxn(char *pkh, const char *addr) +static void bech32_decode(uint8_t *data, int *data_len, const char *input) +{ + int input_len = strlen(input), hrp_len, i; + + *data_len = 0; + while (*data_len < input_len && input[(input_len - 1) - *data_len] != '1') + ++(*data_len); + hrp_len = input_len - (1 + *data_len); + *(data_len) -= 6; + for (i = hrp_len + 1; i < input_len; i++) { + int v = (input[i] & 0x80) ? -1 : charset_rev[(int)input[i]]; + + if (i + 6 < input_len) + data[i - (1 + hrp_len)] = v; + } +} + +static void convert_bits(char *out, int *outlen, const uint8_t *in, + int inlen) +{ + const int outbits = 8, inbits = 5; + uint32_t val = 0, maxv = (((uint32_t)1) << outbits) - 1; + int bits = 0; + + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } +} + +static int address_to_pubkeytxn(char *pkh, const char *addr) { char b58bin[25] = {}; @@ -1743,9 +1788,10 @@ static void address_to_pubkeytxn(char *pkh, const char *addr) memcpy(&pkh[3], &b58bin[1], 20); pkh[23] = 0x88; pkh[24] = 0xac; + return 25; } -static void address_to_scripttxn(char *psh, const char *addr) +static int address_to_scripttxn(char *psh, const char *addr) { char b58bin[25] = {}; @@ -1754,22 +1800,33 @@ static void address_to_scripttxn(char *psh, const char *addr) psh[1] = 0x14; memcpy(&psh[2], &b58bin[1], 20); psh[22] = 0x87; + return 23; +} + +static int segaddress_to_txn(char *p2h, const char *addr) +{ + int data_len, witdata_len = 0; + char *witdata = &p2h[2]; + uint8_t data[84]; + + bech32_decode(data, &data_len, addr); + p2h[0] = data[0]; + /* Witness version is > 0 */ + if (p2h[0]) + p2h[0] += 0x50; + convert_bits(witdata, &witdata_len, data + 1, data_len - 1); + p2h[1] = witdata_len; + return witdata_len + 2; } /* Convert an address to a transaction and return the length of the transaction */ int address_to_txn(char *p2h, const char *addr, const bool script, const bool segwit) { - if (unlikely(segwit)) { - /* It should be impossible to hit this for now */ - LOGEMERG("Segwit bech32 address passed to address_to_txn while unsupported."); - return 0; - } - if (script) { - address_to_scripttxn(p2h, addr); - return 23; - } - address_to_pubkeytxn(p2h, addr); - return 25; + if (segwit) + return segaddress_to_txn(p2h, addr); + if (script) + return address_to_scripttxn(p2h, addr); + return address_to_pubkeytxn(p2h, addr); } /* For encoding nHeight into coinbase, return how many bytes were used */ diff --git a/src/stratifier.c b/src/stratifier.c index 6e3edf1b..ca4fa258 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -389,9 +389,9 @@ static const char *ckdb_seq_names[] = { struct stratifier_data { ckpool_t *ckp; - char txnbin[40]; + char txnbin[48]; int txnlen; - char dontxnbin[40]; + char dontxnbin[48]; int dontxnlen; pool_stats_t stats; @@ -579,7 +579,7 @@ static void generate_coinbase(const ckpool_t *ckp, workbase_t *wb) len += wb->enonce1varlen; len += wb->enonce2varlen; - wb->coinb2bin = ckzalloc(256); + wb->coinb2bin = ckzalloc(512); memcpy(wb->coinb2bin, "\x0a\x63\x6b\x70\x6f\x6f\x6c", 7); wb->coinb2len = 7; if (ckp->btcsig) { @@ -5331,8 +5331,6 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, /* Is this a btc address based username? */ if (!ckp->proxy && (new_user || !user->btcaddress) && (len > 26 && len < 35)) user->btcaddress = generator_checkaddr(ckp, username, &user->script, &user->segwit); - if (user->segwit) /* Bech32 addresses currently unsupported */ - user->btcaddress = false; if (new_user) { LOGNOTICE("Added new user %s%s", username, user->btcaddress ? " as address based registration" : ""); @@ -6839,8 +6837,6 @@ static user_instance_t *generate_remote_user(ckpool_t *ckp, const char *workerna /* Is this a btc address based username? */ if (!ckp->proxy && (new_user || !user->btcaddress) && (len > 26 && len < 35)) user->btcaddress = generator_checkaddr(ckp, username, &user->script, &user->segwit); - if (user->segwit) - user->btcaddress = false; if (new_user) { LOGNOTICE("Added new remote user %s%s", username, user->btcaddress ? " as address based registration" : ""); @@ -8638,10 +8634,6 @@ void *stratifier(void *arg) LOGEMERG("Fatal: btcaddress invalid according to bitcoind"); goto out; } - if (ckp->segwit) { - LOGEMERG("Fatal: bech32 addresses not currently supported"); - goto out; - } /* Store this for use elsewhere */ hex2bin(scriptsig_header_bin, scriptsig_header, 41);