Browse Source

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.

master
Con Kolivas 7 years ago
parent
commit
773c9fae1d
  1. 49
      src/bitcoin.c
  2. 4
      src/bitcoin.h
  3. 4
      src/ckpool.h
  4. 13
      src/generator.c
  5. 4
      src/generator.h
  6. 12
      src/libckpool.c
  7. 31
      src/stratifier.c

49
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 * 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 * under the terms of the GNU General Public License as published by the Free
@ -16,7 +16,6 @@
#include "bitcoin.h" #include "bitcoin.h"
#include "stratifier.h" #include "stratifier.h"
static const char *b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
static char* understood_rules[] = {"segwit"}; static char* understood_rules[] = {"segwit"};
static bool check_required_rule(const char* rule) 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 /* Take a bitcoin address and do some sanity checks on it, then send it to
* bitcoind to see if it's a valid address */ * 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]; char rpc_req[128];
bool ret = false; bool ret = false;
int len, i, j;
if (unlikely(!address)) { if (unlikely(!address)) {
LOGWARNING("Null address passed to validate_address"); LOGWARNING("Null address passed to validate_address");
return ret; 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); snprintf(rpc_req, 128, "{\"method\": \"validateaddress\", \"params\": [\"%s\"]}\n", address);
val = json_rpc_call(cs, rpc_req); 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"); LOGERR("Failed to get isvalid json response to validate_address");
goto out; goto out;
} }
if (!json_is_true(valid_val)) if (!json_is_true(valid_val)) {
LOGDEBUG("Bitcoin address %s is NOT valid", address); LOGDEBUG("Bitcoin address %s is NOT valid", address);
else { goto out;
LOGDEBUG("Bitcoin address %s IS valid", address); }
ret = true; 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: out:
if (val) if (val)
json_decref(val); json_decref(val);

4
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 * 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 * under the terms of the GNU General Public License as published by the Free
@ -12,7 +12,7 @@
typedef struct genwork gbtbase_t; 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); bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt);
void clear_gbtbase(gbtbase_t *gbt); void clear_gbtbase(gbtbase_t *gbt);
int get_blockcount(connsock_t *cs); int get_blockcount(connsock_t *cs);

4
src/ckpool.h

@ -241,8 +241,12 @@ struct ckpool_instance {
/* Coinbase data */ /* Coinbase data */
char *btcaddress; // Address to mine to 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 *btcsig; // Optional signature to add to coinbase
char *donaddress; // Donation address char *donaddress; // Donation address
bool donscript; // Donation is a script
bool donsegwit; // Donation is segwit
bool donvalid; // Donation address works on this network bool donvalid; // Donation address works on this network
/* Stratum options */ /* Stratum options */

13
src/generator.c

@ -253,7 +253,7 @@ static bool server_alive(ckpool_t *ckp, server_instance_t *si, bool pinging)
goto out; goto out;
} }
clear_gbtbase(&gbt); 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); LOGWARNING("Invalid btcaddress: %s !", ckp->btcaddress);
goto out; goto out;
} }
@ -473,11 +473,6 @@ retry:
memset(buf + 12 + 64, 0, 1); memset(buf + 12 + 64, 0, 1);
sprintf(blockmsg, "%sblock:%s", ret ? "" : "no", buf + 12); sprintf(blockmsg, "%sblock:%s", ret ? "" : "no", buf + 12);
send_proc(ckp->stratifier, blockmsg); 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")) { } else if (cmdmatch(buf, "reconnect")) {
goto reconnect; goto reconnect;
} else if (cmdmatch(buf, "loglevel")) { } else if (cmdmatch(buf, "loglevel")) {
@ -904,7 +899,7 @@ out:
return ret; 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; gdata_t *gdata = ckp->gdata;
server_instance_t *si; server_instance_t *si;
@ -917,7 +912,7 @@ bool generator_checkaddr(ckpool_t *ckp, const char *addr)
goto out; goto out;
} }
cs = &si->cs; cs = &si->cs;
ret = validate_address(cs, addr); ret = validate_address(cs, addr, script, segwit);
out: out:
return ret; return ret;
} }
@ -931,7 +926,7 @@ char *generator_get_txn(ckpool_t *ckp, const char *hash)
si = gdata->current_si; si = gdata->current_si;
if (unlikely(!si)) { if (unlikely(!si)) {
LOGWARNING("No live current server in generator_checkaddr"); LOGWARNING("No live current server in generator_get_txn");
goto out; goto out;
} }
cs = &si->cs; cs = &si->cs;

