diff --git a/src/bitcoin.c b/src/bitcoin.c index c8444261..ada453ff 100644 --- a/src/bitcoin.c +++ b/src/bitcoin.c @@ -14,6 +14,7 @@ #include "ckpool.h" #include "libckpool.h" #include "bitcoin.h" +#include "stratifier.h" static const char *b58chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; 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 */ 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 *witnessdata_check; char hash_swap[32], tmp[32]; uint64_t coinbasevalue; 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")); 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")); curtime = json_integer_value(json_object_get(res_val, "curtime")); bits = json_string_value(json_object_get(res_val, "bits")); height = json_integer_value(json_object_get(res_val, "height")); 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"); 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; } - 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); swap_256(tmp, hash_swap); __bin2hex(gbt->prevhash, tmp, 32); - json_object_set_new_nocheck(gbt->json, "prevhash", json_string_nocheck(gbt->prevhash)); strncpy(gbt->target, target, 65); - json_object_set_new_nocheck(gbt->json, "target", json_string_nocheck(gbt->target)); hex2bin(hash_swap, target, 32); 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)); gbt->version = version; - json_object_set_new_nocheck(gbt->json, "version", json_integer(version)); gbt->curtime = curtime; - json_object_set_new_nocheck(gbt->json, "curtime", json_integer(curtime)); snprintf(gbt->ntime, 9, "%08x", curtime); 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); 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)); gbt->coinbasevalue = coinbasevalue; - json_object_set_new_nocheck(gbt->json, "coinbasevalue", json_integer(coinbasevalue)); gbt->height = height; - json_object_set_new_nocheck(gbt->json, "height", json_integer(height)); 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; - out: - json_decref(val); return ret; } void clear_gbtbase(gbtbase_t *gbt) { - dealloc(gbt->flags); - dealloc(gbt->txn_data); - dealloc(gbt->txn_hashes); - json_decref(gbt->json); - gbt->json = NULL; + free(gbt->flags); + if (gbt->json) + json_decref(gbt->json); memset(gbt, 0, sizeof(gbtbase_t)); } diff --git a/src/bitcoin.h b/src/bitcoin.h index a27c91f3..08f6bbe4 100644 --- a/src/bitcoin.h +++ b/src/bitcoin.h @@ -10,27 +10,7 @@ #ifndef BITCOIN_H #define BITCOIN_H -struct gbtbase { - 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; +typedef struct genwork gbtbase_t; bool validate_address(connsock_t *cs, const char *address); bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt); diff --git a/src/generator.c b/src/generator.c index 5c3eaa52..7c910686 100644 --- a/src/generator.c +++ b/src/generator.c @@ -834,12 +834,11 @@ static void reconnect_generator(ckpool_t *ckp) 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; + gbtbase_t *gbt = NULL; server_instance_t *si; - json_t *val = NULL; connsock_t *cs; /* Use temporary variables to prevent deref while accessing */ @@ -849,17 +848,15 @@ json_t *generator_genbase(ckpool_t *ckp) goto out; } 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); si->alive = cs->alive = false; reconnect_generator(ckp); - goto out; + dealloc(gbt); } - val = gbt.json; - gbt.json = NULL; - clear_gbtbase(&gbt); out: - return val; + return gbt; } int generator_getbest(ckpool_t *ckp, char *hash) diff --git a/src/generator.h b/src/generator.h index 6e91c5b7..8b23f989 100644 --- a/src/generator.h +++ b/src/generator.h @@ -17,7 +17,7 @@ #define GETBEST_SUCCESS 1 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); bool generator_checkaddr(ckpool_t *ckp, const char *addr); char *generator_get_txn(ckpool_t *ckp, const char *hash); diff --git a/src/stratifier.c b/src/stratifier.c index 997a8487..aed9fa9f 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -80,80 +80,7 @@ struct pool_stats { typedef struct pool_stats pool_stats_t; -struct workbase { - /* 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; +typedef struct genwork workbase_t; struct json_params { json_t *method; @@ -729,6 +656,8 @@ static void clear_workbase(workbase_t *wb) free(wb->coinb2bin); free(wb->coinb2); json_decref(wb->merkle_array); + if (wb->json) + json_decref(wb->json); free(wb); } @@ -1468,8 +1397,8 @@ static void gbt_witness_data(workbase_t *wb, json_t *txn_array) * are serialised. */ static void block_update(ckpool_t *ckp, int *prio) { - json_t *val, *txn_array, *rules_array; const char* witnessdata_check, *rule; + json_t *txn_array, *rules_array; sdata_t *sdata = ckp->sdata; bool new_block = false; int i, retries = 0; @@ -1479,8 +1408,8 @@ static void block_update(ckpool_t *ckp, int *prio) time_t now_t; retry: - val = generator_genbase(ckp); - if (unlikely(!val)) { + wb = generator_getbase(ckp); + if (unlikely(!wb)) { if (retries++ < 5 || *prio == GEN_PRIORITY) { LOGWARNING("Generator returned failure in update_base, retry #%d", retries); goto retry; @@ -1491,27 +1420,13 @@ retry: if (unlikely(retries)) LOGWARNING("Generator succeeded in update_base after retrying"); - wb = ckzalloc(sizeof(workbase_t)); wb->ckp = ckp; - json_strcpy(wb->target, val, "target"); - 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"); + txn_array = json_object_get(wb->json, "transactions"); txns = wb_merkle_bin_txns(ckp, sdata, wb, txn_array, true); wb->insert_witness = false; - memset(wb->witnessdata, 0, sizeof(wb->witnessdata)); - rules_array = json_object_get(val, "rules"); + rules_array = json_object_get(wb->json, "rules"); if (rules_array) { int rule_count = json_array_size(rules_array); @@ -1523,7 +1438,7 @@ retry: if (*rule == '!') rule++; 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); // 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) @@ -1533,7 +1448,6 @@ retry: } } - json_decref(val); generate_coinbase(ckp, wb); add_base(ckp, sdata, wb, &new_block); diff --git a/src/stratifier.h b/src/stratifier.h index 2c4375cf..cc201890 100644 --- a/src/stratifier.h +++ b/src/stratifier.h @@ -10,6 +10,82 @@ #ifndef 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); #define parse_upstream_txns(ckp, val) parse_remote_txns(ckp, val) void parse_upstream_auth(ckpool_t *ckp, json_t *val);