Add basic Segwit support
This commit is contained in:
parent
a0b8895516
commit
46e919f93c
3 changed files with 83 additions and 29 deletions
99
cpu-miner.c
99
cpu-miner.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 Jeff Garzik
|
* 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
|
* 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
|
||||||
|
@ -127,7 +127,6 @@ static int opt_retries = -1;
|
||||||
static int opt_fail_pause = 30;
|
static int opt_fail_pause = 30;
|
||||||
int opt_timeout = 0;
|
int opt_timeout = 0;
|
||||||
static int opt_scantime = 5;
|
static int opt_scantime = 5;
|
||||||
static const bool opt_time = true;
|
|
||||||
static enum algos opt_algo = ALGO_SCRYPT;
|
static enum algos opt_algo = ALGO_SCRYPT;
|
||||||
static int opt_scrypt_n = 1024;
|
static int opt_scrypt_n = 1024;
|
||||||
static int opt_n_threads;
|
static int opt_n_threads;
|
||||||
|
@ -344,9 +343,6 @@ err_out:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLOCK_VERSION_MASK 0x000000ff
|
|
||||||
#define BLOCK_VERSION_CURRENT 4
|
|
||||||
|
|
||||||
static bool gbt_work_decode(const json_t *val, struct work *work)
|
static bool gbt_work_decode(const json_t *val, struct work *work)
|
||||||
{
|
{
|
||||||
int i, n;
|
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;
|
unsigned char (*merkle_tree)[32] = NULL;
|
||||||
bool coinbase_append = false;
|
bool coinbase_append = false;
|
||||||
bool submit_coinbase = false;
|
bool submit_coinbase = false;
|
||||||
bool version_force = false;
|
bool segwit = false;
|
||||||
bool version_reduce = false;
|
|
||||||
json_t *tmp, *txa;
|
json_t *tmp, *txa;
|
||||||
bool rc = false;
|
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");
|
tmp = json_object_get(val, "mutable");
|
||||||
if (tmp && json_is_array(tmp)) {
|
if (tmp && json_is_array(tmp)) {
|
||||||
n = json_array_size(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;
|
coinbase_append = true;
|
||||||
else if (!strcmp(s, "submit/coinbase"))
|
else if (!strcmp(s, "submit/coinbase"))
|
||||||
submit_coinbase = true;
|
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;
|
goto out;
|
||||||
}
|
}
|
||||||
version = json_integer_value(tmp);
|
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)))) {
|
if (unlikely(!jobj_binary(val, "previousblockhash", prevhash, sizeof(prevhash)))) {
|
||||||
applog(LOG_ERR, "JSON invalid previousblockhash");
|
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 */
|
le32enc((uint32_t *)(cbtx+37), 0xffffffff); /* prev txout index */
|
||||||
cbtx_size = 43;
|
cbtx_size = 43;
|
||||||
/* BIP 34: height in coinbase */
|
/* BIP 34: height in coinbase */
|
||||||
for (n = work->height; n; n >>= 8)
|
for (n = work->height; n; n >>= 8) {
|
||||||
cbtx[cbtx_size++] = n & 0xff;
|
cbtx[cbtx_size++] = n & 0xff;
|
||||||
|
if (n < 0x100 && n >= 0x80)
|
||||||
|
cbtx[cbtx_size++] = 0;
|
||||||
|
}
|
||||||
cbtx[42] = cbtx_size - 43;
|
cbtx[42] = cbtx_size - 43;
|
||||||
cbtx[41] = cbtx_size - 42; /* scriptsig length */
|
cbtx[41] = cbtx_size - 42; /* scriptsig length */
|
||||||
le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */
|
le32enc((uint32_t *)(cbtx+cbtx_size), 0xffffffff); /* sequence */
|
||||||
cbtx_size += 4;
|
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), (uint32_t)cbvalue); /* value */
|
||||||
le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32);
|
le32enc((uint32_t *)(cbtx+cbtx_size+4), cbvalue >> 32);
|
||||||
cbtx_size += 8;
|
cbtx_size += 8;
|
||||||
cbtx[cbtx_size++] = pk_script_size; /* txout-script length */
|
cbtx[cbtx_size++] = pk_script_size; /* txout-script length */
|
||||||
memcpy(cbtx+cbtx_size, pk_script, pk_script_size);
|
memcpy(cbtx+cbtx_size, pk_script, pk_script_size);
|
||||||
cbtx_size += 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 */
|
le32enc((uint32_t *)(cbtx+cbtx_size), 0); /* lock time */
|
||||||
cbtx_size += 4;
|
cbtx_size += 4;
|
||||||
coinbase_append = true;
|
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);
|
tmp = json_array_get(txa, i);
|
||||||
const char *tx_hex = json_string_value(json_object_get(tmp, "data"));
|
const char *tx_hex = json_string_value(json_object_get(tmp, "data"));
|
||||||
const int tx_size = tx_hex ? strlen(tx_hex) / 2 : 0;
|
const int tx_size = tx_hex ? strlen(tx_hex) / 2 : 0;
|
||||||
unsigned char *tx = malloc(tx_size);
|
if (segwit) {
|
||||||
if (!tx_hex || !hex2bin(tx, tx_hex, tx_size)) {
|
const char *txid = json_string_value(json_object_get(tmp, "txid"));
|
||||||
applog(LOG_ERR, "JSON invalid transactions");
|
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);
|
free(tx);
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
sha256d(merkle_tree[1 + i], tx, tx_size);
|
|
||||||
free(tx);
|
|
||||||
if (!submit_coinbase)
|
if (!submit_coinbase)
|
||||||
strcat(work->txs, tx_hex);
|
strcat(work->txs, tx_hex);
|
||||||
}
|
}
|
||||||
|
@ -764,13 +806,14 @@ static const char *getwork_req =
|
||||||
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
|
||||||
|
|
||||||
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
|
#define GBT_CAPABILITIES "[\"coinbasetxn\", \"coinbasevalue\", \"longpoll\", \"workid\"]"
|
||||||
|
#define GBT_RULES "[\"segwit\"]"
|
||||||
|
|
||||||
static const char *gbt_req =
|
static const char *gbt_req =
|
||||||
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
|
"{\"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 =
|
static const char *gbt_lp_req =
|
||||||
"{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": "
|
"{\"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)
|
static bool get_upstream_work(CURL *curl, struct work *work)
|
||||||
{
|
{
|
||||||
|
|
1
miner.h
1
miner.h
|
@ -196,6 +196,7 @@ extern struct work_restart *work_restart;
|
||||||
extern void applog(int prio, const char *fmt, ...);
|
extern void applog(int prio, const char *fmt, ...);
|
||||||
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
|
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
|
||||||
const char *rpc_req, int *curl_err, int flags);
|
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 void bin2hex(char *s, const unsigned char *p, size_t len);
|
||||||
extern char *abin2hex(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);
|
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
|
||||||
|
|
12
util.c
12
util.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 Jeff Garzik
|
* Copyright 2010 Jeff Garzik
|
||||||
* Copyright 2012 Luke Dashjr
|
* 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
|
* 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
|
||||||
|
@ -507,6 +507,16 @@ err_out:
|
||||||
return NULL;
|
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)
|
void bin2hex(char *s, const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
Loading…
Reference in a new issue