Handle network errors properly

This commit is contained in:
pooler 2012-01-21 00:31:51 +01:00
parent 35ae813dc8
commit 14f953e0f8
5 changed files with 55 additions and 71 deletions

6
NEWS
View file

@ -1,3 +1,8 @@
Version 2.1.1 - Jan 20, 2012
- Handle network errors properly
- Make scantime retargeting more accurate
Version 2.1 - Jan 19, 2012 Version 2.1 - Jan 19, 2012
- Share the same work among all threads - Share the same work among all threads
@ -9,6 +14,7 @@ Version 2.0 - Jan 16, 2012
- Change default port to 9332 for Litecoin and remove default credentials - Change default port to 9332 for Litecoin and remove default credentials
- Add 'scrypt' as the default algorithm and remove other algorithms (ArtForz) - Add 'scrypt' as the default algorithm and remove other algorithms (ArtForz)
- Optimize scrypt for x86 and x86-64 - Optimize scrypt for x86 and x86-64
- Make scantime retargeting less granular (ArtForz)
- Test the whole hash instead of just looking at the high 32 bits - Test the whole hash instead of just looking at the high 32 bits
- Add configurable timeout, with a default of 180 seconds - Add configurable timeout, with a default of 180 seconds
- Add share summary output (inlikeflynn) - Add share summary output (inlikeflynn)

View file

