Browse Source

Move merkle tree generation to the stratifier along with all transaction data to allow transaction data to be used directly in future code

master
ckolivas 9 years ago
parent
commit
8702c02822
  1. 112
      src/bitcoin.c
  2. 2
      src/bitcoin.h
  3. 112
      src/stratifier.c

112
src/bitcoin.c

@ -79,99 +79,6 @@ out:
return ret;
}
/* Distill down a set of transactions into an efficient tree arrangement for
* stratum messages and fast work assembly. */
static bool gbt_merkle_bins(gbtbase_t *gbt, json_t *transaction_arr)
{
int i, j, binleft, binlen;
json_t *arr_val;
uchar *hashbin;
dealloc(gbt->txn_data);
dealloc(gbt->txn_hashes);
gbt->txns = 0;
gbt->merkles = 0;
gbt->txns = json_array_size(transaction_arr);
binlen = gbt->txns * 32 + 32;
hashbin = alloca(binlen + 32);
memset(hashbin, 0, 32);
binleft = binlen / 32;
if (gbt->txns) {
int len = 1, ofs = 0;
const char *txn;
for (i = 0; i < gbt->txns; i++) {
arr_val = json_array_get(transaction_arr, i);
txn = json_string_value(json_object_get(arr_val, "data"));
if (!txn) {
LOGWARNING("json_string_value fail - cannot find transaction data");
return false;
}
len += strlen(txn);
}
gbt->txn_data = ckzalloc(len + 1);
gbt->txn_hashes = ckzalloc(gbt->txns * 65 + 1);
memset(gbt->txn_hashes, 0x20, gbt->txns * 65); // Spaces
for (i = 0; i < gbt->txns; i++) {
char binswap[32];
const char *hash;
arr_val = json_array_get(transaction_arr, i);
hash = json_string_value(json_object_get(arr_val, "hash"));
txn = json_string_value(json_object_get(arr_val, "data"));
len = strlen(txn);
memcpy(gbt->txn_data + ofs, txn, len);
ofs += len;
#if 0
/* In case we ever want to be a gbt poolproxy */
if (!hash) {
char *txn_bin;
int txn_len;
txn_len = len / 2;
txn_bin = ckalloc(txn_len);
hex2bin(txn_bin, txn, txn_len);
/* This is needed for pooled mining since only
* transaction data and not hashes are sent */
gen_hash(txn_bin, hashbin + 32 + 32 * i, txn_len);
continue;
}
#endif
if (!hex2bin(binswap, hash, 32)) {
LOGERR("Failed to hex2bin hash in gbt_merkle_bins");
return false;
}
memcpy(gbt->txn_hashes + i * 65, hash, 64);
bswap_256(hashbin + 32 + 32 * i, binswap);
}
}
if (binleft > 1) {
while (42) {
uchar merklebin[32];
if (binleft == 1)
break;
memcpy(merklebin, hashbin + 32, 32);
__bin2hex(&gbt->merklehash[gbt->merkles][0], merklebin, 32);
LOGDEBUG("MH%d %s",gbt->merkles, &gbt->merklehash[gbt->merkles][0]);
gbt->merkles++;
if (binleft % 2) {
memcpy(hashbin + binlen, hashbin + binlen - 32, 32);
binlen += 32;
binleft++;
}
for (i = 32, j = 64; j < binlen; i += 32, j += 64)
gen_hash(hashbin + j, hashbin + i, 64);
binleft /= 2;
binlen = binleft * 32;
}
}
LOGINFO("Stored %d transactions", gbt->txns);
return true;
}
static const char *gbt_req = "{\"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n";
/* Request getblocktemplate from bitcoind already connected with a connsock_t
@ -179,7 +86,7 @@ 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 *transaction_arr, *coinbase_aux, *res_val, *val, *array;
json_t *txn_array, *coinbase_aux, *res_val, *val;
const char *previousblockhash;
char hash_swap[32], tmp[32];
uint64_t coinbasevalue;
@ -189,7 +96,6 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
int version;
int curtime;
int height;
int i;
bool ret = false;
val = json_rpc_call(cs, gbt_req);
@ -205,7 +111,7 @@ 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"));
transaction_arr = json_object_get(res_val, "transactions");
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"));
@ -258,19 +164,7 @@ bool gen_gbtbase(connsock_t *cs, gbtbase_t *gbt)
gbt->flags = strdup(flags);
json_object_set_new_nocheck(gbt->json, "flags", json_string_nocheck(gbt->flags));
gbt_merkle_bins(gbt, transaction_arr);
json_object_set_new_nocheck(gbt->json, "txns", json_integer(gbt->txns));
if (gbt->txns) {
json_object_set_new_nocheck(gbt->json, "txn_data", json_string_nocheck(gbt->txn_data));
json_object_set_new_nocheck(gbt->json, "txn_hashes", json_string_nocheck(gbt->txn_hashes));
}
json_object_set_new_nocheck(gbt->json, "merkles", json_integer(gbt->merkles));
if (gbt->merkles) {
array = json_array();
for (i = 0; i < gbt->merkles; i++)
json_array_append_new(array, json_string_nocheck(&gbt->merklehash[i][0]));
json_object_set_new_nocheck(gbt->json, "merklehash", array);
}
json_object_set_new_nocheck(gbt->json, "transactions", json_deep_copy(txn_array));
ret = true;
out:

2
src/bitcoin.h

@ -1,5 +1,5 @@
/*
* Copyright 2014 Con Kolivas
* Copyright 2014-2016 Con Kolivas
*
* 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

112
src/stratifier.c

@ -1104,6 +1104,95 @@ struct update_req {
static void broadcast_ping(sdata_t *sdata);
/* Distill down a set of transactions into an efficient tree arrangement for
* stratum messages and fast work assembly. */
static void wb_merkle_bins(workbase_t *wb, json_t *txn_array)
{
int i, j, binleft, binlen;
json_t *arr_val;
uchar *hashbin;
wb->txns = json_array_size(txn_array);
wb->merkles = 0;
binlen = wb->txns * 32 + 32;
hashbin = alloca(binlen + 32);
memset(hashbin, 0, 32);
binleft = binlen / 32;
if (wb->txns) {
int len = 1, ofs = 0;
const char *txn;
for (i = 0; i < wb->txns; i++) {
arr_val = json_array_get(txn_array, i);
txn = json_string_value(json_object_get(arr_val, "data"));
if (!txn) {
LOGWARNING("json_string_value fail - cannot find transaction data");
return;
}
len += strlen(txn);
}
wb->txn_data = ckzalloc(len + 1);
wb->txn_hashes = ckzalloc(wb->txns * 65 + 1);
memset(wb->txn_hashes, 0x20, wb->txns * 65); // Spaces
for (i = 0; i < wb->txns; i++) {
char binswap[32];
const char *hash;
arr_val = json_array_get(txn_array, i);
hash = json_string_value(json_object_get(arr_val, "hash"));
txn = json_string_value(json_object_get(arr_val, "data"));
len = strlen(txn);
memcpy(wb->txn_data + ofs, txn, len);
ofs += len;
#if 0
/* In case we ever want to be a gbt poolproxy */
if (!hash) {
char *txn_bin;
int txn_len;
txn_len = len / 2;
txn_bin = ckalloc(txn_len);
hex2bin(txn_bin, txn, txn_len);
/* This is needed for pooled mining since only
* transaction data and not hashes are sent */
gen_hash(txn_bin, hashbin + 32 + 32 * i, txn_len);
continue;
}
#endif
if (!hex2bin(binswap, hash, 32)) {
LOGERR("Failed to hex2bin hash in gbt_merkle_bins");
return;
}
memcpy(wb->txn_hashes + i * 65, hash, 64);
bswap_256(hashbin + 32 + 32 * i, binswap);
}
} else
wb->txn_hashes = ckzalloc(1);
if (binleft > 1) {
while (42) {
uchar merklebin[32];
if (binleft == 1)
break;
memcpy(merklebin, hashbin + 32, 32);
__bin2hex(&wb->merklehash[wb->merkles][0], merklebin, 32);
LOGDEBUG("MH%d %s",wb->merkles, &wb->merklehash[wb->merkles][0]);
wb->merkles++;
if (binleft % 2) {
memcpy(hashbin + binlen, hashbin + binlen - 32, 32);
binlen += 32;
binleft++;
}
for (i = 32, j = 64; j < binlen; i += 32, j += 64)
gen_hash(hashbin + j, hashbin + i, 64);
binleft /= 2;
binlen = binleft * 32;
}
}
}
/* This function assumes it will only receive a valid json gbt base template
* since checking should have been done earlier, and creates the base template
* for generating work templates. */
@ -1113,11 +1202,11 @@ static void *do_update(void *arg)
int prio = ur->prio, retries = 0;
ckpool_t *ckp = ur->ckp;
sdata_t *sdata = ckp->data;
json_t *val, *txn_array;
bool new_block = false;
bool ret = false;
workbase_t *wb;
time_t now_t;
json_t *val;
char *buf;
pthread_detach(pthread_self());
@ -1158,25 +1247,8 @@ retry:
json_uint64cpy(&wb->coinbasevalue, val, "coinbasevalue");
json_intcpy(&wb->height, val, "height");
json_strdup(&wb->flags, val, "flags");
json_intcpy(&wb->txns, val, "txns");
if (wb->txns) {
json_strdup(&wb->txn_data, val, "txn_data");
json_strdup(&wb->txn_hashes, val, "txn_hashes");
} else
wb->txn_hashes = ckzalloc(1);
json_intcpy(&wb->merkles, val, "merkles");
wb->merkle_array = json_array();
if (wb->merkles) {
json_t *arr;
int i;
arr = json_object_get(val, "merklehash");
for (i = 0; i < wb->merkles; i++) {
strcpy(&wb->merklehash[i][0], json_string_value(json_array_get(arr, i)));
hex2bin(&wb->merklebin[i][0], &wb->merklehash[i][0], 32);
json_array_append_new(wb->merkle_array, json_string(&wb->merklehash[i][0]));
}
}
txn_array = json_object_get(val, "transactions");
wb_merkle_bins(wb, txn_array);
json_decref(val);
generate_coinbase(ckp, wb);

Loading…
Cancel
Save