Browse Source

Remove now unnecessary intermediate steps converting gbtbase to workbase by making them one.

master
Con Kolivas 8 years ago
parent
commit
11cf360d9b
  1. 36
      src/bitcoin.c
  2. 22
      src/bitcoin.h
  3. 15
      src/generator.c
  4. 2
      src/generator.h
  5. 104
      src/stratifier.c
  6. 76
      src/stratifier.h

36
src/bitcoin.c

@ -14,6 +14,7 @@
#include "ckpool.h" #include "ckpool.h"
#include "libckpool.h" #include "libckpool.h"
#include "bitcoin.h" #include "bitcoin.h"
#include "stratifier.h"
static const char *b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; static const char *b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
static char* understood_rules[] = {"segwit"}; static char* understood_rules[] = {"segwit"};
@ -98,9 +99,8 @@ static const char *gbt_req = "{\"method\": \"getblocktemplate\", \"params\": [{\
* required to assemble a mining template, storing it in a gbtbase_t structure */ * required to assemble a mining template, storing it in a gbtbase_t structure */
bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt) bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
{ {
json_t *txn_array, *rules_array, *coinbase_aux, *res_val, *val; json_t *rules_array, *coinbase_aux, *res_val, *val;
const char *previousblockhash; const char *previousblockhash;
const char *witnessdata_check;
char hash_swap[32], tmp[32]; char hash_swap[32], tmp[32];
uint64_t coinbasevalue; uint64_t coinbasevalue;
const char *target; const char *target;
@ -139,13 +139,11 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
previousblockhash = json_string_value(json_object_get(res_val, "previousblockhash")); previousblockhash = json_string_value(json_object_get(res_val, "previousblockhash"));
target = json_string_value(json_object_get(res_val, "target")); target = json_string_value(json_object_get(res_val, "target"));
txn_array = json_object_get(res_val, "transactions");
version = json_integer_value(json_object_get(res_val, "version")); version = json_integer_value(json_object_get(res_val, "version"));
curtime = json_integer_value(json_object_get(res_val, "curtime")); curtime = json_integer_value(json_object_get(res_val, "curtime"));
bits = json_string_value(json_object_get(res_val, "bits")); bits = json_string_value(json_object_get(res_val, "bits"));
height = json_integer_value(json_object_get(res_val, "height")); height = json_integer_value(json_object_get(res_val, "height"));
coinbasevalue = json_integer_value(json_object_get(res_val, "coinbasevalue")); coinbasevalue = json_integer_value(json_object_get(res_val, "coinbasevalue"));
witnessdata_check = json_string_value(json_object_get(res_val, "default_witness_commitment"));
coinbase_aux = json_object_get(res_val, "coinbaseaux"); coinbase_aux = json_object_get(res_val, "coinbaseaux");
flags = json_string_value(json_object_get(coinbase_aux, "flags")); flags = json_string_value(json_object_get(coinbase_aux, "flags"));
@ -154,15 +152,16 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
goto out; goto out;
} }
gbt->json = json_object(); /* Store getblocktemplate for remainder of json components as is */
json_incref(res_val);
json_object_del(val, "result");
gbt->json = res_val;
hex2bin(hash_swap, previousblockhash, 32); hex2bin(hash_swap, previousblockhash, 32);
swap_256(tmp, hash_swap); swap_256(tmp, hash_swap);
__bin2hex(gbt->prevhash, tmp, 32); __bin2hex(gbt->prevhash, tmp, 32);
json_object_set_new_nocheck(gbt->json, "prevhash", json_string_nocheck(gbt->prevhash));
strncpy(gbt->target, target, 65); strncpy(gbt->target, target, 65);
json_object_set_new_nocheck(gbt->json, "target", json_string_nocheck(gbt->target));
hex2bin(hash_swap, target, 32); hex2bin(hash_swap, target, 32);
bswap_256(tmp, hash_swap); bswap_256(tmp, hash_swap);
@ -170,13 +169,12 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
json_object_set_new_nocheck(gbt->json, "diff", json_real(gbt->diff)); json_object_set_new_nocheck(gbt->json, "diff", json_real(gbt->diff));
gbt->version = version; gbt->version = version;
json_object_set_new_nocheck(gbt->json, "version", json_integer(version));
gbt->curtime = curtime; gbt->curtime = curtime;
json_object_set_new_nocheck(gbt->json, "curtime", json_integer(curtime));
snprintf(gbt->ntime, 9, "%08x", curtime); snprintf(gbt->ntime, 9, "%08x", curtime);
json_object_set_new_nocheck(gbt->json, "ntime", json_string_nocheck(gbt->ntime)); json_object_set_new_nocheck(gbt->json, "ntime", json_string_nocheck(gbt->ntime));
sscanf(gbt->ntime, "%x", &gbt->ntime32);
snprintf(gbt->bbversion, 9, "%08x", version); snprintf(gbt->bbversion, 9, "%08x", version);
json_object_set_new_nocheck(gbt->json, "bbversion", json_string_nocheck(gbt->bbversion)); json_object_set_new_nocheck(gbt->json, "bbversion", json_string_nocheck(gbt->bbversion));
@ -185,37 +183,21 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
json_object_set_new_nocheck(gbt->json, "nbit", json_string_nocheck(gbt->nbit)); json_object_set_new_nocheck(gbt->json, "nbit", json_string_nocheck(gbt->nbit));
gbt->coinbasevalue = coinbasevalue; gbt->coinbasevalue = coinbasevalue;
json_object_set_new_nocheck(gbt->json, "coinbasevalue", json_integer(coinbasevalue));
gbt->height = height; gbt->height = height;
json_object_set_new_nocheck(gbt->json, "height", json_integer(height));
gbt->flags = strdup(flags); gbt->flags = strdup(flags);
json_object_set_new_nocheck(gbt->json, "flags", json_string_nocheck(gbt->flags));
json_object_set_new_nocheck(gbt->json, "transactions", json_deep_copy(txn_array));
json_object_set_new_nocheck(gbt->json, "rules", json_deep_copy(rules_array));
// Bitcoind includes the default commitment, though it's not part of the
// BIP145 spec. As long as transactions aren't being filtered, it's useful
// To check against this during segwit's deployment.
json_object_set_new_nocheck(gbt->json, "default_witness_commitment", json_string_nocheck(witnessdata_check ? witnessdata_check : ""));
ret = true; ret = true;
out: out:
json_decref(val);
return ret; return ret;
} }
void clear_gbtbase(gbtbase_t *gbt) void clear_gbtbase(gbtbase_t *gbt)
{ {
dealloc(gbt->flags); free(gbt->flags);
dealloc(gbt->txn_data); if (gbt->json)
dealloc(gbt->txn_hashes);
json_decref(gbt->json); json_decref(gbt->json);
gbt->json = NULL;
memset(gbt, 0, sizeof(gbtbase_t)); memset(gbt, 0, sizeof(gbtbase_t));
} }

