diff --git a/src/pool.c b/src/pool.c index d52e20f..ac701fa 100644 --- a/src/pool.c +++ b/src/pool.c @@ -1537,6 +1537,53 @@ rpc_on_block_template(const char* data, rpc_callback_t *callback) json_object_put(root); } +static int +startup_scan_round_shares() +{ + int rc; + char *err; + MDB_txn *txn; + MDB_cursor *cursor; + + if ((rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)) != 0) + { + err = mdb_strerror(rc); + log_error("%s", err); + return rc; + } + if ((rc = mdb_cursor_open(txn, db_shares, &cursor)) != 0) + { + err = mdb_strerror(rc); + log_error("%s", err); + mdb_txn_abort(txn); + return rc; + } + MDB_cursor_op op = MDB_LAST; + while (1) + { + MDB_val key; + MDB_val val; + rc = mdb_cursor_get(cursor, &key, &val, op); + if (rc != 0 && rc != MDB_NOTFOUND) + { + err = mdb_strerror(rc); + log_error("%s", err); + break; + } + if (rc == MDB_NOTFOUND) + break; + op = MDB_PREV; + share_t *share = (share_t*)val.mv_data; + if (share->timestamp > pool_stats.last_block_found) + pool_stats.round_hashes += share->difficulty; + else + break; + } + mdb_cursor_close(cursor); + mdb_txn_abort(txn); + return 0; +} + static int startup_pauout(uint64_t height) { @@ -1668,6 +1715,7 @@ rpc_on_last_block_header(const char* data, rpc_callback_t *callback) block_t *block = bstack_push(bsh, NULL); response_to_block(block_header, block); startup_pauout(block->height); + startup_scan_round_shares(); need_new_template = true; } @@ -1728,6 +1776,7 @@ rpc_on_block_submitted(const char* data, rpc_callback_t *callback) pool_stats.pool_blocks_found++; block_t *b = (block_t*)callback->data; pool_stats.last_block_found = b->timestamp; + pool_stats.round_hashes = 0; log_info("Block submitted at height: %"PRIu64, b->height); int rc = store_block(b->height, b); if (rc != 0) @@ -2473,6 +2522,7 @@ client_on_submit(json_object *message, client_t *client) share.difficulty = job->target; strncpy(share.address, client->address, sizeof(share.address)); share.timestamp = now; + pool_stats.round_hashes += share.difficulty; log_debug("Storing share with difficulty: %"PRIu64, share.difficulty); int rc = store_share(share.height, &share); if (rc != 0) diff --git a/src/webui-embed.html b/src/webui-embed.html index 633d5fe..8d8b808 100644 --- a/src/webui-embed.html +++ b/src/webui-embed.html @@ -52,6 +52,8 @@ Blocks found: Last block found: Last template: + Round HR: + Round hashes: Payment threshold: Pool fee: Pool port: @@ -93,16 +95,42 @@ } } - function format_hashrate(hr) + function format_hashes(h) { - if (hr < 1000) - return parseInt(hr) + " H/s"; - else if (hr < 1000000) - return parseFloat(hr/1000).toFixed(2) + " KH/s"; - else if (hr < 1000000000) - return parseFloat(hr/1000000).toFixed(2) + " MH/s"; + if (h < 1e-12) + return "0 H"; + else if (h < 1e-9) + return parseFloat(h*1e+12).toFixed(2) + " pH"; + else if (h < 1e-6) + return parseFloat(h*1e+9).toFixed(2) + " nH"; + else if (h < 1e-3) + return parseFloat(h*1e+6).toFixed(2) + " μH"; + else if (h < 1) + return parseFloat(h*1e+3).toFixed(2) + " mH"; + else if (h < 1e+3) + return parseInt(h) + " H"; + else if (h < 1e+6) + return parseFloat(h*1e-3).toFixed(2) + " KH"; + else if (h < 1e+9) + return parseFloat(h*1e-6).toFixed(2) + " MH"; else - return parseFloat(hr/1000000000).toFixed(2) + " GH/s"; + return parseFloat(h*1e-9).toFixed(2) + " GH"; + } + + function format_hashrate(h) + { + return format_hashes(h) + "/s"; + } + + function format_round_hashrate(round_hashes, last_block_found) + { + var now = new Date().getTime() / 1000; + var diff = now - last_block_found; + if (last_block_found == 0) + return 0; + if (diff <= 0) + return 0; + return format_hashrate(round_hashes / diff) } var wf = document.querySelector(".address"); @@ -124,6 +152,12 @@ el.innerHTML = (stats[e]*100) + "%"; else if (e == "allow_self_select") el.innerHTML = stats[e] == 1 ? "Yes" : "No"; + else if (e == "round_hashes") + { + el.innerHTML = (stats[e]*100/stats["network_difficulty"]).toFixed(2) + "%" + el.innerHTML += " (" + format_hashes(stats[e]) + " / " + format_hashes(stats["network_difficulty"]) + ")"; + document.querySelector("#round_hashrate").innerHTML = format_round_hashrate(stats["round_hashes"], stats["last_block_found"]); + } else if (e == "pool_ssl_port") { el.closest("tr").style = "display: " + diff --git a/src/webui.c b/src/webui.c index c70fcd9..cb89e3c 100644 --- a/src/webui.c +++ b/src/webui.c @@ -68,10 +68,12 @@ send_json_stats(struct evhttp_request *req, void *arg) struct evkeyvalq *hdrs_out = NULL; uint64_t ph = context->pool_stats->pool_hashrate; uint64_t nh = context->pool_stats->network_hashrate; + uint64_t nd = context->pool_stats->network_difficulty; uint64_t height = context->pool_stats->network_height; uint64_t ltf = context->pool_stats->last_template_fetched; uint64_t lbf = context->pool_stats->last_block_found; uint32_t pbf = context->pool_stats->pool_blocks_found; + uint64_t rh = context->pool_stats->round_hashes; unsigned ss = context->allow_self_select; uint64_t mh = 0; double mb = 0.0; @@ -92,7 +94,9 @@ send_json_stats(struct evhttp_request *req, void *arg) evbuffer_add_printf(buf, "{" "\"pool_hashrate\":%"PRIu64"," + "\"round_hashes\":%"PRIu64"," "\"network_hashrate\":%"PRIu64"," + "\"network_difficulty\":%"PRIu64"," "\"network_height\":%"PRIu64"," "\"last_template_fetched\":%"PRIu64"," "\"last_block_found\":%"PRIu64"," @@ -105,7 +109,7 @@ send_json_stats(struct evhttp_request *req, void *arg) "\"connected_miners\":%d," "\"miner_hashrate\":%"PRIu64"," "\"miner_balance\":%.8f" - "}", ph, nh, height, ltf, lbf, pbf, + "}", ph, rh, nh, nd, height, ltf, lbf, pbf, context->payment_threshold, context->pool_fee, context->pool_port, context->pool_ssl_port, ss, context->pool_stats->connected_miners, diff --git a/src/webui.h b/src/webui.h index f76ff92..1ec1d7b 100644 --- a/src/webui.h +++ b/src/webui.h @@ -42,6 +42,7 @@ typedef struct pool_stats_t uint64_t network_height; uint32_t connected_miners; uint64_t pool_hashrate; + uint64_t round_hashes; uint32_t pool_blocks_found; time_t last_block_found; time_t last_template_fetched;