Browse Source

Merge branch 'master' of https://github.com/ckolivas/cgminer.git

nfactor-troky
Paul Sheppard 12 years ago
parent
commit
01db191aa1
  1. 2
      Makefile.am
  2. 81
      NEWS
  3. 548
      cgminer.c
  4. 9
      configure.ac
  5. 47
      miner.h
  6. 3
      util.c

2
Makefile.am

@ -26,7 +26,7 @@ cgminer_LDADD = $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
@OPENCL_LIBS@ @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \ @OPENCL_LIBS@ @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
@UDEV_LIBS@ @USB_LIBS@ \ @UDEV_LIBS@ @USB_LIBS@ \
@MATH_LIBS@ lib/libgnu.a ccan/libccan.a @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ cgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @OPENCL_FLAGS@ @LIBCURL_CFLAGS@
# common sources # common sources
cgminer_SOURCES := cgminer.c cgminer_SOURCES := cgminer.c

81
NEWS

@ -1,3 +1,84 @@
Version 2.9.1 - November 6, 2012
- Reset work flags to prevent GBT shares from being submitted as stratum ones
after switching.
Version 2.9.0 - November 6, 2012
- Add endian swap defines for where missing.
- Only retarget stratum shares to new pool diff if diff has dropped.
- Remove resetting of probed variable when detecting GBT.
- Count lost stratum share submits and increase message priority to warning.
- Only retrieve a new block template for GBT pools that are the current pool.
- Show which pool untracked share messages have come from.
- Add management for dead GBT pools.
- Count lost shares with stratum as submit stale lost.
- Discard record of stratum shares sent and report lost shares on disconnection
since they will never be reported back.
- Swab, don't just swap the bytes in the GBT target.
- Change status window message for GBT connected pools versus LP.
- Generate a gbt work item from longpoll when required to set new block and
message appropriately.
- Use existing pool submit_old bool from gbt data.
- Retrieve a new block template if more than 30 seconds has elapsed since the
last one to keep the data current and test the pool is still alive.
- Update GBT longpollid every time we request a new longpoll.
- Manage appropriate response codes for share submission with GBT.
- Allow the longpoll thread to start with GBT and only set the longpollid once.
- Correct last few components of GBT block generation courtesy of Luke-jr.
- Use correct length for offsetting extra nonce and remaining data.
- Flip all 80 bytes in the flip function which was wrongly named flip256 for its
purpose.
- Calculate midstate for gbt work and remove now unused variable.
- Use a standard function for flipping bytes.
- Insert the extra nonce and remaining data in the correct position in the
coinbase.
- Remove txn size debugging and enlarge gbt block string to prevent overflow.
- Remove varint display debugging.
- Build varint correctly for share submission and sleep 5 seconds before
retrying submit.
- Make gbt_coinbase large enough for submissions, swap bytes correctly to make a
header from GBT and encode the number of transactions in share submission.
- Store the fixed size entries as static variables in GBT in binary form,
byteswapping as is required.
- 32 bit hex encoded variables should be in LE with GBT.
- Target and prevblockhash need to be reversed from GBT variables.
- Construct block for submission when using GBT.
- Use same string for debug as for submission and make string larger to cope
with future GBT messages.
- Skip trying to decipher LP url if we have GBT support.
- Store all the transaction hashes in pool->txn_hashes instead of separating
txn0 and correct generation of merkle root, fixing memory overwrites.
- Hook into various places to generate GBT work where appropriate.
- Create extra work fields when generating GBT work.
- Generate header from correct hashing generation of the merkle root for GBT.
- Generate the merkle root for gbt work generation.
- Create a store of the transactions with GBT in the minimum size form required
to generate work items with a varied coinbase.
- Create a function that generates a GBT coinbase from the existing pool
variables.
- Extract and store the various variables GBT uses when decoding gbt work.
- Check for invalid json result in work_decode.
- Decode work in separate functions for getwork vs gbt.
- Check for the coinbase/append mutable in GBT support to decide whether to use
it or not.
- Add a gbt mutex within the pool struct for protecting the gbt values.
- Convert work decode function to prepare for decoding block templates.
- Check for GBT support on first probing the pool and convert to using the GBT
request as the rpc request for that pool.
- Make the rpc request used with getwork a pool variable to allow it to be
converted to/from gbt requests.
- Changes to build prototypes to support building on FreeBSD 9.1-RC2 amd64
- Free old stratum_work data before replacing it
- There is no need for addrinfo any more.
- server and client sockaddr_in are no longer used in struct pool.
- Merge pull request #322 from luke-jr/bugfix_stratum_tmpwork
- Set sshare id and swork_id within the sshare mutex to avoid multiple share
submits with the same id.
- Initialize temporary stratum work
Version 2.8.7 - October 29, 2012 Version 2.8.7 - October 29, 2012
- Fail on select() failing in stratum thread without needing to attempt - Fail on select() failing in stratum thread without needing to attempt

548
cgminer.c