22
src/bitcoin.h

@ -10,27 +10,7 @@
#ifndef BITCOIN_H #ifndef BITCOIN_H
#define BITCOIN_H #define BITCOIN_H
struct gbtbase { typedef struct genwork gbtbase_t;
char target[68];
double diff;
uint32_t version;
uint32_t curtime;
char prevhash[68];
char ntime[12];
char bbversion[12];
char nbit[12];
uint64_t coinbasevalue;
int height;
char *flags;
int txns;
char *txn_data;
char *txn_hashes;
int merkles;
char merklehash[16][68];
json_t *json;
};
typedef struct gbtbase gbtbase_t;
bool validate_address(connsock_t *cs, const char *address); bool validate_address(connsock_t *cs, const char *address);
bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt); bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt);

15
src/generator.c

@ -834,12 +834,11 @@ static void reconnect_generator(ckpool_t *ckp)
send_proc(ckp->generator, "reconnect"); send_proc(ckp->generator, "reconnect");
} }
json_t *generator_genbase(ckpool_t *ckp) struct genwork *generator_getbase(ckpool_t *ckp)
{ {
gbtbase_t gbt = {.target={}};
gdata_t *gdata = ckp->gdata; gdata_t *gdata = ckp->gdata;
gbtbase_t *gbt = NULL;
server_instance_t *si; server_instance_t *si;
json_t *val = NULL;
connsock_t *cs; connsock_t *cs;
/* Use temporary variables to prevent deref while accessing */ /* Use temporary variables to prevent deref while accessing */
@ -849,17 +848,15 @@ json_t *generator_genbase(ckpool_t *ckp)
goto out; goto out;
} }
cs = &si->cs; cs = &si->cs;
if (unlikely(!gen_gbtbase(cs, &gbt))) { gbt = ckzalloc(sizeof(gbtbase_t));
if (unlikely(!gen_gbtbase(cs, gbt))) {
LOGWARNING("Failed to get block template from %s:%s", cs->url, cs->port); LOGWARNING("Failed to get block template from %s:%s", cs->url, cs->port);
si->alive = cs->alive = false; si->alive = cs->alive = false;
reconnect_generator(ckp); reconnect_generator(ckp);
goto out; dealloc(gbt);
} }
val = gbt.json;
gbt.json = NULL;
clear_gbtbase(&gbt);
out: out:
return val; return gbt;
} }
int generator_getbest(ckpool_t *ckp, char *hash) int generator_getbest(ckpool_t *ckp, char *hash)

2
src/generator.h