4
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 * 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 * 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); void generator_add_send(ckpool_t *ckp, json_t *val);
struct genwork *generator_getbase(ckpool_t *ckp); struct genwork *generator_getbase(ckpool_t *ckp);
int generator_getbest(ckpool_t *ckp, char *hash); 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); char *generator_get_txn(ckpool_t *ckp, const char *hash);
bool generator_submitblock(ckpool_t *ckp, const char *buf); bool generator_submitblock(ckpool_t *ckp, const char *buf);
void generator_preciousblock(ckpool_t *ckp, const char *hash); void generator_preciousblock(ckpool_t *ckp, const char *hash);

12
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 * 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 * 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; pkh[24] = 0xac;
} }
void address_to_scripttxn(char *pkh, const char *addr) void address_to_scripttxn(char *psh, const char *addr)
{ {
char b58bin[25] = {}; char b58bin[25] = {};
b58tobin(b58bin, addr); b58tobin(b58bin, addr);
pkh[0] = 0xa9; psh[0] = 0xa9;
pkh[1] = 0x14; psh[1] = 0x14;
memcpy(&pkh[2], &b58bin[1], 20); memcpy(&psh[2], &b58bin[1], 20);
pkh[22] = 0x87; psh[22] = 0x87;
} }
/* For encoding nHeight into coinbase, return how many bytes were used */ /* For encoding nHeight into coinbase, return how many bytes were used */

31
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 * 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 * under the terms of the GNU General Public License as published by the Free
@ -113,6 +113,8 @@ struct user_instance {
int id; int id;
char *secondaryuserid; char *secondaryuserid;
bool btcaddress; bool btcaddress;
bool script;
bool segwit;
/* A linked list of all connected instances of this user */ /* A linked list of all connected instances of this user */
stratum_instance_t *clients; stratum_instance_t *clients;
@ -5313,7 +5315,9 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client,
/* Is this a btc address based username? */ /* Is this a btc address based username? */
if (!ckp->proxy && (new_user || !user->btcaddress) && (len > 26 && len < 35)) 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) { if (new_user) {
LOGNOTICE("Added new user %s%s", username, user->btcaddress ? LOGNOTICE("Added new user %s%s", username, user->btcaddress ?
" as address based registration" : ""); " as address based registration" : "");
@ -6787,7 +6791,9 @@ static user_instance_t *generate_remote_user(ckpool_t *ckp, const char *workerna
/* Is this a btc address based username? */ /* Is this a btc address based username? */
if (!ckp->proxy && (new_user || !user->btcaddress) && (len > 26 && len < 35)) 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) { if (new_user) {
LOGNOTICE("Added new remote user %s%s", username, user->btcaddress ? LOGNOTICE("Added new remote user %s%s", username, user->btcaddress ?
" as address based registration" : ""); " as address based registration" : "");
@ -8557,13 +8563,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) void *stratifier(void *arg)
{ {
proc_instance_t *pi = (proc_instance_t *)arg; proc_instance_t *pi = (proc_instance_t *)arg;
@ -8587,14 +8586,18 @@ void *stratifier(void *arg)
cksleep_ms(10); cksleep_ms(10);
if (!ckp->proxy) { 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"); LOGEMERG("Fatal: btcaddress invalid according to bitcoind");
goto out; goto out;
} }
if (ckp->segwit) {
LOGEMERG("Fatal: bech32 addresses not currently supported");
goto out;
}
/* Store this for use elsewhere */ /* Store this for use elsewhere */
hex2bin(scriptsig_header_bin, scriptsig_header, 41); hex2bin(scriptsig_header_bin, scriptsig_header, 41);
if (script_address(ckp->btcaddress)) { if (ckp->script) {
address_to_scripttxn(sdata->pubkeytxnbin, ckp->btcaddress); address_to_scripttxn(sdata->pubkeytxnbin, ckp->btcaddress);
sdata->pubkeytxnlen = 23; sdata->pubkeytxnlen = 23;
} else { } else {
@ -8602,9 +8605,9 @@ void *stratifier(void *arg)
sdata->pubkeytxnlen = 25; sdata->pubkeytxnlen = 25;
} }
if (generator_checkaddr(ckp, ckp->donaddress)) { if (generator_checkaddr(ckp, ckp->donaddress, &ckp->donscript, &ckp->donsegwit)) {
ckp->donvalid = true; ckp->donvalid = true;
if (script_address(ckp->donaddress)) { if (ckp->donscript) {
sdata->donkeytxnlen = 23; sdata->donkeytxnlen = 23;
address_to_scripttxn(sdata->donkeytxnbin, ckp->donaddress); address_to_scripttxn(sdata->donkeytxnbin, ckp->donaddress);
} else { } else {

Loading…
Cancel
Save