@ -405,6 +405,10 @@ static void sharelog(const char*disposition, const struct work*work)
applog(LOG_ERR, "sharelog fwrite error"); applog(LOG_ERR, "sharelog fwrite error");
} }
static char *getwork_req = "{\"method\": \"getwork\", \"params\": [], \"id\":0}\n";
static char *gbt_req = "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": [{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"]}]}\n";
/* Return value is ignored if not called from add_pool_details */ /* Return value is ignored if not called from add_pool_details */
struct pool *add_pool(void) struct pool *add_pool(void)
{ {
@ -416,17 +420,17 @@ struct pool *add_pool(void)
pool->pool_no = pool->prio = total_pools; pool->pool_no = pool->prio = total_pools;
pools = realloc(pools, sizeof(struct pool *) * (total_pools + 2)); pools = realloc(pools, sizeof(struct pool *) * (total_pools + 2));
pools[total_pools++] = pool; pools[total_pools++] = pool;
if (unlikely(pthread_mutex_init(&pool->pool_lock, NULL))) mutex_init(&pool->pool_lock);
quit(1, "Failed to pthread_mutex_init in add_pool");
if (unlikely(pthread_cond_init(&pool->cr_cond, NULL))) if (unlikely(pthread_cond_init(&pool->cr_cond, NULL)))
quit(1, "Failed to pthread_cond_init in add_pool"); quit(1, "Failed to pthread_cond_init in add_pool");
if (unlikely(pthread_mutex_init(&pool->stratum_lock, NULL))) mutex_init(&pool->stratum_lock);
quit(1, "Failed to pthread_mutex_init in add_pool"); mutex_init(&pool->gbt_lock);
INIT_LIST_HEAD(&pool->curlring); INIT_LIST_HEAD(&pool->curlring);
/* Make sure the pool doesn't think we've been idle since time 0 */ /* Make sure the pool doesn't think we've been idle since time 0 */
pool->tv_idle.tv_sec = ~0UL; pool->tv_idle.tv_sec = ~0UL;
pool->rpc_req = getwork_req;
pool->rpc_proxy = NULL; pool->rpc_proxy = NULL;
return pool; return pool;
@ -1353,37 +1357,286 @@ static void calc_midstate(struct work *work)
#endif #endif
} }
static bool work_decode(const json_t *val, struct work *work) /* Generate a GBT coinbase from the existing GBT variables stored. Must be
* entered under gbt_lock */
static void __build_gbt_coinbase(struct pool *pool)
{
int cbt_len, cal_len, orig_len;
unsigned char *coinbase;
uint8_t *extra_len;
cbt_len = strlen(pool->coinbasetxn) / 2;
pool->coinbase_len = cbt_len + 4;
/* We add 4 bytes of extra data corresponding to nonce2 of stratum */
cal_len = pool->coinbase_len + 1;
if (cal_len % 4)
cal_len += 4 - (cal_len % 4);
coinbase = calloc(cal_len, 1);
hex2bin(coinbase, pool->coinbasetxn, 42);
extra_len = (uint8_t *)(coinbase + 41);
orig_len = *extra_len;
hex2bin(coinbase + 42, pool->coinbasetxn + 84, orig_len);
memcpy(coinbase + 42 + orig_len, &pool->nonce2, 4);
*extra_len += 4;
hex2bin(coinbase + 42 + *extra_len, pool->coinbasetxn + 84 + (orig_len * 2), cbt_len - orig_len - 42);
pool->nonce2++;
free(pool->gbt_coinbase);
pool->gbt_coinbase = coinbase;
}
static void gen_hash(unsigned char *data, unsigned char *hash, int len);
/* Process transactions with GBT by storing the binary value of the first
* transaction, and the hashes of the remaining transactions since these
* remain constant with an altered coinbase when generating work. Must be
* entered under gbt_lock */
static bool __build_gbt_txns(struct pool *pool, json_t *res_val)
{
json_t *txn_array;
bool ret = false;
int i, cal_len;
free(pool->txn_hashes);
pool->txn_hashes = NULL;
pool->gbt_txns = 0;
txn_array = json_object_get(res_val, "transactions");
if (!json_is_array(txn_array))
goto out;
ret = true;
pool->gbt_txns = json_array_size(txn_array);
if (!pool->gbt_txns)
goto out;
pool->txn_hashes = calloc(32 * (pool->gbt_txns + 1), 1);
if (unlikely(!pool->txn_hashes))
quit(1, "Failed to calloc txn_hashes in __build_gbt_txns");
for (i = 0; i < pool->gbt_txns; i++) {
json_t *txn_val = json_object_get(json_array_get(txn_array, i), "data");
const char *txn = json_string_value(txn_val);
int txn_len = strlen(txn);
unsigned char *txn_bin;
cal_len = txn_len;
if (cal_len % 4)
cal_len += 4 - (cal_len % 4);
txn_bin = calloc(cal_len, 1);
if (unlikely(!txn_bin))
quit(1, "Failed to calloc txn_bin in __build_gbt_txns");
if (unlikely(!hex2bin(txn_bin, txn, txn_len / 2)))
quit(1, "Failed to hex2bin txn_bin");
gen_hash(txn_bin, pool->txn_hashes + (32 * i), txn_len / 2);
free(txn_bin);
}
out:
return ret;
}
static unsigned char *__gbt_merkleroot(struct pool *pool)
{ {
if (unlikely(!jobj_binary(val, "data", work->data, sizeof(work->data), true))) { unsigned char *merkle_hash;
int i, txns;
merkle_hash = calloc(32 * (pool->gbt_txns + 2), 1);
if (unlikely(!merkle_hash))
quit(1, "Failed to calloc merkle_hash in __gbt_merkleroot");
gen_hash(pool->gbt_coinbase, merkle_hash, pool->coinbase_len);
if (pool->gbt_txns)
memcpy(merkle_hash + 32, pool->txn_hashes, pool->gbt_txns * 32);
txns = pool->gbt_txns + 1;
while (txns > 1) {
if (txns % 2) {
memcpy(&merkle_hash[txns * 32], &merkle_hash[(txns - 1) * 32], 32);
txns++;
}
for (i = 0; i < txns; i += 2){
unsigned char hashout[32];
gen_hash(merkle_hash + (i * 32), hashout, 64);
memcpy(merkle_hash + (i / 2 * 32), hashout, 32);
}
txns /= 2;
}
return merkle_hash;
}
static void calc_diff(struct work *work, int known);
static void gen_gbt_work(struct pool *pool, struct work *work)
{
unsigned char *merkleroot;
char *cbhex;
mutex_lock(&pool->gbt_lock);
__build_gbt_coinbase(pool);
merkleroot = __gbt_merkleroot(pool);
memcpy(work->data, &pool->gbt_version, 4);
memcpy(work->data + 4, pool->previousblockhash, 32);
memcpy(work->data + 4 + 32 + 32, &pool->curtime, 4);
memcpy(work->data + 4 + 32 + 32 + 4, &pool->gbt_bits, 4);
memcpy(work->target, pool->gbt_target, 32);
cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
sprintf(work->gbt_coinbase, "%s", cbhex);
free(cbhex);
/* For encoding the block data on submission */
work->gbt_txns = pool->gbt_txns + 1;
mutex_unlock(&pool->gbt_lock);
memcpy(work->data + 4 + 32, merkleroot, 32);
flip32(work->data + 4 + 32, merkleroot);
free(merkleroot);
memset(work->data + 4 + 32 + 32 + 4 + 4, 0, 4); /* nonce */
hex2bin(work->data + 4 + 32 + 32 + 4 + 4 + 4, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000", 48);
hex2bin(work->hash1, "00000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000010000", 64);
if (opt_debug) {
char *header = bin2hex(work->data, 128);
applog(LOG_DEBUG, "Generated GBT header %s", header);
applog(LOG_DEBUG, "Work coinbase %s", work->gbt_coinbase);
free(header);
}
calc_midstate(work);
local_work++;
work->pool = pool;
work->gbt = true;
work->id = total_work++;
work->longpoll = false;
work->getwork_mode = GETWORK_MODE_GBT;
work->work_block = work_block;
calc_diff(work, 0);
gettimeofday(&work->tv_staged, NULL);
}
static bool gbt_decode(struct pool *pool, json_t *res_val)
{
const char *previousblockhash;
const char *target;
const char *coinbasetxn;
const char *longpollid;
unsigned char hash_swap[32];
int expires;
int version;
int curtime;
bool submitold;
const char *bits;
previousblockhash = json_string_value(json_object_get(res_val, "previousblockhash"));
target = json_string_value(json_object_get(res_val, "target"));
coinbasetxn = json_string_value(json_object_get(json_object_get(res_val, "coinbasetxn"), "data"));
longpollid = json_string_value(json_object_get(res_val, "longpollid"));
expires = json_integer_value(json_object_get(res_val, "expires"));
version = json_integer_value(json_object_get(res_val, "version"));
curtime = json_integer_value(json_object_get(res_val, "curtime"));
submitold = json_is_true(json_object_get(res_val, "submitold"));
bits = json_string_value(json_object_get(res_val, "bits"));
if (!previousblockhash || !target || !coinbasetxn || !longpollid ||
!expires || !version || !curtime || !bits) {
applog(LOG_ERR, "JSON failed to decode GBT");
return false;
}
applog(LOG_DEBUG, "previousblockhash: %s", previousblockhash);
applog(LOG_DEBUG, "target: %s", target);
applog(LOG_DEBUG, "coinbasetxn: %s", coinbasetxn);
applog(LOG_DEBUG, "longpollid: %s", longpollid);
applog(LOG_DEBUG, "expires: %d", expires);
applog(LOG_DEBUG, "version: %d", version);
applog(LOG_DEBUG, "curtime: %d", curtime);
applog(LOG_DEBUG, "submitold: %s", submitold ? "true" : "false");
applog(LOG_DEBUG, "bits: %s", bits);
mutex_lock(&pool->gbt_lock);
free(pool->coinbasetxn);
pool->coinbasetxn = strdup(coinbasetxn);
free(pool->longpollid);
pool->longpollid = strdup(longpollid);
hex2bin(hash_swap, previousblockhash, 32);
swap256(pool->previousblockhash, hash_swap);
hex2bin(hash_swap, target, 32);
swab256(pool->gbt_target, hash_swap);
pool->gbt_expires = expires;
pool->gbt_version = htobe32(version);
pool->curtime = htobe32(curtime);
pool->submit_old = submitold;
hex2bin((unsigned char *)&pool->gbt_bits, bits, 4);
__build_gbt_txns(pool, res_val);
mutex_unlock(&pool->gbt_lock);
return true;
}
static bool getwork_decode(json_t *res_val, struct work *work)
{
if (unlikely(!jobj_binary(res_val, "data", work->data, sizeof(work->data), true))) {
applog(LOG_ERR, "JSON inval data"); applog(LOG_ERR, "JSON inval data");
goto err_out; return false;
} }
if (!jobj_binary(val, "midstate", work->midstate, sizeof(work->midstate), false)) { if (!jobj_binary(res_val, "midstate", work->midstate, sizeof(work->midstate), false)) {
// Calculate it ourselves // Calculate it ourselves
applog(LOG_DEBUG, "Calculating midstate locally"); applog(LOG_DEBUG, "Calculating midstate locally");
calc_midstate(work); calc_midstate(work);
} }
if (!jobj_binary(val, "hash1", work->hash1, sizeof(work->hash1), false)) { if (!jobj_binary(res_val, "hash1", work->hash1, sizeof(work->hash1), false)) {
// Always the same anyway // Always the same anyway
memcpy(work->hash1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0", 64); memcpy(work->hash1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x80\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0", 64);
} }
if (unlikely(!jobj_binary(val, "target", work->target, sizeof(work->target), true))) { if (unlikely(!jobj_binary(res_val, "target", work->target, sizeof(work->target), true))) {
applog(LOG_ERR, "JSON inval target"); applog(LOG_ERR, "JSON inval target");
goto err_out; return false;
}
return true;
}
static bool work_decode(struct pool *pool, struct work *work, json_t *val)
{
json_t *res_val = json_object_get(val, "result");
bool ret = false;
if (!res_val || json_is_null(res_val)) {
applog(LOG_ERR, "JSON Failed to decode result");
goto out;
} }
if (pool->has_gbt) {
if (unlikely(!gbt_decode(pool, res_val)))
goto out;
gettimeofday(&pool->tv_template, NULL);
work->gbt = true;
ret = true;
goto out;
} else if (unlikely(!getwork_decode(res_val, work)))
goto out;
memset(work->hash, 0, sizeof(work->hash)); memset(work->hash, 0, sizeof(work->hash));
gettimeofday(&work->tv_staged, NULL); gettimeofday(&work->tv_staged, NULL);
return true; ret = true;
err_out: out:
return false; return ret;
} }
int dev_from_id(int thr_id) int dev_from_id(int thr_id)
@ -1593,8 +1846,9 @@ static void curses_print_status(void)
mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP", mvwprintw(statuswin, 4, 0, " Connected to multiple pools with%s LP",
have_longpoll ? "": "out"); have_longpoll ? "": "out");
} else { } else {
mvwprintw(statuswin, 4, 0, " Connected to %s with%s LP as user %s", mvwprintw(statuswin, 4, 0, " Connected to %s with%s %s as user %s",
pool->sockaddr_url, have_longpoll ? "": "out", pool->rpc_user); pool->sockaddr_url, have_longpoll ? "": "out",
pool->has_gbt ? "GBT" : "LP", pool->rpc_user);
} }
wclrtoeol(statuswin); wclrtoeol(statuswin);
mvwprintw(statuswin, 5, 0, " Block: %s... Started: %s Best share: %s ", current_hash, blocktime, best_share); mvwprintw(statuswin, 5, 0, " Block: %s... Started: %s Best share: %s ", current_hash, blocktime, best_share);
@ -1879,7 +2133,7 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
struct pool *pool = work->pool; struct pool *pool = work->pool;
struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu; struct cgpu_info *cgpu = thr_info[work->thr_id].cgpu;
if (json_is_true(res)) { if (json_is_true(res) || (work->gbt && json_is_null(res))) {
cgpu->accepted++; cgpu->accepted++;
total_accepted++; total_accepted++;
pool->accepted++; pool->accepted++;
@ -1937,7 +2191,8 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
else else
strcpy(where, ""); strcpy(where, "");
res = json_object_get(val, "reject-reason"); if (!work->gbt)
res = json_object_get(val, "reject-reason");
if (res) { if (res) {
const char *reasontmp = json_string_value(res); const char *reasontmp = json_string_value(res);
@ -2025,7 +2280,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
{ {
char *hexstr = NULL; char *hexstr = NULL;
json_t *val, *res, *err; json_t *val, *res, *err;
char s[345], sd[345]; char s[1024];
bool rc = false; bool rc = false;
int thr_id = work->thr_id; int thr_id = work->thr_id;
struct cgpu_info *cgpu = thr_info[thr_id].cgpu; struct cgpu_info *cgpu = thr_info[thr_id].cgpu;
@ -2046,14 +2301,39 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
hexstr = bin2hex(work->data, sizeof(work->data)); hexstr = bin2hex(work->data, sizeof(work->data));
/* build JSON-RPC request */ /* build JSON-RPC request */
sprintf(s, if (work->gbt) {
"{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}\r\n", char gbt_block[1024], *varint, *header;
hexstr); unsigned char data[80];
sprintf(sd,
"{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", flip80(data, work->data);
hexstr); header = bin2hex(data, 80);
sprintf(gbt_block, "%s", header);
free(header);
if (work->gbt_txns < 0xfd) {
uint8_t val = work->gbt_txns;
varint = bin2hex((const unsigned char *)&val, 1);
} else if (work->gbt_txns <= 0xffff) {
uint16_t val = htole16(work->gbt_txns);
strcat(gbt_block, "fd");
varint = bin2hex((const unsigned char *)&val, 2);
} else {
uint32_t val = htole32(work->gbt_txns);
strcat(gbt_block, "fe");
varint = bin2hex((const unsigned char *)&val, 4);
}
strcat(gbt_block, varint);
free(varint);
strcat(gbt_block, work->gbt_coinbase);
applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd); sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block);
} else
sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr);
applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, s);
strcat(s, "\n");
gettimeofday(&tv_submit, NULL); gettimeofday(&tv_submit, NULL);
/* issue JSON-RPC request */ /* issue JSON-RPC request */
@ -2066,6 +2346,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
pool->remotefail_occasions++; pool->remotefail_occasions++;
applog(LOG_WARNING, "Pool %d communication failure, caching submissions", pool->pool_no); applog(LOG_WARNING, "Pool %d communication failure, caching submissions", pool->pool_no);
} }
sleep(5);
goto out; goto out;
} else if (pool_tclear(pool, &pool->submit_fail)) } else if (pool_tclear(pool, &pool->submit_fail))
applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no);
@ -2158,9 +2439,6 @@ out:
return rc; return rc;
} }
static const char *rpc_req =
"{\"method\": \"getwork\", \"params\": [], \"id\":0}\r\n";
/* In balanced mode, the amount of diff1 solutions per pool is monitored as a /* In balanced mode, the amount of diff1 solutions per pool is monitored as a
* rolling average per 10 minutes and if pools start getting more, it biases * rolling average per 10 minutes and if pools start getting more, it biases
* away from them to distribute work evenly. The share count is reset to the * away from them to distribute work evenly. The share count is reset to the
@ -2290,18 +2568,18 @@ static bool get_upstream_work(struct work *work, CURL *curl)
bool rc = false; bool rc = false;
char *url; char *url;
applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, rpc_req); applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req);
url = pool->rpc_url; url = pool->rpc_url;
gettimeofday(&(work->tv_getwork), NULL); gettimeofday(&(work->tv_getwork), NULL);
val = json_rpc_call(curl, url, pool->rpc_userpass, rpc_req, false, val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false,
false, &work->rolltime, pool, false); false, &work->rolltime, pool, false);
pool_stats->getwork_attempts++; pool_stats->getwork_attempts++;
if (likely(val)) { if (likely(val)) {
rc = work_decode(json_object_get(val, "result"), work); rc = work_decode(pool, work, val);
if (unlikely(!rc)) if (unlikely(!rc))
applog(LOG_DEBUG, "Failed to decode work in get_upstream_work"); applog(LOG_DEBUG, "Failed to decode work in get_upstream_work");
} else } else
@ -2761,6 +3039,29 @@ retry:
goto out; goto out;
} }
if (pool->has_gbt) {
while (pool->idle) {
struct pool *altpool = select_pool(true);
sleep(5);
if (altpool != pool) {
wc->pool = altpool;
inc_queued(altpool);
dec_queued(pool);
goto retry;
}
}
ret_work = make_work();
gen_gbt_work(pool, ret_work);
if (unlikely(!stage_work(ret_work))) {
applog(LOG_ERR, "Failed to stage gbt work in get_work_thread");
kill_work();
free(ret_work);
}
dec_queued(pool);
goto out;
}
if (clone_available()) { if (clone_available()) {
dec_queued(pool); dec_queued(pool);
goto out; goto out;
@ -2941,11 +3242,13 @@ static void *submit_work_thread(void *userdata)
applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no);
applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db"); applog(LOG_DEBUG, "Successfully submitted, adding to stratum_shares db");
} else { } else {
applog(LOG_INFO, "Failed to submit stratum share"); applog(LOG_WARNING, "Failed to submit stratum share to pool %d", pool->pool_no);
mutex_lock(&sshare_lock); mutex_lock(&sshare_lock);
HASH_DEL(stratum_shares, sshare); HASH_DEL(stratum_shares, sshare);
mutex_unlock(&sshare_lock); mutex_unlock(&sshare_lock);
free(sshare); free(sshare);
pool->stale_shares++;
total_stale++;
if (!pool_tset(pool, &pool->submit_fail)) { if (!pool_tset(pool, &pool->submit_fail)) {
total_ro++; total_ro++;
@ -3016,6 +3319,8 @@ static struct pool *priority_pool(int choice)
return ret; return ret;
} }
static bool pool_active(struct pool *pool, bool pinging);
void switch_pools(struct pool *selected) void switch_pools(struct pool *selected)
{ {
struct pool *pool, *last_pool; struct pool *pool, *last_pool;
@ -3084,8 +3389,13 @@ void switch_pools(struct pool *selected)
if (opt_fail_only) if (opt_fail_only)
pool_tset(pool, &pool->lagging); pool_tset(pool, &pool->lagging);
if (pool != last_pool) if (pool != last_pool) {
applog(LOG_WARNING, "Switching to %s", pool->rpc_url); applog(LOG_WARNING, "Switching to %s", pool->rpc_url);
/* Get a fresh block template since we may not have an up to
* date one */
if (pool->has_gbt)
pool_active(pool, true);
}
mutex_lock(&lp_lock); mutex_lock(&lp_lock);
pthread_cond_broadcast(&lp_cond); pthread_cond_broadcast(&lp_cond);
@ -3274,8 +3584,8 @@ static bool test_work_current(struct work *work)
if (!work->stratum) { if (!work->stratum) {
if (work->longpoll) { if (work->longpoll) {
applog(LOG_NOTICE, "LONGPOLL from pool %d detected new block", applog(LOG_NOTICE, "%sLONGPOLL from pool %d detected new block",
work->pool->pool_no); work->gbt ? "GBT " : "", work->pool->pool_no);
work->longpoll = false; work->longpoll = false;
} else if (have_longpoll) } else if (have_longpoll)
applog(LOG_NOTICE, "New block detected on network before longpoll"); applog(LOG_NOTICE, "New block detected on network before longpoll");
@ -3286,8 +3596,8 @@ static bool test_work_current(struct work *work)
} else if (work->longpoll) { } else if (work->longpoll) {
work->longpoll = false; work->longpoll = false;
if (work->pool == current_pool()) { if (work->pool == current_pool()) {
applog(LOG_NOTICE, "LONGPOLL from pool %d requested work restart", applog(LOG_NOTICE, "%sLONGPOLL from pool %d requested work restart",
work->pool->pool_no); work->gbt ? "GBT " : "", work->pool->pool_no);
work_block++; work_block++;
restart_threads(); restart_threads();
} }
@ -4246,7 +4556,7 @@ static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val,
/* Parses stratum json responses and tries to find the id that the request /* Parses stratum json responses and tries to find the id that the request
* matched to and treat it accordingly. */ * matched to and treat it accordingly. */
static bool parse_stratum_response(char *s) static bool parse_stratum_response(struct pool *pool, char *s)
{ {
json_t *val = NULL, *err_val, *res_val, *id_val; json_t *val = NULL, *err_val, *res_val, *id_val;
struct stratum_share *sshare; struct stratum_share *sshare;
@ -4287,9 +4597,9 @@ static bool parse_stratum_response(char *s)
mutex_unlock(&sshare_lock); mutex_unlock(&sshare_lock);
if (!sshare) { if (!sshare) {
if (json_is_true(res_val)) if (json_is_true(res_val))
applog(LOG_NOTICE, "Accepted untracked stratum share"); applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no);
else else
applog(LOG_NOTICE, "Rejected untracked stratum share"); applog(LOG_NOTICE, "Rejected untracked stratum share from pool %d", pool->pool_no);
goto out; goto out;
} }
stratum_share_result(val, res_val, err_val, sshare); stratum_share_result(val, res_val, err_val, sshare);
@ -4305,6 +4615,28 @@ out:
static void pool_resus(struct pool *pool); static void pool_resus(struct pool *pool);
static void clear_stratum_shares(struct pool *pool)
{
struct stratum_share *sshare, *tmpshare;
int cleared = 0;
mutex_lock(&sshare_lock);
HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
if (sshare->work.pool == pool) {
HASH_DEL(stratum_shares, sshare);
free(sshare);
cleared++;
}
}
mutex_unlock(&sshare_lock);
if (cleared) {
applog(LOG_WARNING, "Lost %d shares due to stratum disconnect on pool %d", cleared, pool->pool_no);
pool->stale_shares++;
total_stale++;
}
}
/* One stratum thread per pool that has stratum waits on the socket checking /* One stratum thread per pool that has stratum waits on the socket checking
* for new messages and for the integrity of the socket connection. We reset * for new messages and for the integrity of the socket connection. We reset
* the connection based on the integrity of the receive side only as the send * the connection based on the integrity of the receive side only as the send
@ -4341,6 +4673,11 @@ static void *stratum_thread(void *userdata)
pool->getfail_occasions++; pool->getfail_occasions++;
total_go++; total_go++;
/* If the socket to our stratum pool disconnects, all
* tracked submitted shares are lost and we will leak
* the memory if we don't discard their records. */
clear_stratum_shares(pool);
if (initiate_stratum(pool) && auth_stratum(pool)) if (initiate_stratum(pool) && auth_stratum(pool))
continue; continue;
@ -4356,7 +4693,7 @@ static void *stratum_thread(void *userdata)
continue; continue;
} }
if (!parse_method(pool, s) && !parse_stratum_response(s)) if (!parse_method(pool, s) && !parse_stratum_response(pool, s))
applog(LOG_INFO, "Unknown stratum msg: %s", s); applog(LOG_INFO, "Unknown stratum msg: %s", s);
free(s); free(s);
if (pool->swork.clean) { if (pool->swork.clean) {
@ -4412,7 +4749,10 @@ static bool pool_active(struct pool *pool, bool pinging)
CURL *curl; CURL *curl;
int rolltime; int rolltime;
applog(LOG_INFO, "Testing pool %s", pool->rpc_url); if (pool->has_gbt)
applog(LOG_DEBUG, "Retrieving block template from pool %s", pool->rpc_url);
else
applog(LOG_INFO, "Testing pool %s", pool->rpc_url);
/* This is the central point we activate stratum when we can */ /* This is the central point we activate stratum when we can */
retry_stratum: retry_stratum:
@ -4439,9 +4779,47 @@ retry_stratum:
return false; return false;
} }
/* Probe for GBT support on first pass */
if (!pool->probed && !opt_fix_protocol) {
applog(LOG_DEBUG, "Probing for GBT support");
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass,
gbt_req, true, false, &rolltime, pool, false);
if (val) {
json_t *res_val, *mutables;
int i, mutsize = 0;
res_val = json_object_get(val, "result");
if (res_val) {
mutables = json_object_get(res_val, "mutable");
mutsize = json_array_size(mutables);
}
for (i = 0; i < mutsize; i++) {
json_t *arrval = json_array_get(mutables, i);
if (json_is_string(arrval)) {
const char *mutable = json_string_value(arrval);
/* Only use GBT if it supports coinbase append */
if (!strncasecmp(mutable, "coinbase/append", 15)) {
pool->has_gbt = true;
pool->rpc_req = gbt_req;
break;
}
}
}
json_decref(val);
}
if (pool->has_gbt)
applog(LOG_DEBUG, "GBT coinbase append support found, switching to GBT protocol");
else
applog(LOG_DEBUG, "No GBT coinbase append support found, using getwork protocol");
}
gettimeofday(&tv_getwork, NULL); gettimeofday(&tv_getwork, NULL);
val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, rpc_req, val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass,
true, false, &rolltime, pool, false); pool->rpc_req, true, false, &rolltime, pool, false);
gettimeofday(&tv_getwork_reply, NULL); gettimeofday(&tv_getwork_reply, NULL);
/* Detect if a http getwork pool has an X-Stratum header at startup, /* Detect if a http getwork pool has an X-Stratum header at startup,
@ -4460,7 +4838,7 @@ retry_stratum:
struct work *work = make_work(); struct work *work = make_work();
bool rc; bool rc;
rc = work_decode(json_object_get(val, "result"), work); rc = work_decode(pool, work, val);
if (rc) { if (rc) {
applog(LOG_DEBUG, "Successfully retrieved and deciphered work from pool %u %s", applog(LOG_DEBUG, "Successfully retrieved and deciphered work from pool %u %s",
pool->pool_no, pool->rpc_url); pool->pool_no, pool->rpc_url);
@ -4635,7 +5013,15 @@ static bool reuse_work(struct work *work, struct pool *pool)
if (!pool->stratum_active) if (!pool->stratum_active)
return false; return false;
applog(LOG_DEBUG, "Reusing stratum work"); applog(LOG_DEBUG, "Reusing stratum work");
gen_stratum_work(pool, work);; gen_stratum_work(pool, work);
return true;
}
if (pool->has_gbt) {
if (pool->idle)
return false;
applog(LOG_DEBUG, "Reusing GBT work");
gen_gbt_work(pool, work);
return true; return true;
} }
@ -4827,6 +5213,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id)
goto out; goto out;
} }
/* Reset these flags in case we switch pools with these work structs */
work->stratum = work->gbt = false;
retry: retry:
pool = current_pool(); pool = current_pool();
@ -4941,7 +5329,7 @@ static bool hashtest(struct thr_info *thr, struct work *work)
unsigned char hash2[32]; unsigned char hash2[32];
uint32_t *hash2_32 = (uint32_t *)hash2; uint32_t *hash2_32 = (uint32_t *)hash2;
struct pool *pool = work->pool; struct pool *pool = work->pool;
int i, diff; int i;
for (i = 0; i < 80 / 4; i++) for (i = 0; i < 80 / 4; i++)
swap32[i] = swab32(data32[i]); swap32[i] = swab32(data32[i]);
@ -4967,11 +5355,15 @@ static bool hashtest(struct thr_info *thr, struct work *work)
} }
if (work->stratum) { if (work->stratum) {
int diff;
mutex_lock(&pool->pool_lock); mutex_lock(&pool->pool_lock);
diff = pool->swork.diff; diff = pool->swork.diff;
mutex_unlock(&pool->pool_lock); mutex_unlock(&pool->pool_lock);
if (unlikely(work->sdiff != diff)) { /* Retarget share only if pool diff has dropped since we
* generated this work */
if (unlikely(work->sdiff > diff)) {
applog(LOG_DEBUG, "Share needs retargetting to match pool"); applog(LOG_DEBUG, "Share needs retargetting to match pool");
set_work_target(work, diff); set_work_target(work, diff);
} }
@ -5237,7 +5629,7 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct
work = make_work(); work = make_work();
rc = work_decode(json_object_get(val, "result"), work); rc = work_decode(pool, work, val);
if (unlikely(!rc)) { if (unlikely(!rc)) {
applog(LOG_ERR, "Could not convert longpoll data to work"); applog(LOG_ERR, "Could not convert longpoll data to work");
free_work(work); free_work(work);
@ -5245,15 +5637,18 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct
} }
work->pool = pool; work->pool = pool;
work->rolltime = rolltime; work->rolltime = rolltime;
work->longpoll = true;
memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval)); memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval));
memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval)); memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval));
work->getwork_mode = GETWORK_MODE_LP;
calc_diff(work, 0); calc_diff(work, 0);
if (pool->enabled == POOL_REJECTING) if (pool->enabled == POOL_REJECTING)
work->mandatory = true; work->mandatory = true;
if (pool->has_gbt)
gen_gbt_work(pool, work);
work->longpoll = true;
work->getwork_mode = GETWORK_MODE_LP;
/* We'll be checking this work item twice, but we already know it's /* We'll be checking this work item twice, but we already know it's
* from a new block so explicitly force the new block detection now * from a new block so explicitly force the new block detection now
* rather than waiting for it to hit the stage thread. This also * rather than waiting for it to hit the stage thread. This also
@ -5286,7 +5681,7 @@ static struct pool *select_longpoll_pool(struct pool *cp)
{ {
int i; int i;
if (cp->hdr_path) if (cp->hdr_path || cp->has_gbt)
return cp; return cp;
for (i = 0; i < total_pools; i++) { for (i = 0; i < total_pools; i++) {
struct pool *pool = pools[i]; struct pool *pool = pools[i];
@ -5321,6 +5716,8 @@ static void *longpoll_thread(void *userdata)
struct timeval start, reply, end; struct timeval start, reply, end;
CURL *curl = NULL; CURL *curl = NULL;
int failures = 0; int failures = 0;
char lpreq[1024];
char *lp_url;
int rolltime; int rolltime;
curl = curl_easy_init(); curl = curl_easy_init();
@ -5344,10 +5741,18 @@ retry_pool:
wait_lpcurrent(cp); wait_lpcurrent(cp);
if (cp == pool) if (pool->has_gbt) {
applog(LOG_WARNING, "Long-polling activated for %s", pool->lp_url); lp_url = pool->rpc_url;
else applog(LOG_WARNING, "GBT longpoll ID activated for %s", lp_url);
applog(LOG_WARNING, "Long-polling activated for pool %s via %s", cp->rpc_url, pool->lp_url); } else {
strcpy(lpreq, getwork_req);
lp_url = pool->lp_url;
if (cp == pool)
applog(LOG_WARNING, "Long-polling activated for %s", lp_url);
else
applog(LOG_WARNING, "Long-polling activated for pool %s via %s", cp->rpc_url, lp_url);
}
while (42) { while (42) {
json_t *val, *soval; json_t *val, *soval;
@ -5356,13 +5761,23 @@ retry_pool:
gettimeofday(&start, NULL); gettimeofday(&start, NULL);
/* Update the longpollid every time, but do it under lock to
* avoid races */
if (pool->has_gbt) {
mutex_lock(&pool->gbt_lock);
sprintf(lpreq, "{\"id\": 0, \"method\": \"getblocktemplate\", \"params\": "
"[{\"capabilities\": [\"coinbasetxn\", \"workid\", \"coinbase/append\"], "
"\"longpollid\": \"%s\"}]}\n", pool->longpollid);
mutex_unlock(&pool->gbt_lock);
}
/* Longpoll connections can be persistent for a very long time /* Longpoll connections can be persistent for a very long time
* and any number of issues could have come up in the meantime * and any number of issues could have come up in the meantime
* so always establish a fresh connection instead of relying on * so always establish a fresh connection instead of relying on
* a persistent one. */ * a persistent one. */
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
val = json_rpc_call(curl, pool->lp_url, pool->rpc_userpass, rpc_req, val = json_rpc_call(curl, lp_url, pool->rpc_userpass,
false, true, &rolltime, pool, false); lpreq, false, true, &rolltime, pool, false);
gettimeofday(&reply, NULL); gettimeofday(&reply, NULL);
@ -5384,7 +5799,7 @@ retry_pool:
if (end.tv_sec - start.tv_sec > 30) if (end.tv_sec - start.tv_sec > 30)
continue; continue;
if (failures == 1) if (failures == 1)
applog(LOG_WARNING, "longpoll failed for %s, retrying every 30s", pool->lp_url); applog(LOG_WARNING, "longpoll failed for %s, retrying every 30s", lp_url);
sleep(30); sleep(30);
} }
if (pool != cp) { if (pool != cp) {
@ -5460,8 +5875,18 @@ static void *watchpool_thread(void __maybe_unused *userdata)
if (pool->enabled == POOL_DISABLED || pool->has_stratum) if (pool->enabled == POOL_DISABLED || pool->has_stratum)
continue; continue;
/* Apart from longpollid comms, we retrieve a fresh
* template if more than 30 seconds has elapsed since
* the last one to keep the data current and as a test
* for when the pool dies. */
if (!pool->idle && pool->has_gbt && pool == current_pool() &&
now.tv_sec - pool->tv_template.tv_sec > 60) {
if (!pool_active(pool, true))
pool_died(pool);
}
/* Test pool is idle once every minute */ /* Test pool is idle once every minute */
if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 60) { if (pool->idle && now.tv_sec - pool->tv_idle.tv_sec > 30) {
gettimeofday(&pool->tv_idle, NULL); gettimeofday(&pool->tv_idle, NULL);
if (pool_active(pool, true) && pool_tclear(pool, &pool->idle)) if (pool_active(pool, true) && pool_tclear(pool, &pool->idle))
pool_resus(pool); pool_resus(pool);
@ -6436,6 +6861,7 @@ int main(int argc, char *argv[])
for (i = 0; i < total_pools; i++) { for (i = 0; i < total_pools; i++) {
struct pool *pool = pools[i]; struct pool *pool = pools[i];
if (pool_active(pool, false)) { if (pool_active(pool, false)) {
pool_tclear(pool, &pool->idle);
if (!currentpool) if (!currentpool)
currentpool = pool; currentpool = pool;
applog(LOG_INFO, "Pool %d %s active", pool->pool_no, pool->rpc_url); applog(LOG_INFO, "Pool %d %s active", pool->pool_no, pool->rpc_url);

9
configure.ac

@ -1,8 +1,8 @@
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_maj], [2]) m4_define([v_maj], [2])
m4_define([v_min], [8]) m4_define([v_min], [9])
m4_define([v_mic], [7]) m4_define([v_mic], [1])
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([v_ver], [v_maj.v_min.v_mic])
m4_define([lt_rev], m4_eval(v_maj + v_min)) m4_define([lt_rev], m4_eval(v_maj + v_min))
@ -70,6 +70,9 @@ WS2_LIBS=""
MATH_LIBS="-lm" MATH_LIBS="-lm"
case $target in case $target in
amd64-*)
have_x86_64=true
;;
x86_64-*) x86_64-*)
have_x86_64=true have_x86_64=true
;; ;;
@ -257,7 +260,7 @@ if test "x$curses" = "xno"; then
else else
AC_SEARCH_LIBS(addstr, ncurses pdcurses, [ AC_SEARCH_LIBS(addstr, ncurses pdcurses, [
curses=yes curses=yes
cursesmsg="FOUND: ${ac_cv_search_addstr:2}" cursesmsg="FOUND: ${ac_cv_search_addstr}"
AC_DEFINE([HAVE_CURSES], [1], [Defined to 1 if curses TUI support is wanted]) AC_DEFINE([HAVE_CURSES], [1], [Defined to 1 if curses TUI support is wanted])
], [ ], [
if test "x$curses" = "xyes"; then if test "x$curses" = "xyes"; then

47
miner.h

@ -143,11 +143,15 @@ static inline int fsync (int fd)
* htobe64 also won't exist */ * htobe64 also won't exist */
#ifndef htobe32 #ifndef htobe32
# if __BYTE_ORDER == __LITTLE_ENDIAN # if __BYTE_ORDER == __LITTLE_ENDIAN
# define htole16(x) (x)
# define htole32(x) (x)
# define be32toh(x) bswap_32(x) # define be32toh(x) bswap_32(x)
# define be64toh(x) bswap_64(x) # define be64toh(x) bswap_64(x)
# define htobe32(x) bswap_32(x) # define htobe32(x) bswap_32(x)
# define htobe64(x) bswap_64(x) # define htobe64(x) bswap_64(x)
# elif __BYTE_ORDER == __BIG_ENDIAN # elif __BYTE_ORDER == __BIG_ENDIAN
# define htole16(x) bswap_16(x)
# define htole32(x) bswap_32(x)
# define be32toh(x) (x) # define be32toh(x) (x)
# define be64toh(x) (x) # define be64toh(x) (x)
# define htobe32(x) (x) # define htobe32(x) (x)
@ -544,6 +548,26 @@ static inline void swab256(void *dest_p, const void *src_p)
dest[7] = swab32(src[0]); dest[7] = swab32(src[0]);
} }
static inline void flip32(void *dest_p, const void *src_p)
{
uint32_t *dest = dest_p;
const uint32_t *src = src_p;
int i;
for (i = 0; i < 8; i++)
dest[i] = swab32(src[i]);
}
static inline void flip80(void *dest_p, const void *src_p)
{
uint32_t *dest = dest_p;
const uint32_t *src = src_p;
int i;
for (i = 0; i < 20; i++)
dest[i] = swab32(src[i]);
}
extern void quit(int status, const char *format, ...); extern void quit(int status, const char *format, ...);
static inline void mutex_lock(pthread_mutex_t *lock) static inline void mutex_lock(pthread_mutex_t *lock)
@ -841,6 +865,7 @@ struct pool {
double utility; double utility;
int last_shares, shares; int last_shares, shares;
char *rpc_req;
char *rpc_url; char *rpc_url;
char *rpc_userpass; char *rpc_userpass;
char *rpc_user, *rpc_pass; char *rpc_user, *rpc_pass;
@ -882,6 +907,23 @@ struct pool {
struct stratum_work swork; struct stratum_work swork;
pthread_t stratum_thread; pthread_t stratum_thread;
pthread_mutex_t stratum_lock; pthread_mutex_t stratum_lock;
/* GBT variables */
bool has_gbt;
pthread_mutex_t gbt_lock;
unsigned char previousblockhash[32];
unsigned char gbt_target[32];
char *coinbasetxn;
char *longpollid;
int gbt_expires;
uint32_t gbt_version;
uint32_t curtime;
uint32_t gbt_bits;
unsigned char *gbt_coinbase;
unsigned char *txn_hashes;
int gbt_txns;
int coinbase_len;
struct timeval tv_template;
}; };
#define GETWORK_MODE_TESTPOOL 'T' #define GETWORK_MODE_TESTPOOL 'T'
@ -889,6 +931,7 @@ struct pool {
#define GETWORK_MODE_LP 'L' #define GETWORK_MODE_LP 'L'
#define GETWORK_MODE_BENCHMARK 'B' #define GETWORK_MODE_BENCHMARK 'B'
#define GETWORK_MODE_STRATUM 'S' #define GETWORK_MODE_STRATUM 'S'
#define GETWORK_MODE_GBT 'G'
struct work { struct work {
unsigned char data[128]; unsigned char data[128];
@ -926,6 +969,10 @@ struct work {
char ntime[16]; char ntime[16];
int sdiff; int sdiff;
bool gbt;
char gbt_coinbase[512];
int gbt_txns;
unsigned int work_block; unsigned int work_block;
int id; int id;
UT_hash_handle hh; UT_hash_handle hh;

3
util.c

@ -451,8 +451,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
res_val = json_object_get(val, "result"); res_val = json_object_get(val, "result");
err_val = json_object_get(val, "error"); err_val = json_object_get(val, "error");
if (!res_val || json_is_null(res_val) || if (!res_val ||(err_val && !json_is_null(err_val))) {
(err_val && !json_is_null(err_val))) {
char *s; char *s;
if (err_val) if (err_val)

Loading…
Cancel
Save