|
|
@ -459,6 +459,9 @@ struct stratifier_data { |
|
|
|
int workbases_generated; |
|
|
|
int workbases_generated; |
|
|
|
txntable_t *txns; |
|
|
|
txntable_t *txns; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Is this a node and unable to rebuild workinfos due to lack of txns */ |
|
|
|
|
|
|
|
bool wbincomplete; |
|
|
|
|
|
|
|
|
|
|
|
/* Semaphore to serialise calls to add_base */ |
|
|
|
/* Semaphore to serialise calls to add_base */ |
|
|
|
sem_t update_sem; |
|
|
|
sem_t update_sem; |
|
|
|
/* Time we last sent out a stratum update */ |
|
|
|
/* Time we last sent out a stratum update */ |
|
|
@ -955,6 +958,7 @@ static void send_workinfo(ckpool_t *ckp, sdata_t *sdata, const workbase_t *wb) |
|
|
|
"createcode", __func__, |
|
|
|
"createcode", __func__, |
|
|
|
"createinet", ckp->serverurl[0]); |
|
|
|
"createinet", ckp->serverurl[0]); |
|
|
|
ckdbq_add(ckp, ID_WORKINFO, val); |
|
|
|
ckdbq_add(ckp, ID_WORKINFO, val); |
|
|
|
|
|
|
|
if (!ckp->proxy) |
|
|
|
send_node_workinfo(sdata, wb); |
|
|
|
send_node_workinfo(sdata, wb); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1117,7 +1121,8 @@ static void broadcast_ping(sdata_t *sdata); |
|
|
|
|
|
|
|
|
|
|
|
/* Build a hashlist of all transactions, allowing us to compare with the list of
|
|
|
|
/* Build a hashlist of all transactions, allowing us to compare with the list of
|
|
|
|
* existing transactions to determine which need to be propagated */ |
|
|
|
* existing transactions to determine which need to be propagated */ |
|
|
|
static void add_txn(sdata_t *sdata, txntable_t **txns, const char *hash, const char *data) |
|
|
|
static void add_txn(ckpool_t *ckp, sdata_t *sdata, txntable_t **txns, const char *hash, |
|
|
|
|
|
|
|
const char *data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool found = false; |
|
|
|
bool found = false; |
|
|
|
txntable_t *txn; |
|
|
|
txntable_t *txn; |
|
|
@ -1127,7 +1132,10 @@ static void add_txn(sdata_t *sdata, txntable_t **txns, const char *hash, const c |
|
|
|
ck_rlock(&sdata->workbase_lock); |
|
|
|
ck_rlock(&sdata->workbase_lock); |
|
|
|
HASH_FIND_STR(sdata->txns, hash, txn); |
|
|
|
HASH_FIND_STR(sdata->txns, hash, txn); |
|
|
|
if (txn) { |
|
|
|
if (txn) { |
|
|
|
txn->refcount++; |
|
|
|
if (ckp->node) |
|
|
|
|
|
|
|
txn->refcount = 100; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
txn->refcount = 20; |
|
|
|
found = true; |
|
|
|
found = true; |
|
|
|
} |
|
|
|
} |
|
|
|
ck_runlock(&sdata->workbase_lock); |
|
|
|
ck_runlock(&sdata->workbase_lock); |
|
|
@ -1138,7 +1146,10 @@ static void add_txn(sdata_t *sdata, txntable_t **txns, const char *hash, const c |
|
|
|
txn = ckzalloc(sizeof(txntable_t)); |
|
|
|
txn = ckzalloc(sizeof(txntable_t)); |
|
|
|
memcpy(txn->hash, hash, 65); |
|
|
|
memcpy(txn->hash, hash, 65); |
|
|
|
txn->data = strdup(data); |
|
|
|
txn->data = strdup(data); |
|
|
|
txn->refcount = 10; |
|
|
|
if (ckp->node) |
|
|
|
|
|
|
|
txn->refcount = 100; |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
txn->refcount = 20; |
|
|
|
HASH_ADD_STR(*txns, hash, txn); |
|
|
|
HASH_ADD_STR(*txns, hash, txn); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1173,7 +1184,7 @@ static void send_node_transactions(sdata_t *sdata, const json_t *txn_val) |
|
|
|
|
|
|
|
|
|
|
|
/* Distill down a set of transactions into an efficient tree arrangement for
|
|
|
|
/* Distill down a set of transactions into an efficient tree arrangement for
|
|
|
|
* stratum messages and fast work assembly. */ |
|
|
|
* stratum messages and fast work assembly. */ |
|
|
|
static void wb_merkle_bins(sdata_t *sdata, workbase_t *wb, json_t *txn_array) |
|
|
|
static void wb_merkle_bins(ckpool_t *ckp, sdata_t *sdata, workbase_t *wb, json_t *txn_array) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int i, j, binleft, binlen, added = 0, purged = 0; |
|
|
|
int i, j, binleft, binlen, added = 0, purged = 0; |
|
|
|
txntable_t *txns = NULL, *tmp, *tmpa; |
|
|
|
txntable_t *txns = NULL, *tmp, *tmpa; |
|
|
@ -1211,7 +1222,7 @@ static void wb_merkle_bins(sdata_t *sdata, workbase_t *wb, json_t *txn_array) |
|
|
|
arr_val = json_array_get(txn_array, i); |
|
|
|
arr_val = json_array_get(txn_array, i); |
|
|
|
hash = json_string_value(json_object_get(arr_val, "hash")); |
|
|
|
hash = json_string_value(json_object_get(arr_val, "hash")); |
|
|
|
txn = json_string_value(json_object_get(arr_val, "data")); |
|
|
|
txn = json_string_value(json_object_get(arr_val, "data")); |
|
|
|
add_txn(sdata, &txns, hash, txn); |
|
|
|
add_txn(ckp, sdata, &txns, hash, txn); |
|
|
|
len = strlen(txn); |
|
|
|
len = strlen(txn); |
|
|
|
memcpy(wb->txn_data + ofs, txn, len); |
|
|
|
memcpy(wb->txn_data + ofs, txn, len); |
|
|
|
ofs += len; |
|
|
|
ofs += len; |
|
|
@ -1268,7 +1279,7 @@ static void wb_merkle_bins(sdata_t *sdata, workbase_t *wb, json_t *txn_array) |
|
|
|
* and remove them. */ |
|
|
|
* and remove them. */ |
|
|
|
ck_wlock(&sdata->workbase_lock); |
|
|
|
ck_wlock(&sdata->workbase_lock); |
|
|
|
HASH_ITER(hh, sdata->txns, tmp, tmpa) { |
|
|
|
HASH_ITER(hh, sdata->txns, tmp, tmpa) { |
|
|
|
if (tmp->refcount--) |
|
|
|
if (tmp->refcount-- > 0) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
HASH_DEL(sdata->txns, tmp); |
|
|
|
HASH_DEL(sdata->txns, tmp); |
|
|
|
dealloc(tmp->data); |
|
|
|
dealloc(tmp->data); |
|
|
@ -1360,7 +1371,7 @@ retry: |
|
|
|
json_intcpy(&wb->height, val, "height"); |
|
|
|
json_intcpy(&wb->height, val, "height"); |
|
|
|
json_strdup(&wb->flags, val, "flags"); |
|
|
|
json_strdup(&wb->flags, val, "flags"); |
|
|
|
txn_array = json_object_get(val, "transactions"); |
|
|
|
txn_array = json_object_get(val, "transactions"); |
|
|
|
wb_merkle_bins(sdata, wb, txn_array); |
|
|
|
wb_merkle_bins(ckp, sdata, wb, txn_array); |
|
|
|
json_decref(val); |
|
|
|
json_decref(val); |
|
|
|
generate_coinbase(ckp, wb); |
|
|
|
generate_coinbase(ckp, wb); |
|
|
|
|
|
|
|
|
|
|
@ -1393,7 +1404,7 @@ out_free: |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool rebuild_txns(sdata_t *sdata, workbase_t *wb, json_t *txnhashes) |
|
|
|
static bool rebuild_txns(ckpool_t *ckp, sdata_t *sdata, workbase_t *wb, json_t *txnhashes) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const char *hashes = json_string_value(txnhashes); |
|
|
|
const char *hashes = json_string_value(txnhashes); |
|
|
|
json_t *txn_array; |
|
|
|
json_t *txn_array; |
|
|
@ -1427,7 +1438,7 @@ static bool rebuild_txns(sdata_t *sdata, workbase_t *wb, json_t *txnhashes) |
|
|
|
ret = false; |
|
|
|
ret = false; |
|
|
|
goto out_unlock; |
|
|
|
goto out_unlock; |
|
|
|
} |
|
|
|
} |
|
|
|
txn->refcount += 2; |
|
|
|
txn->refcount = 100; |
|
|
|
JSON_CPACK(txn_val, "{ss,ss}", |
|
|
|
JSON_CPACK(txn_val, "{ss,ss}", |
|
|
|
"hash", hash, "data", txn->data); |
|
|
|
"hash", hash, "data", txn->data); |
|
|
|
json_array_append_new(txn_array, txn_val); |
|
|
|
json_array_append_new(txn_array, txn_val); |
|
|
@ -1437,7 +1448,7 @@ out_unlock: |
|
|
|
|
|
|
|
|
|
|
|
if (ret) { |
|
|
|
if (ret) { |
|
|
|
LOGINFO("Rebuilt txns into workbase with %d transactions", (int)i); |
|
|
|
LOGINFO("Rebuilt txns into workbase with %d transactions", (int)i); |
|
|
|
wb_merkle_bins(sdata, wb, txn_array); |
|
|
|
wb_merkle_bins(ckp, sdata, wb, txn_array); |
|
|
|
} |
|
|
|
} |
|
|
|
json_decref(txn_array); |
|
|
|
json_decref(txn_array); |
|
|
|
|
|
|
|
|
|
|
@ -1481,11 +1492,18 @@ static void add_node_base(ckpool_t *ckp, json_t *val) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
json_intcpy(&wb->txns, val, "txns"); |
|
|
|
json_intcpy(&wb->txns, val, "txns"); |
|
|
|
txnhashes = json_object_get(val, "txn_hashes"); |
|
|
|
txnhashes = json_object_get(val, "txn_hashes"); |
|
|
|
if (!rebuild_txns(sdata, wb, txnhashes)) { |
|
|
|
if (!rebuild_txns(ckp, sdata, wb, txnhashes)) { |
|
|
|
LOGWARNING("Unable to rebuild transactions from hashes to create workinfo"); |
|
|
|
if (!sdata->wbincomplete) { |
|
|
|
|
|
|
|
sdata->wbincomplete = true; |
|
|
|
|
|
|
|
LOGWARNING("Unable to rebuild transactions to create workinfo, ignore displayed hashrate"); |
|
|
|
|
|
|
|
} |
|
|
|
free(wb); |
|
|
|
free(wb); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (sdata->wbincomplete) { |
|
|
|
|
|
|
|
LOGWARNING("Successfully resumed rebuilding transactions into workinfo"); |
|
|
|
|
|
|
|
sdata->wbincomplete = false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
json_strdup(&wb->coinb1, val, "coinb1"); |
|
|
|
json_strdup(&wb->coinb1, val, "coinb1"); |
|
|
|
json_intcpy(&wb->coinb1len, val, "coinb1len"); |
|
|
|
json_intcpy(&wb->coinb1len, val, "coinb1len"); |
|
|
@ -5589,7 +5607,7 @@ out_unlock: |
|
|
|
} |
|
|
|
} |
|
|
|
ckdbq_add(ckp, ID_SHARES, val); |
|
|
|
ckdbq_add(ckp, ID_SHARES, val); |
|
|
|
out: |
|
|
|
out: |
|
|
|
if ((!result && !submit) || !share) { |
|
|
|
if (!sdata->wbincomplete && ((!result && !submit) || !share)) { |
|
|
|
/* Is this the first in a run of invalids? */ |
|
|
|
/* Is this the first in a run of invalids? */ |
|
|
|
if (client->first_invalid < client->last_share.tv_sec || !client->first_invalid) |
|
|
|
if (client->first_invalid < client->last_share.tv_sec || !client->first_invalid) |
|
|
|
client->first_invalid = now_t; |
|
|
|
client->first_invalid = now_t; |
|
|
@ -6320,7 +6338,7 @@ static void add_node_txns(sdata_t *sdata, const json_t *val) |
|
|
|
} |
|
|
|
} |
|
|
|
HASH_FIND_STR(sdata->txns, hash, txn); |
|
|
|
HASH_FIND_STR(sdata->txns, hash, txn); |
|
|
|
if (txn) { |
|
|
|
if (txn) { |
|
|
|
txn->refcount++; |
|
|
|
txn->refcount = 100; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
txn = ckzalloc(sizeof(txntable_t)); |
|
|
|
txn = ckzalloc(sizeof(txntable_t)); |
|
|
@ -6329,7 +6347,7 @@ static void add_node_txns(sdata_t *sdata, const json_t *val) |
|
|
|
/* Set the refcount for node transactions greater than the
|
|
|
|
/* Set the refcount for node transactions greater than the
|
|
|
|
* upstream pool to ensure we never age them faster than the |
|
|
|
* upstream pool to ensure we never age them faster than the |
|
|
|
* pool does. */ |
|
|
|
* pool does. */ |
|
|
|
txn->refcount = 50; |
|
|
|
txn->refcount = 100; |
|
|
|
HASH_ADD_STR(sdata->txns, hash, txn); |
|
|
|
HASH_ADD_STR(sdata->txns, hash, txn); |
|
|
|
added++; |
|
|
|
added++; |
|
|
|
} |
|
|
|
} |
|
|
|