Add basic Segwit support

This commit is contained in:
pooler 2017-04-28 12:19:18 +02:00
parent a0b8895516
commit 46e919f93c
3 changed files with 83 additions and 29 deletions

View file

@ -1,6 +1,6 @@
/*
* Copyright 2010 Jeff Garzik
* Copyright 2012-2015 pooler
* Copyright 2012-2017 pooler
*
* 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
@ -127,7 +127,6 @@ static int opt_retries = -1;
static int opt_fail_pause = 30;
int opt_timeout = 0;
static int opt_scantime = 5;
static const bool opt_time = true;
static enum algos opt_algo = ALGO_SCRYPT;
static int opt_scrypt_n = 1024;
static int opt_n_threads;
@ -344,9 +343,6 @@ err_out:
return false;
}
#define BLOCK_VERSION_MASK 0x000000ff
#define BLOCK_VERSION_CURRENT 4
static bool gbt_work_decode(const json_t *val, struct work *work)
{
int i, n;
@ -360,11 +356,22 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
unsigned char (*merkle_tree)[32] = NULL;
bool coinbase_append = false;
bool submit_coinbase = false;
bool version_force = false;
bool version_reduce = false;
bool segwit = false;
json_t *tmp, *txa;
bool rc = false;
tmp = json_object_get(val, "rules");
if (tmp && json_is_array(tmp)) {
n = json_array_size(tmp);
for (i = 0; i < n; i++) {
const char *s = json_string_value(json_array_get(tmp, i));
if (!s)
continue;
if (!strcmp(s, "segwit") || !strcmp(s, "!segwit"))
segwit = true;
}
}
tmp = json_object_get(val, "mutable");
if (tmp && json_is_array(tmp)) {
n = json_array_size(tmp);
@ -376,10 +383,6 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
coinbase_append = true;
else if (!strcmp(s, "submit/coinbase"))
submit_coinbase = true;
else if (!strcmp(s, "version/force"))
version_force = true;
else if (!strcmp(s, "version/reduce"))
version_reduce = true;
}
}
@ -396,13 +399,6 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
goto out;
}
version = json_integer_value(tmp);
if ((version & BLOCK_VERSION_MASK) > BLOCK_VERSION_CURRENT) {
if (version_reduce) {
version = (version & ~BLOCK_VERSION_MASK) | BLOCK_VERSION_CURRENT;
} else if (!version_force) {
applog(LOG_WARNING, "Unrecognized block version: %u", version);
}
}
if (unlikely(!jobj_binary(val, "previousblockhash", prevhash, sizeof(prevhash)))) {
applog(LOG_ERR, "JSON invalid previousblockhash");
@ -472,19 +468,56 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
le32enc((uint32_t *)(cbtx+37), 0xffffffff); /* prev txout index */
cbtx_size = 43;
/* BIP 34: height in coinbase */
for (n = work->height; n; n >>= 8)
for (n = work->height; n; n >>= 8) {
cbtx[cbtx_size++] = n & 0xff;
if (n < 0x100 && n >= 0x80)
cbtx[cbtx_size++] = 0;
}
cbtx[42] = cbtx_size - 43;
cbtx[41] = cbtx_size - 42; /* scriptsig length */
le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */
cbtx_size += 4;
cbtx[cbtx_size++] = 1; /* out-counter */
cbtx[cbtx_size++] = segwit ? 2 : 1; /* out-counter */
le32enc((uint32_t *)(cbtx+cbtx_size), (uint32_t)cbvalue); /* value */
le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32);
cbtx_size += 8;
cbtx[cbtx_size++] = pk_script_size; /* txout-script length */
memcpy(cbtx+cbtx_size, pk_script, pk_script_size);
cbtx_size += pk_script_size;
if (segwit) {
unsigned char (*wtree)[32] = calloc(tx_count + 2, 32);
memset(cbtx+cbtx_size, 0, 8); /* value */
cbtx_size += 8;
cbtx[cbtx_size++] = 38; /* txout-script length */
cbtx[cbtx_size++] = 0x6a; /* txout-script */
cbtx[cbtx_size++] = 0x24;
cbtx[cbtx_size++] = 0xaa;
cbtx[cbtx_size++] = 0x21;
cbtx[cbtx_size++] = 0xa9;
cbtx[cbtx_size++] = 0xed;
for (i = 0; i < tx_count; i++) {
const json_t *tx = json_array_get(txa, i);
const json_t *hash = json_object_get(tx, "hash");
if (!hash || !hex2bin(wtree[1+i], json_string_value(hash), 32)) {
applog(LOG_ERR, "JSON invalid transaction hash");
free(wtree);
goto out;
}
memrev(wtree[1+i], 32);
}
n = tx_count + 1;
while (n > 1) {
if (n % 2)
memcpy(wtree[n], wtree[n-1], 32);
n = (n + 1) / 2;
for (i = 0; i < n; i++)
sha256d(wtree[i], wtree[2*i], 64);
}
memset(wtree[1], 0, 32); /* witness reserved value = 0 */
sha256d(cbtx+cbtx_size, wtree[0], 64);
cbtx_size += 32;
free(wtree);
}
le32enc((uint32_t *)(cbtx+cbtx_size), 0); /* lock time */
cbtx_size += 4;
coinbase_append = true;
@ -547,14 +580,23 @@ static bool gbt_work_decode(const json_t *val, struct work *work)
tmp = json_array_get(txa, i);
const char *tx_hex = json_string_value(json_object_get(tmp, "data"));
const int tx_size = tx_hex ? strlen(tx_hex) / 2 : 0;
unsigned char *tx = malloc(tx_size);
if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) {
applog(LOG_ERR, "JSON invalid transactions");
if (segwit) {
const char *txid = json_string_value(json_object_get(tmp, "txid"));
if (!txid || !hex2bin(merkle_tree[1 + i], txid, 32)) {
applog(LOG_ERR, "JSON invalid transaction txid");
goto out;
}
memrev(merkle_tree[1 + i], 32);
} else {
unsigned char *tx = malloc(tx_size);
if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) {
applog(LOG_ERR, "JSON invalid transactions");
free(tx);
goto out;
}
sha256d(merkle_tree[1 + i], tx, tx_size);
free(tx);
goto out;
}
sha256d(merkle_tree[1 + i], tx, tx_size);
free(tx);
if (!submit_coinbase)
strcat(work->txs, tx_hex);
}
@ -764,13 +806,14 @@ static const char *getwork_req =
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
#define GBT_RULES "[\"segwit\"]"
static const char *gbt_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
GBT_CAPABILITIES "}], \"id\":0}\r\n";
GBT_CAPABILITIES ", \"rules\": " GBT_RULES "}], \"id\":0}\r\n";
static const char *gbt_lp_req =
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
GBT_CAPABILITIES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n";
GBT_CAPABILITIES ", \"rules\": " GBT_RULES ", \"longpollid\": \"%s\"}], \"id\":0}\r\n";
static bool get_upstream_work(CURL *curl, struct work *work)
{

View file

@ -196,6 +196,7 @@ extern struct work_restart *work_restart;
extern void applog(int prio, const char *fmt, ...);
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, int *curl_err, int flags);
void memrev(unsigned char *p, size_t len);
extern void bin2hex(char *s, const unsigned char *p, size_t len);
extern char *abin2hex(const unsigned char *p, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);

12
util.c
View file

@ -1,7 +1,7 @@
/*
* Copyright 2010 Jeff Garzik
* Copyright 2012 Luke Dashjr
* Copyright 2012-2015 pooler
* Copyright 2012-2017 pooler
*
* 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
@ -507,6 +507,16 @@ err_out:
return NULL;
}
void memrev(unsigned char *p, size_t len)
{
unsigned char c, *q;
for (q = p + len - 1; p < q; p++, q--) {
c = *p;
*p = *q;
*q = c;
}
}
void bin2hex(char *s, const unsigned char *p, size_t len)
{
int i;