diff --git a/bignum.cpp b/bignum.cpp index 1a68654..80687b0 100644 --- a/bignum.cpp +++ b/bignum.cpp @@ -74,6 +74,7 @@ extern "C" void bn_store_hash_target_ratio(uint32_t* hash, uint32_t* target, str { // only if the option is enabled (to reduce cpu usage) if (!opt_showdiff) return; + if (nonce < 0 || nonce >= MAX_NONCES) return; work->shareratio[nonce] = bn_hash_target_ratio(hash, target); work->sharediff[nonce] = work->targetdiff * work->shareratio[nonce]; @@ -88,6 +89,6 @@ extern "C" void bn_set_target_ratio(struct work* work, uint32_t* hash, int nonce // compat (only store single nonce share diff per work) extern "C" void work_set_target_ratio(struct work* work, uint32_t* hash) { - bn_store_hash_target_ratio(hash, work->target, work, 0); + bn_store_hash_target_ratio(hash, work->target, work, work->submit_nonce_id); } diff --git a/ccminer.cpp b/ccminer.cpp index 02ad780..b85fe86 100644 --- a/ccminer.cpp +++ b/ccminer.cpp @@ -94,7 +94,7 @@ bool want_stratum = true; bool have_stratum = false; bool allow_gbt = true; bool allow_mininginfo = true; -bool check_dups = false; +bool check_dups = true; //false; bool check_stratum_jobs = false; bool submit_old = false; @@ -796,18 +796,17 @@ static bool submit_upstream_work(CURL *curl, struct work *work) struct pool_infos *pool = &pools[work->pooln]; json_t *val, *res, *reason; bool stale_work = false; - int idnonce = 0; + int idnonce = work->submit_nonce_id; if (pool->type & POOL_STRATUM && stratum.rpc2) { struct work submit_work; memcpy(&submit_work, work, sizeof(struct work)); - bool sent = hashlog_already_submittted(submit_work.job_id, submit_work.nonces[0]); - if (sent) { - return true; + if (!hashlog_already_submittted(submit_work.job_id, submit_work.nonces[idnonce])) { + if (rpc2_stratum_submit(pool, &submit_work)) + hashlog_remember_submit(&submit_work, submit_work.nonces[idnonce]); + stratum.job.shares_count++; } - bool ret = rpc2_stratum_submit(pool, &submit_work); - hashlog_remember_submit(&submit_work, submit_work.nonces[0]); - return ret; + return true; } /* discard if a newer block was received */ @@ -851,7 +850,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work) if (pool->type & POOL_STRATUM) { uint32_t sent = 0; - uint32_t ntime, nonce; + uint32_t ntime, nonce = work->nonces[idnonce]; char *ntimestr, *noncestr, *xnonce2str, *nvotestr; uint16_t nvote = 0; @@ -879,7 +878,7 @@ static bool submit_upstream_work(CURL *curl, struct work *work) case ALGO_LBRY: check_dups = true; le32enc(&ntime, work->data[25]); - le32enc(&nonce, work->data[27]); + //le32enc(&nonce, work->data[27]); break; case ALGO_SIA: be32enc(&ntime, work->data[10]); @@ -930,18 +929,18 @@ static bool submit_upstream_work(CURL *curl, struct work *work) stratum.sharediff); else if (opt_debug_diff) applog(LOG_DEBUG, "share diff: %.5f (x %.1f)", - stratum.sharediff, work->shareratio); + stratum.sharediff, work->shareratio[idnonce]); if (opt_vote) { // ALGO_HEAVY ALGO_DECRED nvotestr = bin2hex((const uchar*)(&nvote), 2); sprintf(s, "{\"method\": \"mining.submit\", \"params\": [" - "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":%d}", - pool->user, work->job_id + 8, xnonce2str, ntimestr, noncestr, nvotestr, 10+idnonce); + "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":%u}", + pool->user, work->job_id + 8, xnonce2str, ntimestr, noncestr, nvotestr, stratum.job.shares_count + 10); free(nvotestr); } else { sprintf(s, "{\"method\": \"mining.submit\", \"params\": [" - "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":%d}", - pool->user, work->job_id + 8, xnonce2str, ntimestr, noncestr, 10+idnonce); + "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\"], \"id\":%u}", + pool->user, work->job_id + 8, xnonce2str, ntimestr, noncestr, stratum.job.shares_count + 10); } free(xnonce2str); free(ntimestr); @@ -953,8 +952,9 @@ static bool submit_upstream_work(CURL *curl, struct work *work) return false; } - if (check_dups) + if (check_dups || opt_showdiff) hashlog_remember_submit(work, nonce); + stratum.job.shares_count++; } else { @@ -1830,6 +1830,10 @@ static void *miner_thread(void *userdata) } } + // reset shares id counter on new job + if (strcmp(work.job_id, g_work.job_id)) + stratum.job.shares_count = 0; + if (!opt_benchmark && (g_work.height != work.height || memcmp(work.target, g_work.target, sizeof(work.target)))) { if (opt_debug) { @@ -2385,7 +2389,8 @@ static void *miner_thread(void *userdata) nonceptr[0] = UINT32_MAX; } - if (check_dups && opt_algo != ALGO_DECRED && opt_algo != ALGO_SIA) + // only required to debug purpose + if (opt_debug && check_dups && opt_algo != ALGO_DECRED && opt_algo != ALGO_SIA) hashlog_remember_scan_range(&work); /* output */ @@ -2441,6 +2446,7 @@ static void *miner_thread(void *userdata) // second nonce found, submit too (on pool only!) if (rc > 1 && work.nonces[1]) { + work.submit_nonce_id = 1; nonceptr[0] = work.nonces[1]; if (opt_algo == ALGO_ZR5) { // todo: use + 4..6 index for pok to allow multiple nonces @@ -2620,7 +2626,8 @@ static bool stratum_handle_response(char *buf) json_t *val, *err_val, *res_val, *id_val; json_error_t err; struct timeval tv_answer, diff; - int num = 0; + int num = 0, job_nonce_id = 0; + double sharediff = stratum.sharediff; bool ret = false; val = JSON_LOADS(buf, &err); @@ -2641,8 +2648,10 @@ static bool stratum_handle_response(char *buf) if (num < 4) goto out; - // todo: use request id to index nonce diff data - // num = num % 10; + // We dont have the work anymore, so use the hashlog to get the right sharediff for multiple nonces + job_nonce_id = num - 10; + if (opt_showdiff && check_dups) + sharediff = hashlog_get_sharediff(g_work.job_id, job_nonce_id, sharediff); gettimeofday(&tv_answer, NULL); timeval_subtract(&diff, &tv_answer, &stratum.tv_submit); @@ -2650,21 +2659,17 @@ static bool stratum_handle_response(char *buf) stratum.answer_msec = (1000 * diff.tv_sec) + (uint32_t) (0.001 * diff.tv_usec); if (stratum.rpc2) { - const char* reject_reason = err_val ? json_string_value(json_object_get(err_val, "message")) : NULL; - // {"id":4,"jsonrpc":"2.0","error":null,"result":{"status":"OK"}} - share_result(json_is_null(err_val), stratum.pooln, stratum.sharediff, reject_reason); + // {"id":10,"jsonrpc":"2.0","error":null,"result":{"status":"OK"}} + share_result(json_is_null(err_val), stratum.pooln, sharediff, reject_reason); if (reject_reason) { g_work_time = 0; restart_threads(); } - } else { - if (!res_val) goto out; - - share_result(json_is_true(res_val), stratum.pooln, stratum.sharediff, + share_result(json_is_true(res_val), stratum.pooln, sharediff, err_val ? json_string_value(json_array_get(err_val, 1)) : NULL); } @@ -2765,7 +2770,7 @@ wait_stratum_url: stratum.job.height); } restart_threads(); - if (check_dups) + if (check_dups || opt_showdiff) hashlog_purge_old(); stats_purge_old(); } else if (opt_debug && !opt_quiet) { diff --git a/crypto/wildkeccak.cu b/crypto/wildkeccak.cu index fae66ae..3598d5f 100644 --- a/crypto/wildkeccak.cu +++ b/crypto/wildkeccak.cu @@ -222,16 +222,12 @@ static bool init[MAX_GPUS] = { 0 }; extern "C" int scanhash_wildkeccak(int thr_id, struct work* work, uint32_t max_nonce, unsigned long *hashes_done) { - //uint32_t _ALIGN(64) endiandata[20]; uint32_t *ptarget = work->target; uint32_t throughput = 0; uint64_t n, nonce, first; uint8_t *pdata = (uint8_t*) work->data; memcpy(&first, &pdata[1], 8); - //memcpy(&n, &pdata[1], 4);; n = nonce = first; -// pdata[5] = thr_id; -// memcpy(&nonce, &pdata[1], 8); if (!scratchpad_size || !h_scratchpad[thr_id]) { if (h_scratchpad[thr_id]) @@ -245,7 +241,8 @@ extern "C" int scanhash_wildkeccak(int thr_id, struct work* work, uint32_t max_n if (device_config[thr_id]) { sscanf(device_config[thr_id], "%ux%u", &WK_CUDABlocks, &WK_CUDAThreads); - gpulog(LOG_INFO, thr_id, "Using %u x %u threads kernel launch config", WK_CUDABlocks, WK_CUDAThreads); + gpulog(LOG_INFO, thr_id, "Using %u x %u kernel launch config, %u threads", + WK_CUDABlocks, WK_CUDAThreads, throughput); } else { throughput = cuda_default_throughput(thr_id, WK_CUDABlocks*WK_CUDAThreads); gpulog(LOG_INFO, thr_id, "Intensity set to %g, %u cuda threads", throughput2intensity(throughput), throughput); @@ -319,6 +316,7 @@ extern "C" int scanhash_wildkeccak(int thr_id, struct work* work, uint32_t max_n if (n + throughput > max_nonce) { *hashes_done = (unsigned long) (max_nonce - first); } + work->valid_nonces = 1; return 1; } } diff --git a/crypto/xmr-rpc.cpp b/crypto/xmr-rpc.cpp index 0935000..94f5696 100644 --- a/crypto/xmr-rpc.cpp +++ b/crypto/xmr-rpc.cpp @@ -341,7 +341,7 @@ static bool addendum_decode(const json_t *addm) current_scratchpad_hi = hi; if (!opt_quiet && !opt_quiet_start) - applog(LOG_BLUE, "ADDENDUM APPLIED: %lld --> %lld", old_height, current_scratchpad_hi.height); + applog(LOG_BLUE, "ADDENDUM APPLIED: Block %lld", (long long) current_scratchpad_hi.height); return true; err_out: @@ -440,6 +440,8 @@ bool rpc2_job_decode(const json_t *job, struct work *work) } if (rpc2_job_id) { + // reset job share counter + if (strcmp(rpc2_job_id, job_id)) stratum.job.shares_count = 0; free(rpc2_job_id); } rpc2_job_id = strdup(job_id); @@ -478,8 +480,7 @@ bool rpc2_stratum_job(struct stratum_ctx *sctx, json_t *id, json_t *params) pthread_mutex_lock(&rpc2_work_lock); ret = rpc2_job_decode(params, &rpc2_work); // update miner threads work - if (ret) rpc2_stratum_gen_work(sctx, &g_work); - //memcpy(&g_work, &rpc2_work, sizeof(struct work)); + ret = ret && rpc2_stratum_gen_work(sctx, &g_work); restart_threads(); pthread_mutex_unlock(&rpc2_work_lock); return ret; @@ -510,32 +511,35 @@ bool rpc2_stratum_gen_work(struct stratum_ctx *sctx, struct work *work) } #define JSON_SUBMIT_BUF_LEN 512 +// called by submit_upstream_work() bool rpc2_stratum_submit(struct pool_infos *pool, struct work *work) { char _ALIGN(64) s[JSON_SUBMIT_BUF_LEN]; uint8_t _ALIGN(64) hash[32]; uint8_t _ALIGN(64) data[88]; char *noncestr, *hashhex; + int idnonce = work->submit_nonce_id; memcpy(&data[0], work->data, 88); if (opt_algo == ALGO_WILDKECCAK) { + // 64 bits nonce memcpy(&data[1], work->nonces, 8); // pass if the previous hash is not the current previous hash if(!submit_old && memcmp(&work->data[3], &g_work.data[3], 28)) { - if (opt_debug) applog(LOG_DEBUG, "stale work detected", work->sharediff, work->targetdiff); + if (opt_debug) applog(LOG_DEBUG, "stale work detected"); pool->stales_count++; - return true; + return false; } noncestr = bin2hex((unsigned char*) &data[1], 8); - memcpy(&last_found_nonce, work->nonces, 8); // "nonce":"5794ec8000000000" => 0x0000000080ec9457 + // "nonce":"5794ec8000000000" => 0x0000000080ec9457 + memcpy(&last_found_nonce, work->nonces, 8); wildkeccak_hash(hash, data, NULL, 0); work_set_target_ratio(work, (uint32_t*) hash); } else if (opt_algo == ALGO_CRYPTOLIGHT) { - uint32_t nonce; - memcpy(&nonce, &data[39], 4); + uint32_t nonce = work->nonces[idnonce]; noncestr = bin2hex((unsigned char*) &nonce, 4); last_found_nonce = nonce; cryptolight_hash(hash, data, 76); @@ -543,34 +547,33 @@ bool rpc2_stratum_submit(struct pool_infos *pool, struct work *work) } else if (opt_algo == ALGO_CRYPTONIGHT) { - uint32_t nonce; - memcpy(&nonce, &data[39], 4); + uint32_t nonce = work->nonces[idnonce]; noncestr = bin2hex((unsigned char*) &nonce, 4); last_found_nonce = nonce; cryptonight_hash(hash, data, 76); work_set_target_ratio(work, (uint32_t*) hash); } - //applog(LOG_DEBUG, "submit diff %g > %g", work->sharediff, work->targetdiff); - //applog_hex(data, 81); - //applog_hex(hash, 32); if (hash[31] != 0) - return true; // prevent bad hashes + return false; // prevent bad hashes hashhex = bin2hex((unsigned char*)hash, 32); snprintf(s, sizeof(s), "{\"method\":\"submit\",\"params\":" - "{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}, \"id\":4}", - rpc2_id, work->job_id, noncestr, hashhex); + "{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"}, \"id\":%u}", + rpc2_id, work->job_id, noncestr, hashhex, stratum.job.shares_count + 10); free(hashhex); free(noncestr); + gettimeofday(&stratum.tv_submit, NULL); + if(!stratum_send_line(&stratum, s)) { - applog(LOG_ERR, "submit_upstream_work stratum_send_line failed"); + applog(LOG_ERR, "%s stratum_send_line failed", __func__); return false; } - stratum.sharediff = target_to_diff_rpc2((uint32_t*)hash); + //stratum.sharediff = target_to_diff_rpc2((uint32_t*)hash); + stratum.sharediff = work->sharediff[idnonce]; return true; } @@ -892,14 +895,14 @@ void GetScratchpad() pscratchpad_buff = (uint64_t*) mmap(0, sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, 0, 0); if(pscratchpad_buff == MAP_FAILED) { - applog(LOG_INFO, "hugetlb not available"); + if(opt_debug) applog(LOG_DEBUG, "hugetlb not available"); pscratchpad_buff = (uint64_t*) malloc(sz); if(!pscratchpad_buff) { applog(LOG_ERR, "Scratchpad allocation failed"); exit(1); } } else { - applog(LOG_INFO, "using hugetlb"); + if(opt_debug) applog(LOG_DEBUG, "using hugetlb"); } madvise(pscratchpad_buff, sz, MADV_RANDOM | MADV_WILLNEED | MADV_HUGEPAGE); mlock(pscratchpad_buff, sz); @@ -1187,9 +1190,9 @@ out: bool rpc2_stratum_request_job(struct stratum_ctx *sctx) { json_t *val = NULL, *res_val, *err_val; - char *sret; json_error_t err; bool ret = false; + char *sret; char *s = (char*) calloc(1, 10*2048); if (!s) { applog(LOG_ERR, "Stratum job OOM!"); diff --git a/hashlog.cpp b/hashlog.cpp index 876ce3a..ce13191 100644 --- a/hashlog.cpp +++ b/hashlog.cpp @@ -1,10 +1,10 @@ /** * Hash log of submitted job nonces - * Prevent duplicate shares + * Prevent duplicate shares and remember shares diff * * (to be merged later with stats) * - * tpruvot@github 2014 + * tpruvot@github 2014 - 2017 */ #include #include @@ -20,7 +20,10 @@ struct hashlog_data { uint8_t npool; uint8_t pool_type; + uint8_t nonce_id; + uint8_t job_nonce_id; uint32_t height; + double sharediff; uint32_t njobid; uint32_t nonce; uint32_t scanned_from; @@ -36,6 +39,8 @@ static std::map tlastshares; #define LOG_PURGE_TIMEOUT 5*60 +extern struct stratum_ctx stratum; + /** * str hex to uint32 */ @@ -74,13 +79,16 @@ void hashlog_remember_submit(struct work* work, uint32_t nonce) hashlog_data data; memset(&data, 0, sizeof(data)); + data.nonce_id = work->submit_nonce_id; data.scanned_from = work->scanned_from; - data.scanned_to = nonce; + data.scanned_to = work->scanned_to; + data.sharediff = work->sharediff[data.nonce_id]; data.height = work->height; data.njobid = (uint32_t) njobid; data.tm_add = data.tm_upd = data.tm_sent = (uint32_t) time(NULL); data.npool = (uint8_t) cur_pooln; data.pool_type = pools[cur_pooln].type; + data.job_nonce_id = (uint8_t) stratum.job.shares_count; tlastshares[key] = data; } @@ -162,18 +170,44 @@ uint64_t hashlog_get_scan_range(char* jobid) uint32_t hashlog_get_last_sent(char* jobid) { uint32_t nonce = 0; - uint64_t njobid = hextouint(jobid); + uint64_t njobid = jobid ? hextouint(jobid) : UINT32_MAX; uint64_t keypfx = (njobid << 32); - std::map::iterator i = tlastshares.begin(); - while (i != tlastshares.end()) { - if ((keypfx & i->first) == keypfx && i->second.tm_sent > 0) { + std::map::reverse_iterator i = tlastshares.rbegin(); + while (i != tlastshares.rend()) { + if ((keypfx & i->first) == keypfx && i->second.tm_sent) { nonce = LO_DWORD(i->first); + break; } i++; } return nonce; } +/** + * To display correcly second nonce(s) share diff (on pool accept) + */ +double hashlog_get_sharediff(char* jobid, int job_nonceid, double defvalue) +{ + double diff = defvalue; + const uint64_t njobid = jobid ? hextouint(jobid) : UINT32_MAX; + const uint64_t keypfx = (njobid << 32); + const uint64_t keymsk = (0xffffffffULL << 32); + + std::map::reverse_iterator it = tlastshares.rbegin(); + while (it != tlastshares.rend()) { + if ((keymsk & it->first) == keypfx) { + if ((int) it->second.job_nonce_id == job_nonceid && it->second.tm_sent) { + diff = it->second.sharediff; + // applog(LOG_BLUE, "sharediff nonce %x:%d (%d) match %g", + // njobid, (int) it->second.nonce_id, job_nonceid, diff); + break; + } + } + ++it; + } + return diff; +} + /** * Export data for api calls */ diff --git a/miner.h b/miner.h index 5a5bb08..0ff92f3 100644 --- a/miner.h +++ b/miner.h @@ -421,9 +421,12 @@ struct stats_data { struct hashlog_data { uint8_t npool; uint8_t pool_type; - uint16_t align; + uint8_t nonce_id; + uint8_t job_nonce_id; uint32_t height; + double sharediff; + uint32_t njobid; uint32_t nonce; uint32_t scanned_from; @@ -601,6 +604,7 @@ struct stratum_job { bool clean; unsigned char nreward[2]; uint32_t height; + uint32_t shares_count; double diff; }; @@ -656,6 +660,8 @@ struct work { uint8_t pooln; uint8_t valid_nonces; + uint8_t submit_nonce_id; + uint8_t job_nonce_id; uint32_t nonces[MAX_NONCES]; double sharediff[MAX_NONCES]; @@ -754,6 +760,7 @@ bool rpc2_stratum_authorize(struct stratum_ctx *sctx, const char *user, const ch void hashlog_remember_submit(struct work* work, uint32_t nonce); void hashlog_remember_scan_range(struct work* work); +double hashlog_get_sharediff(char* jobid, int idnonce, double defvalue); uint32_t hashlog_already_submittted(char* jobid, uint32_t nounce); uint32_t hashlog_get_last_sent(char* jobid); uint64_t hashlog_get_scan_range(char* jobid);