From 9610e94e592eae4a725f54027e1f2324faf5eb67 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Tue, 6 Feb 2018 09:35:48 +1100 Subject: [PATCH] Use the RPC output from bitcoind to determine if an address is a script or a segwit bech32 address, currently refusing to mine to a bech32 address. --- src/bitcoin.c | 51 +++++++++++++++++++++--------------------------- src/bitcoin.h | 4 ++-- src/ckpool.h | 4 ++++ src/generator.c | 13 ++++-------- src/generator.h | 4 ++-- src/libckpool.c | 12 ++++++------ src/stratifier.c | 31 ++++++++++++++++------------- 7 files changed, 57 insertions(+), 62 deletions(-) diff --git a/src/bitcoin.c b/src/bitcoin.c index 4381270f..646ad472 100644 --- a/src/bitcoin.c +++ b/src/bitcoin.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 Con Kolivas + * Copyright 2014-2018 Con Kolivas * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -16,7 +16,6 @@ #include "bitcoin.h" #include "stratifier.h" -static const char *b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static char* understood_rules[] = {"segwit"}; static bool check_required_rule(const char* rule) @@ -32,37 +31,16 @@ static bool check_required_rule(const char* rule) /* Take a bitcoin address and do some sanity checks on it, then send it to * bitcoind to see if it's a valid address */ -bool validate_address(connsock_t *cs, const char *address) +bool validate_address(connsock_t *cs, const char *address, bool *script, bool *segwit) { - json_t *val, *res_val, *valid_val; + json_t *val, *res_val, *valid_val, *tmp_val; char rpc_req[128]; bool ret = false; - int len, i, j; if (unlikely(!address)) { LOGWARNING("Null address passed to validate_address"); return ret; } - len = strlen(address); - if (len < 27 || len > 36) { - LOGWARNING("Invalid address length %d passed to validate_address", len); - return ret; - } - for (i = 0; i < len; i++) { - char c = address[i]; - bool found = false; - - for (j = 0; j < 58; j++) { - if (c == b58chars[j]) { - found = true; - break; - } - } - if (!found) { - LOGNOTICE("Invalid char %.1s passed to validate_address", &c); - return ret; - } - } snprintf(rpc_req, 128, "{\"method\": \"validateaddress\", \"params\": [\"%s\"]}\n", address); val = json_rpc_call(cs, rpc_req); @@ -80,12 +58,27 @@ bool validate_address(connsock_t *cs, const char *address) LOGERR("Failed to get isvalid json response to validate_address"); goto out; } - if (!json_is_true(valid_val)) + if (!json_is_true(valid_val)) { LOGDEBUG("Bitcoin address %s is NOT valid", address); - else { - LOGDEBUG("Bitcoin address %s IS valid", address); - ret = true; + goto out; } + ret = true; + tmp_val = json_object_get(res_val, "isscript"); + if (unlikely(!tmp_val)) { + /* All recent bitcoinds should support this, if not, look for + * a 3x address to at least support it on mainnet */ + LOGDEBUG("No isscript support from bitcoind"); + if (address[0] == '3') + *script = true; + goto out; + } + *script = json_is_true(tmp_val); + tmp_val = json_object_get(res_val, "iswitness"); + if (unlikely(!tmp_val)) + goto out; + *segwit = json_is_true(tmp_val); + LOGDEBUG("Bitcoin address %s IS valid%s%s", address, *script ? " script" : "", + *segwit ? " segwit" : ""); out: if (val) json_decref(val); diff --git a/src/bitcoin.h b/src/bitcoin.h index 08f6bbe4..782a2073 100644 --- a/src/bitcoin.h +++ b/src/bitcoin.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 Con Kolivas + * Copyright 2014-2018 Con Kolivas * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -12,7 +12,7 @@ typedef struct genwork gbtbase_t; -bool validate_address(connsock_t *cs, const char *address); +bool validate_address(connsock_t *cs, const char *address, bool *script, bool *segwit); bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt); void clear_gbtbase(gbtbase_t *gbt); int get_blockcount(connsock_t *cs); diff --git a/src/ckpool.h b/src/ckpool.h index e998816f..b8681dd6 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -241,8 +241,12 @@ struct ckpool_instance { /* Coinbase data */ char *btcaddress; // Address to mine to + bool script; // Address is a script address + bool segwit; // Address is a segwit address char *btcsig; // Optional signature to add to coinbase char *donaddress; // Donation address + bool donscript; // Donation is a script + bool donsegwit; // Donation is segwit bool donvalid; // Donation address works on this network /* Stratum options */ diff --git a/src/generator.c b/src/generator.c index 4d7a1947..61cf4464 100644 --- a/src/generator.c +++ b/src/generator.c @@ -253,7 +253,7 @@ static bool server_alive(ckpool_t *ckp, server_instance_t *si, bool pinging) goto out; } clear_gbtbase(&gbt); - if (!ckp->node && !validate_address(cs, ckp->btcaddress)) { + if (!ckp->node && !validate_address(cs, ckp->btcaddress, &ckp->script, &ckp->segwit)) { LOGWARNING("Invalid btcaddress: %s !", ckp->btcaddress); goto out; } @@ -473,11 +473,6 @@ retry: memset(buf + 12 + 64, 0, 1); sprintf(blockmsg, "%sblock:%s", ret ? "" : "no", buf + 12); send_proc(ckp->stratifier, blockmsg); - } else if (cmdmatch(buf, "checkaddr:")) { - if (validate_address(cs, buf + 10)) - send_unix_msg(umsg->sockd, "true"); - else - send_unix_msg(umsg->sockd, "false"); } else if (cmdmatch(buf, "reconnect")) { goto reconnect; } else if (cmdmatch(buf, "loglevel")) { @@ -904,7 +899,7 @@ out: return ret; } -bool generator_checkaddr(ckpool_t *ckp, const char *addr) +bool generator_checkaddr(ckpool_t *ckp, const char *addr, bool *script, bool *segwit) { gdata_t *gdata = ckp->gdata; server_instance_t *si; @@ -917,7 +912,7 @@ bool generator_checkaddr(ckpool_t *ckp, const char *addr) goto out; } cs = &si->cs; - ret = validate_address(cs, addr); + ret = validate_address(cs, addr, script, segwit); out: return ret; } @@ -931,7 +926,7 @@ char *generator_get_txn(ckpool_t *ckp, const char *hash) si = gdata->current_si; if (unlikely(!si)) { - LOGWARNING("No live current server in generator_checkaddr"); + LOGWARNING("No live current server in generator_get_txn"); goto out; } cs = &si->cs; diff --git a/src/generator.h b/src/generator.h index 8b23f989..242466eb 100644 --- a/src/generator.h +++ b/src/generator.h @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 Con Kolivas + * Copyright 2014-2018 Con Kolivas * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -19,7 +19,7 @@ void generator_add_send(ckpool_t *ckp, json_t *val); struct genwork *generator_getbase(ckpool_t *ckp); int generator_getbest(ckpool_t *ckp, char *hash); -bool generator_checkaddr(ckpool_t *ckp, const char *addr); +bool generator_checkaddr(ckpool_t *ckp, const char *addr, bool *script, bool *segwit); char *generator_get_txn(ckpool_t *ckp, const char *hash); bool generator_submitblock(ckpool_t *ckp, const char *buf); void generator_preciousblock(ckpool_t *ckp, const char *hash); diff --git a/src/libckpool.c b/src/libckpool.c index bac71efa..694444ed 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2016 Con Kolivas + * Copyright 2014-2018 Con Kolivas * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -1743,15 +1743,15 @@ void address_to_pubkeytxn(char *pkh, const char *addr) pkh[24] = 0xac; } -void address_to_scripttxn(char *pkh, const char *addr) +void address_to_scripttxn(char *psh, const char *addr) { char b58bin[25] = {}; b58tobin(b58bin, addr); - pkh[0] = 0xa9; - pkh[1] = 0x14; - memcpy(&pkh[2], &b58bin[1], 20); - pkh[22] = 0x87; + psh[0] = 0xa9; + psh[1] = 0x14; + memcpy(&psh[2], &b58bin[1], 20); + psh[22] = 0x87; } /* For encoding nHeight into coinbase, return how many bytes were used */ diff --git a/src/stratifier.c b/src/stratifier.c index 796edb15..2b9ff353 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1,5 +1,5 @@ /* - * Copyright 2014-2017 Con Kolivas + * Copyright 2014-2018 Con Kolivas * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -113,6 +113,8 @@ struct user_instance { int id; char *secondaryuserid; bool btcaddress; + bool script; + bool segwit; /* A linked list of all connected instances of this user */ stratum_instance_t *clients; @@ -5328,7 +5330,9 @@ 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->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" : ""); @@ -6834,7 +6838,9 @@ 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->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" : ""); @@ -8605,13 +8611,6 @@ static void read_poolstats(ckpool_t *ckp, int *tvsec_diff) } } -/* Braindead check to see if this btcaddress is an M of N script address which - * is currently unsupported as a generation address. */ -static bool script_address(const char *btcaddress) -{ - return btcaddress[0] == '3'; -} - void *stratifier(void *arg) { proc_instance_t *pi = (proc_instance_t *)arg; @@ -8635,14 +8634,18 @@ void *stratifier(void *arg) cksleep_ms(10); if (!ckp->proxy) { - if (!generator_checkaddr(ckp, ckp->btcaddress)) { + if (!generator_checkaddr(ckp, ckp->btcaddress, &ckp->script, &ckp->segwit)) { 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); - if (script_address(ckp->btcaddress)) { + if (ckp->script) { address_to_scripttxn(sdata->pubkeytxnbin, ckp->btcaddress); sdata->pubkeytxnlen = 23; } else { @@ -8650,9 +8653,9 @@ void *stratifier(void *arg) sdata->pubkeytxnlen = 25; } - if (generator_checkaddr(ckp, ckp->donaddress)) { + if (generator_checkaddr(ckp, ckp->donaddress, &ckp->donscript, &ckp->donsegwit)) { ckp->donvalid = true; - if (script_address(ckp->donaddress)) { + if (ckp->donscript) { sdata->donkeytxnlen = 23; address_to_scripttxn(sdata->donkeytxnbin, ckp->donaddress); } else {