@ -101,7 +101,7 @@ int opt_scantime = 5;
static json_t *opt_config; static json_t *opt_config;
static const bool opt_time = true; static const bool opt_time = true;
static enum sha256_algos opt_algo = ALGO_SCRYPT; static enum sha256_algos opt_algo = ALGO_SCRYPT;
int opt_n_threads; static int opt_n_threads;
static int num_processors; static int num_processors;
static char *rpc_url; static char *rpc_url;
static char *rpc_userpass; static char *rpc_userpass;
@ -292,7 +292,7 @@ static bool submit_upstream_work(CURL *curl, const struct work *work)
hexstr); hexstr);
/* issue JSON-RPC request */ /* issue JSON-RPC request */
val = json_rpc_call(curl, rpc_url, rpc_userpass, s, false, false); val = json_rpc_call(curl, rpc_url, rpc_userpass, s, false, false, NULL);
if (unlikely(!val)) { if (unlikely(!val)) {
applog(LOG_ERR, "submit_upstream_work json_rpc_call failed"); applog(LOG_ERR, "submit_upstream_work json_rpc_call failed");
goto out; goto out;
@ -312,7 +312,7 @@ static bool submit_upstream_work(CURL *curl, const struct work *work)
accepted_count, accepted_count,
accepted_count + rejected_count, accepted_count + rejected_count,
100. * accepted_count / (accepted_count + rejected_count), 100. * accepted_count / (accepted_count + rejected_count),
hashrate, 1e-3 * hashrate,
json_is_true(res) ? "(yay!!!)" : "(booooo)"); json_is_true(res) ? "(yay!!!)" : "(booooo)");
json_decref(val); json_decref(val);
@ -333,7 +333,7 @@ static bool get_upstream_work(CURL *curl, struct work *work)
bool rc; bool rc;
val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req, val = json_rpc_call(curl, rpc_url, rpc_userpass, rpc_req,
want_longpoll, false); want_longpoll, false, NULL);
if (!val) if (!val)
return false; return false;
@ -456,22 +456,6 @@ static void *workio_thread(void *userdata)
return NULL; return NULL;
} }
static void hashmeter(int thr_id, const struct timeval *diff,
unsigned long hashes_done)
{
double khashes, secs;
khashes = hashes_done / 1000.0;
secs = (double)diff->tv_sec + ((double)diff->tv_usec / 1000000.0);
thr_hashrates[thr_id] = khashes / secs;
if (!opt_quiet)
applog(LOG_INFO, "thread %d: %lu hashes, %.2f khash/s",
thr_id, hashes_done,
khashes / secs);
}
static bool get_work(struct thr_info *thr, struct work *work) static bool get_work(struct thr_info *thr, struct work *work)
{ {
struct workio_cmd *wc; struct workio_cmd *wc;
@ -535,7 +519,7 @@ static void *miner_thread(void *userdata)
{ {
struct thr_info *mythr = userdata; struct thr_info *mythr = userdata;
int thr_id = mythr->id; int thr_id = mythr->id;
uint32_t max_nonce = 0xffffff; uint32_t max_nonce;
uint32_t next_nonce; uint32_t next_nonce;
unsigned char *scratchbuf = NULL; unsigned char *scratchbuf = NULL;
@ -553,15 +537,13 @@ static void *miner_thread(void *userdata)
if (opt_algo == ALGO_SCRYPT) if (opt_algo == ALGO_SCRYPT)
{ {
scratchbuf = scrypt_buffer_alloc(); scratchbuf = scrypt_buffer_alloc();
max_nonce = 0xffff * opt_n_threads;
} }
while (1) { while (1) {
struct work work __attribute__((aligned(128))); struct work work __attribute__((aligned(128)));
unsigned long hashes_done; unsigned long hashes_done;
struct timeval tv_start, tv_end, diff; struct timeval tv_start, tv_end, diff;
int diffms; int64_t max64;
uint64_t max64;
bool rc; bool rc;
/* obtain new work from internal workio thread */ /* obtain new work from internal workio thread */
@ -579,20 +561,29 @@ static void *miner_thread(void *userdata)
} }
if (memcmp(work.data, g_work.data, 76)) { if (memcmp(work.data, g_work.data, 76)) {
memcpy(&work, &g_work, sizeof(struct work)); memcpy(&work, &g_work, sizeof(struct work));
next_nonce = thr_id; next_nonce = 0xffffffffU / opt_n_threads * thr_id;
} }
pthread_mutex_unlock(&g_work_lock); pthread_mutex_unlock(&g_work_lock);
work_restart[thr_id].restart = 0; work_restart[thr_id].restart = 0;
/* adjust max_nonce to meet target scan time */
max64 = (g_work_time + opt_scantime - time(NULL)) *
(int64_t)thr_hashrates[thr_id];
if (max64 <= 0)
max64 = 0xfffLL;
if (next_nonce + max64 > 0xfffffffeLL)
max_nonce = 0xfffffffeU;
else
max_nonce = next_nonce + max64;
hashes_done = 0; hashes_done = 0;
gettimeofday(&tv_start, NULL); gettimeofday(&tv_start, NULL);
/* scan nonces for a proof-of-work hash */ /* scan nonces for a proof-of-work hash */
switch (opt_algo) { switch (opt_algo) {
case ALGO_SCRYPT: case ALGO_SCRYPT:
rc = scanhash_scrypt(thr_id, work.data, scratchbuf, rc = scanhash_scrypt(thr_id, work.data, scratchbuf, work.target,
work.target, next_nonce + max_nonce, max_nonce, &next_nonce, &hashes_done);
&next_nonce, &hashes_done);
break; break;
default: default:
@ -603,19 +594,11 @@ static void *miner_thread(void *userdata)
/* record scanhash elapsed time */ /* record scanhash elapsed time */
gettimeofday(&tv_end, NULL); gettimeofday(&tv_end, NULL);
timeval_subtract(&diff, &tv_end, &tv_start); timeval_subtract(&diff, &tv_end, &tv_start);
thr_hashrates[thr_id] =
hashmeter(thr_id, &diff, hashes_done); hashes_done / (diff.tv_sec + 1e-6 * diff.tv_usec);
if (!opt_quiet)
/* adjust max_nonce to meet target scan time */ applog(LOG_INFO, "thread %d: %lu hashes, %.2f khash/s",
diffms = diff.tv_sec * 1000 + diff.tv_usec / 1000; thr_id, hashes_done, 1e-3 * thr_hashrates[thr_id]);
if (diffms > 0) {
max64 =
((uint64_t)hashes_done * opt_scantime * 1000) / diffms;
max64 *= opt_n_threads;
if (max64 > 0xffff0000ULL)
max64 = 0xffff0000ULL;
max_nonce = max64;
}
/* if nonce found, submit work */ /* if nonce found, submit work */
if (rc && !submit_work(mythr, &work)) if (rc && !submit_work(mythr, &work))
@ -677,9 +660,10 @@ static void *longpoll_thread(void *userdata)
while (1) { while (1) {
json_t *val; json_t *val;
int err;
val = json_rpc_call(curl, lp_url, rpc_userpass, rpc_req, val = json_rpc_call(curl, lp_url, rpc_userpass, rpc_req,
false, true); false, true, &err);
if (likely(val)) { if (likely(val)) {
failures = 0; failures = 0;
applog(LOG_INFO, "LONGPOLL detected new block"); applog(LOG_INFO, "LONGPOLL detected new block");
@ -691,10 +675,14 @@ static void *longpoll_thread(void *userdata)
restart_threads(); restart_threads();
} }
pthread_mutex_unlock(&g_work_lock); pthread_mutex_unlock(&g_work_lock);
} else { json_decref(val);
/* longpoll failed, keep trying */ } else if (err != CURLE_OPERATION_TIMEDOUT) {
pthread_mutex_lock(&g_work_lock);
g_work_time -= opt_scantime;
pthread_mutex_unlock(&g_work_lock);
restart_threads();
sleep(opt_fail_pause);
} }
json_decref(val);
} }
out: out:

View file

@ -123,7 +123,7 @@ extern bool opt_debug;
extern bool opt_protocol; extern bool opt_protocol;
extern const uint32_t sha256_init_state[]; extern const uint32_t sha256_init_state[];
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, bool, bool); const char *rpc_req, bool, bool, int *);
extern char *bin2hex(const unsigned char *p, size_t len); extern char *bin2hex(const unsigned char *p, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@ -141,7 +141,6 @@ extern int opt_scantime;
extern int opt_timeout; extern int opt_timeout;
extern bool want_longpoll; extern bool want_longpoll;
extern bool have_longpoll; extern bool have_longpoll;
extern int opt_n_threads;
struct thread_q; struct thread_q;
struct work_restart { struct work_restart {

View file

@ -520,7 +520,7 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf,
uint32_t data3[20], hash3[8]; uint32_t data3[20], hash3[8];
int throughput; int throughput;
#endif #endif
unsigned long c = 0; unsigned long first_nonce = *next_nonce;
uint32_t n = *next_nonce; uint32_t n = *next_nonce;
uint32_t Htarg = le32dec(&((const uint32_t *)ptarget)[7]); uint32_t Htarg = le32dec(&((const uint32_t *)ptarget)[7]);
int i; int i;
@ -533,24 +533,18 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf,
throughput = scrypt_best_throughput(); throughput = scrypt_best_throughput();
#endif #endif
while (1) { do {
data[19] = n; data[19] = n++;
n += opt_n_threads;
++c;
#ifdef SCRYPT_3WAY #ifdef SCRYPT_3WAY
if (throughput >= 2 && n <= max_nonce) { if (throughput >= 2 && n <= max_nonce) {
data2[19] = n; data2[19] = n++;
n += opt_n_threads;
++c;
if (throughput >= 3 && n <= max_nonce) { if (throughput >= 3 && n <= max_nonce) {
data3[19] = n; data3[19] = n++;
n += opt_n_threads;
++c;
scrypt_1024_1_1_256_sp_3way(data, data2, data3, hash, hash2, hash3, scratchbuf); scrypt_1024_1_1_256_sp_3way(data, data2, data3, hash, hash2, hash3, scratchbuf);
if (hash3[7] < Htarg || hash3[7] == Htarg && test_hash(hash3, (uint32_t *)ptarget)) { if (hash3[7] < Htarg || hash3[7] == Htarg && test_hash(hash3, (uint32_t *)ptarget)) {
be32enc(&((uint32_t *)pdata)[19], data3[19]); be32enc(&((uint32_t *)pdata)[19], data3[19]);
*next_nonce = n; *next_nonce = n;
*hashes_done = c; *hashes_done = n - first_nonce;
return true; return true;
} }
} else { } else {
@ -559,7 +553,7 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf,
if (hash2[7] < Htarg || hash2[7] == Htarg && test_hash(hash2, (uint32_t *)ptarget)) { if (hash2[7] < Htarg || hash2[7] == Htarg && test_hash(hash2, (uint32_t *)ptarget)) {
be32enc(&((uint32_t *)pdata)[19], data2[19]); be32enc(&((uint32_t *)pdata)[19], data2[19]);
*next_nonce = n; *next_nonce = n;
*hashes_done = c; *hashes_done = n - first_nonce;
return true; return true;
} }
} else { } else {
@ -568,19 +562,16 @@ int scanhash_scrypt(int thr_id, unsigned char *pdata, unsigned char *scratchbuf,
#else #else
scrypt_1024_1_1_256_sp(data, hash, scratchbuf); scrypt_1024_1_1_256_sp(data, hash, scratchbuf);
#endif #endif
if (hash[7] < Htarg || hash[7] == Htarg && test_hash(hash, (uint32_t *)ptarget)) { if (hash[7] < Htarg || hash[7] == Htarg && test_hash(hash, (uint32_t *)ptarget)) {
be32enc(&((uint32_t *)pdata)[19], data[19]); be32enc(&((uint32_t *)pdata)[19], data[19]);
*next_nonce = n; *next_nonce = n;
*hashes_done = c; *hashes_done = n - first_nonce;
return true; return true;
} }
} while (n <= max_nonce && !work_restart[thr_id].restart);
if ((n > max_nonce) || work_restart[thr_id].restart)
break;
}
*next_nonce = n; *next_nonce = n;
*hashes_done = c; *hashes_done = n - first_nonce;
return false; return false;
} }

6
util.c
View file

@ -205,7 +205,7 @@ out:
json_t *json_rpc_call(CURL *curl, const char *url, json_t *json_rpc_call(CURL *curl, const char *url,
const char *userpass, const char *rpc_req, const char *userpass, const char *rpc_req,
bool longpoll_scan, bool longpoll) bool longpoll_scan, bool longpoll, int *curl_err)
{ {
json_t *val, *err_val, *res_val; json_t *val, *err_val, *res_val;
int rc; int rc;
@ -266,11 +266,11 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
rc = curl_easy_perform(curl); rc = curl_easy_perform(curl);
if (curl_err != NULL)
*curl_err = rc;
if (rc) { if (rc) {
if (!(longpoll && rc == CURLE_OPERATION_TIMEDOUT)) if (!(longpoll && rc == CURLE_OPERATION_TIMEDOUT))
applog(LOG_ERR, "HTTP request failed: %s", curl_err_str); applog(LOG_ERR, "HTTP request failed: %s", curl_err_str);
if (longpoll && rc != CURLE_OPERATION_TIMEDOUT)
sleep(30);
goto err_out; goto err_out;
} }