@ -17,7 +17,7 @@
#define GETBEST_SUCCESS 1 #define GETBEST_SUCCESS 1
void generator_add_send(ckpool_t *ckp, json_t *val); void generator_add_send(ckpool_t *ckp, json_t *val);
json_t *generator_genbase(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);
char *generator_get_txn(ckpool_t *ckp, const char *hash); char *generator_get_txn(ckpool_t *ckp, const char *hash);

104
src/stratifier.c

@ -80,80 +80,7 @@ struct pool_stats {
typedef struct pool_stats pool_stats_t; typedef struct pool_stats pool_stats_t;
struct workbase { typedef struct genwork workbase_t;
/* Hash table data */
UT_hash_handle hh;
/* The next two fields need to be consecutive as both of them are
* used as the key for their hashtable entry in remote_workbases */
int64_t id;
/* The client id this workinfo came from if remote */
int64_t client_id;
char idstring[20];
/* How many readers we currently have of this workbase, set
* under write workbase_lock */
int readcount;
/* The id a remote workinfo is mapped to locally */
int64_t mapped_id;
ts_t gentime;
tv_t retired;
/* GBT/shared variables */
char target[68];
double diff;
double network_diff;
uint32_t version;
uint32_t curtime;
char prevhash[68];
char ntime[12];
uint32_t ntime32;
char bbversion[12];
char nbit[12];
uint64_t coinbasevalue;
int height;
char *flags;
int txns;
char *txn_data;
char *txn_hashes;
char witnessdata[80]; //null-terminated ascii
bool insert_witness;
int merkles;
char merklehash[16][68];
char merklebin[16][32];
json_t *merkle_array;
/* Template variables, lengths are binary lengths! */
char *coinb1; // coinbase1
uchar *coinb1bin;
int coinb1len; // length of above
char enonce1const[32]; // extranonce1 section that is constant
uchar enonce1constbin[16];
int enonce1constlen; // length of above - usually zero unless proxying
int enonce1varlen; // length of unique extranonce1 string for each worker - usually 8
int enonce2varlen; // length of space left for extranonce2 - usually 8 unless proxying
char *coinb2; // coinbase2
uchar *coinb2bin;
int coinb2len; // length of above
/* Cached header binary */
char headerbin[112];
char *logdir;
ckpool_t *ckp;
bool proxy; /* This workbase is proxied work */
bool incomplete; /* This is a remote workinfo without all the txn data */
};
typedef struct workbase workbase_t;
struct json_params { struct json_params {
json_t *method; json_t *method;
@ -729,6 +656,8 @@ static void clear_workbase(workbase_t *wb)
free(wb->coinb2bin); free(wb->coinb2bin);
free(wb->coinb2); free(wb->coinb2);
json_decref(wb->merkle_array); json_decref(wb->merkle_array);
if (wb->json)
json_decref(wb->json);
free(wb); free(wb);
} }
@ -1468,8 +1397,8 @@ static void gbt_witness_data(workbase_t *wb, json_t *txn_array)
* are serialised. */ * are serialised. */
static void block_update(ckpool_t *ckp, int *prio) static void block_update(ckpool_t *ckp, int *prio)
{ {
json_t *val, *txn_array, *rules_array;
const char* witnessdata_check, *rule; const char* witnessdata_check, *rule;
json_t *txn_array, *rules_array;
sdata_t *sdata = ckp->sdata; sdata_t *sdata = ckp->sdata;
bool new_block = false; bool new_block = false;
int i, retries = 0; int i, retries = 0;
@ -1479,8 +1408,8 @@ static void block_update(ckpool_t *ckp, int *prio)
time_t now_t; time_t now_t;
retry: retry:
val = generator_genbase(ckp); wb = generator_getbase(ckp);
if (unlikely(!val)) { if (unlikely(!wb)) {
if (retries++ < 5 || *prio == GEN_PRIORITY) { if (retries++ < 5 || *prio == GEN_PRIORITY) {
LOGWARNING("Generator returned failure in update_base, retry #%d", retries); LOGWARNING("Generator returned failure in update_base, retry #%d", retries);
goto retry; goto retry;
@ -1491,27 +1420,13 @@ retry:
if (unlikely(retries)) if (unlikely(retries))
LOGWARNING("Generator succeeded in update_base after retrying"); LOGWARNING("Generator succeeded in update_base after retrying");
wb = ckzalloc(sizeof(workbase_t));
wb->ckp = ckp; wb->ckp = ckp;
json_strcpy(wb->target, val, "target"); txn_array = json_object_get(wb->json, "transactions");
json_dblcpy(&wb->diff, val, "diff");
json_uintcpy(&wb->version, val, "version");
json_uintcpy(&wb->curtime, val, "curtime");
json_strcpy(wb->prevhash, val, "prevhash");
json_strcpy(wb->ntime, val, "ntime");
sscanf(wb->ntime, "%x", &wb->ntime32);
json_strcpy(wb->bbversion, val, "bbversion");
json_strcpy(wb->nbit, val, "nbit");
json_uint64cpy(&wb->coinbasevalue, val, "coinbasevalue");
json_intcpy(&wb->height, val, "height");
json_strdup(&wb->flags, val, "flags");
txn_array = json_object_get(val, "transactions");
txns = wb_merkle_bin_txns(ckp, sdata, wb, txn_array, true); txns = wb_merkle_bin_txns(ckp, sdata, wb, txn_array, true);
wb->insert_witness = false; wb->insert_witness = false;
memset(wb->witnessdata, 0, sizeof(wb->witnessdata)); rules_array = json_object_get(wb->json, "rules");
rules_array = json_object_get(val, "rules");
if (rules_array) { if (rules_array) {
int rule_count = json_array_size(rules_array); int rule_count = json_array_size(rules_array);
@ -1523,7 +1438,7 @@ retry:
if (*rule == '!') if (*rule == '!')
rule++; rule++;
if (safecmp(rule, "segwit")) { if (safecmp(rule, "segwit")) {
witnessdata_check = json_string_value(json_object_get(val, "default_witness_commitment")); witnessdata_check = json_string_value(json_object_get(wb->json, "default_witness_commitment"));
gbt_witness_data(wb, txn_array); gbt_witness_data(wb, txn_array);
// Verify against the pre-calculated value if it exists. Skip the size/OP_RETURN bytes. // Verify against the pre-calculated value if it exists. Skip the size/OP_RETURN bytes.
if (wb->insert_witness && witnessdata_check[0] && safecmp(witnessdata_check + 4, wb->witnessdata) != 0) if (wb->insert_witness && witnessdata_check[0] && safecmp(witnessdata_check + 4, wb->witnessdata) != 0)
@ -1533,7 +1448,6 @@ retry:
} }
} }
json_decref(val);
generate_coinbase(ckp, wb); generate_coinbase(ckp, wb);
add_base(ckp, sdata, wb, &new_block); add_base(ckp, sdata, wb, &new_block);

76
src/stratifier.h

@ -10,6 +10,82 @@
#ifndef STRATIFIER_H #ifndef STRATIFIER_H
#define STRATIFIER_H #define STRATIFIER_H
/* Generic structure for both workbase in stratifier and gbtbase in generator */
struct genwork {
/* Hash table data */
UT_hash_handle hh;
/* The next two fields need to be consecutive as both of them are
* used as the key for their hashtable entry in remote_workbases */
int64_t id;
/* The client id this workinfo came from if remote */
int64_t client_id;
char idstring[20];
/* How many readers we currently have of this workbase, set
* under write workbase_lock */
int readcount;
/* The id a remote workinfo is mapped to locally */
int64_t mapped_id;
ts_t gentime;
tv_t retired;
/* GBT/shared variables */
char target[68];
double diff;
double network_diff;
uint32_t version;
uint32_t curtime;
char prevhash[68];
char ntime[12];
uint32_t ntime32;
char bbversion[12];
char nbit[12];
uint64_t coinbasevalue;
int height;
char *flags;
int txns;
char *txn_data;
char *txn_hashes;
char witnessdata[80]; //null-terminated ascii
bool insert_witness;
int merkles;
char merklehash[16][68];
char merklebin[16][32];
json_t *merkle_array;
/* Template variables, lengths are binary lengths! */
char *coinb1; // coinbase1
uchar *coinb1bin;
int coinb1len; // length of above
char enonce1const[32]; // extranonce1 section that is constant
uchar enonce1constbin[16];
int enonce1constlen; // length of above - usually zero unless proxying
int enonce1varlen; // length of unique extranonce1 string for each worker - usually 8
int enonce2varlen; // length of space left for extranonce2 - usually 8 unless proxying
char *coinb2; // coinbase2
uchar *coinb2bin;
int coinb2len; // length of above
/* Cached header binary */
char headerbin[112];
char *logdir;
ckpool_t *ckp;
bool proxy; /* This workbase is proxied work */
bool incomplete; /* This is a remote workinfo without all the txn data */
json_t *json; /* getblocktemplate json */
};
void parse_remote_txns(ckpool_t *ckp, const json_t *val); void parse_remote_txns(ckpool_t *ckp, const json_t *val);
#define parse_upstream_txns(ckp, val) parse_remote_txns(ckp, val) #define parse_upstream_txns(ckp, val) parse_remote_txns(ckp, val)
void parse_upstream_auth(ckpool_t *ckp, json_t *val); void parse_upstream_auth(ckpool_t *ckp, json_t *val);

Loading…
Cancel
Save