From 49a85a68560895837bb3cf77908bf2b8956f4a33 Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 8 Sep 2014 05:34:44 +1000 Subject: [PATCH] ckdb/php - add per worker and per block stats --- pool/page_blocks.php | 82 ++++++++ pool/page_workers.php | 24 ++- sql/ckdb.sql | 15 +- sql/v0.8-v0.9.sql | 46 ++++ src/ckdb.c | 474 +++++++++++++++++++++++++++++++----------- 5 files changed, 512 insertions(+), 129 deletions(-) create mode 100644 sql/v0.8-v0.9.sql diff --git a/pool/page_blocks.php b/pool/page_blocks.php index b37ba449..4fda69df 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -1,5 +1,43 @@ 255) + $grn = 255; + + if ($grn > 100) + $fg = '#00f'; + else + $fg = '#fff'; + $bg = sprintf("#00%02x00", $grn); + } + + if ($pct > 100) + { + $red = (log10(pow($pct,4.0)) - 8.0) / 3.0 * 255; + if ($red < 0) + $red = 0; + if ($red > 255) + $red = 255; + + $fg = '#fff'; + $bg = sprintf("#%02x0000", $red); + } + + return array($fg, $bg); +} +# function doblocks($data, $user) { $blink = ' 0) + { + $pct = 100.0 * $diffacc / $netdiff; + list($fg, $bg) = pctcolour($pct); + $bpct = "".number_format($pct, 2).'%'; + $bg = " bgcolor=$bg"; + $nettot += $netdiff; + if ($stat != 'Orphan') + $blktot += $diffacc; + } + else + { + $bg = ''; + $bpct = '?'; + } + $pg .= ""; $pg .= "$hifld"; $pg .= "".$ans['workername:'.$i].''; $pg .= "".btcfmt($ans['reward:'.$i]).''; $pg .= "".gmdate('Y-m-d H:i:s+00', $ans['firstcreatedate:'.$i]).''; $pg .= "".$stat.''; + $pg .= "".$acc.''; + $pg .= "".$bpct.''; $pg .= "\n"; } } + if ($nettot > 0) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $pct = 100.0 * $blktot / $nettot; + list($fg, $bg) = pctcolour($pct); + $bpct = "".number_format($pct, 2).'%'; + $bg = " bgcolor=$bg"; + + $pg .= ""; + $pg .= ""; + $pg .= "".$bpct.''; + $pg .= "\n"; + } $pg .= "\n"; return $pg; diff --git a/pool/page_workers.php b/pool/page_workers.php index 023e6e9c..9bdffd84 100644 --- a/pool/page_workers.php +++ b/pool/page_workers.php @@ -14,11 +14,15 @@ function doworker($data, $user) // $pg .= "Idle Notification Time"; $pg .= "Work Diff"; $pg .= "Last Share"; + $pg .= "Shares"; + $pg .= "Diff"; + $pg .= "Invalid"; $pg .= "Hash Rate"; $pg .= "\n"; + $thr = 0; + $i = 0; if ($ans['STATUS'] == 'ok') { - $thr = 0; $count = $ans['rows']; for ($i = 0; $i < $count; $i++) { @@ -81,6 +85,20 @@ function doworker($data, $user) } } $pg .= "$lstdes"; + + $shareacc = number_format($ans['w_shareacc:'.$i], 0); + $diffacc = number_format($ans['w_diffacc:'.$i], 0); + $pg .= "$shareacc"; + $pg .= "$diffacc"; + + $dtot = $ans['w_diffacc:'.$i] + $ans['w_diffinv:'.$i]; + if ($dtot > 0) + $rej = number_format(100.0 * $ans['w_diffinv:'.$i] / $dtot, 3); + else + $rej = '0'; + + $pg .= "$rej%"; + if ($ans['w_elapsed:'.$i] > 3600) $uhr = $ans['w_hashrate1hr:'.$i]; else @@ -102,6 +120,7 @@ function doworker($data, $user) } } $pg .= "$uhr"; + $pg .= "\n"; } } @@ -119,7 +138,8 @@ function doworker($data, $user) $row = 'even'; else $row = 'odd'; - $pg .= "$thr\n"; + $pg .= ""; + $pg .= "$thr\n"; $pg .= "\n"; return $pg; diff --git a/sql/ckdb.sql b/sql/ckdb.sql index 62e85614..9d509506 100644 --- a/sql/ckdb.sql +++ b/sql/ckdb.sql @@ -240,9 +240,8 @@ CREATE TABLE workmarkers ( -- range of workinfo for share accounting createcode character varying(128) DEFAULT ''::character varying NOT NULL, createinet character varying(128) DEFAULT ''::character varying NOT NULL, expirydate timestamp with time zone DEFAULT '6666-06-06 06:06:06+00', - PRIMARY KEY (workinfoidstart) + PRIMARY KEY (markerid) ); -CREATE UNIQUE INDEX workmarkersid ON workmarkers USING btree (markerid); CREATE TABLE markersummary ( -- sum of sharesummary for a workinfo range @@ -276,8 +275,6 @@ CREATE TABLE markersummary ( -- sum of sharesummary for a workinfo range ); --- shares will be a flat file only --- so this needs all info from shares CREATE TABLE blocks ( height integer not NULL, blockhash character varying(256) NOT NULL, @@ -291,10 +288,11 @@ CREATE TABLE blocks ( reward bigint NOT NULL, -- satoshis confirmed char DEFAULT '' NOT NULL, diffacc float DEFAULT 0 NOT NULL, - differr float DEFAULT 0 NOT NULL, - sharecount bigint DEFAULT 0 NOT NULL, - errorcount bigint DEFAULT 0 NOT NULL, + diffinv float DEFAULT 0 NOT NULL, + shareacc float DEFAULT 0 NOT NULL, + shareinv float DEFAULT 0 NOT NULL, elapsed bigint DEFAULT 0 NOT NULL, + statsconfirmed char DEFAULT 'N' NOT NULL, createdate timestamp with time zone NOT NULL, createby character varying(64) DEFAULT ''::character varying NOT NULL, createcode character varying(128) DEFAULT ''::character varying NOT NULL, @@ -306,7 +304,6 @@ CREATE TABLE blocks ( -- calculation for the given block - orphans will be here also (not deleted later) -- rules for orphans/next block will be pool dependent --- normally pay due would be related to sum of one height + for all blockhash CREATE TABLE miningpayouts ( miningpayoutid bigint NOT NULL, -- unique per record userid bigint NOT NULL, @@ -397,4 +394,4 @@ CREATE TABLE version ( PRIMARY KEY (vlock) ); -insert into version (vlock,version) values (1,'0.8'); +insert into version (vlock,version) values (1,'0.9'); diff --git a/sql/v0.8-v0.9.sql b/sql/v0.8-v0.9.sql new file mode 100644 index 00000000..f0aeddeb --- /dev/null +++ b/sql/v0.8-v0.9.sql @@ -0,0 +1,46 @@ +SET SESSION AUTHORIZATION 'postgres'; + +BEGIN transaction; + +DO $$ +DECLARE ver TEXT; +BEGIN + + UPDATE version set version='0.9' where vlock=1 and version='0.8'; + + IF found THEN + RETURN; + END IF; + + SELECT version into ver from version + WHERE vlock=1; + + RAISE EXCEPTION 'Wrong DB version - expect "0.8" - found "%"', ver; + +END $$; + +DROP TABLE IF EXISTS workmarkers; + +CREATE TABLE workmarkers ( + markerid bigint NOT NULL, + workinfoidend bigint NOT NULL, + workinfoidstart bigint NOT NULL, + description character varying(256) DEFAULT ''::character varying NOT NULL, + createdate timestamp with time zone NOT NULL, + createby character varying(64) DEFAULT ''::character varying NOT NULL, + createcode character varying(128) DEFAULT ''::character varying NOT NULL, + createinet character varying(128) DEFAULT ''::character varying NOT NULL, + expirydate timestamp with time zone DEFAULT '6666-06-06 06:06:06+00', + PRIMARY KEY (markerid) +); + +ALTER TABLE ONLY blocks + DROP COLUMN differr, + DROP COLUMN sharecount, + DROP COLUMN errorcount, + ADD COLUMN diffinv float DEFAULT 0 NOT NULL, + ADD COLUMN shareacc float DEFAULT 0 NOT NULL, + ADD COLUMN shareinv float DEFAULT 0 NOT NULL, + ADD COLUMN statsconfirmed char DEFAULT 'N' NOT NULL; + +END transaction; diff --git a/src/ckdb.c b/src/ckdb.c index c4e3d43a..1a46b3e0 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -46,8 +46,8 @@ */ #define DB_VLOCK "1" -#define DB_VERSION "0.8" -#define CKDB_VERSION DB_VERSION"-0.240" +#define DB_VERSION "0.9" +#define CKDB_VERSION DB_VERSION"-0.250" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -170,11 +170,9 @@ static char *restorefrom; * DB+RAM blocks: resolved by workinfo - any unsaved blocks (if any) * will be after the last DB workinfo * DB+RAM accountbalance (TODO): resolved by shares/workinfo/blocks - * RAM workerstatus: last_auth, last_share, last_stats all handled by - * DB load up to whatever the CCL reload point is, and then - * corrected with the CCL reload - * last_idle will be the last idle userstats in the CCL load or 0 - * Code currently doesn't use last_idle, so for now this is OK + * RAM workerstatus: all except last_idle are set at the end of the + * CCL reload + * Code currently doesn't use last_idle * * idcontrol: only userid reuse is critical and the user is added * immeditately to the DB before replying to the add message @@ -234,13 +232,15 @@ static LOADSTATUS dbstatus; typedef struct poolstatus { int64_t workinfoid; // Last block double diffacc; - double diffinv; - double best_sdiff; // TODO + double diffinv; // Non-acc + double shareacc; + double shareinv; // Non-acc + double best_sdiff; // TODO (maybe) } POOLSTATUS; static POOLSTATUS pool; /* TODO: when we know about orphans, the count reset to zero * will need to be undone - i.e. recalculate this data from - * the memory tables */ + * the memory tables - maybe ... */ // size limit on the command string #define CMD_SIZ 31 @@ -282,7 +282,7 @@ static char *safe_text(char *txt) char *ret, *buf; if (!txt) { - buf = strdup("(null)"); + buf = strdup("(Null)"); if (!buf) quithere(1, "malloc OOM"); return buf; @@ -1274,6 +1274,12 @@ typedef struct blocks { char nonce[TXT_SML+1]; int64_t reward; char confirmed[TXT_FLAG+1]; + double diffacc; + double diffinv; + double shareacc; + double shareinv; + int64_t elapsed; + char statsconfirmed[TXT_FLAG+1]; HISTORYDATECONTROLFIELDS; } BLOCKS; @@ -2310,13 +2316,29 @@ static K_ITEM *get_workerstatus(int64_t userid, char *workername) return find; } -static K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, bool create) +/* Worker loading/creation calls this with create = true + * All others with create = false since the workerstatus should exist + * Failure is a code bug and a reported error, but handled anyway + * This has 2 sets of file/func/line to allow 2 levels of traceback + */ +static K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, + bool create, const char *file2, + const char *func2, const int line2, + WHERE_FFL_ARGS) { WORKERSTATUS *row; K_ITEM *item; item = get_workerstatus(userid, workername); - if (!item && create) { + if (!item) { + if (!create) { + LOGEMERG("%s(): Missing workerstatus %"PRId64"/%s" + WHERE_FFL WHERE_FFL, + __func__, userid, workername, + file2, func2, line2, WHERE_FFL_PASS); + return NULL; + } + K_WLOCK(workerstatus_free); item = k_unlink_head(workerstatus_free); @@ -2333,15 +2355,103 @@ static K_ITEM *_find_create_workerstatus(int64_t userid, char *workername, bool return item; } -#define find_create_workerstatus(_u, _w) _find_create_workerstatus(_u, _w, true) -#define find_workerstatus(_u, _w) _find_create_workerstatus(_u, _w, false) +#define find_create_workerstatus(_u, _w, _file, _func, _line) \ + _find_create_workerstatus(_u, _w, true, _file, _func, _line, WHERE_FFL_HERE) +#define find_workerstatus(_u, _w, _file, _func, _line) \ + _find_create_workerstatus(_u, _w, false, _file, _func, _line, WHERE_FFL_HERE) static cmp_t cmp_userstats_workerstatus(K_ITEM *a, K_ITEM *b); static cmp_t cmp_sharesummary(K_ITEM *a, K_ITEM *b); +static void zero_on_new_block() +{ + WORKERSTATUS *workerstatus; + K_TREE_CTX ctx[1]; + K_ITEM *ws_item; + + K_WLOCK(workerstatus_free); + pool.diffacc = pool.diffinv = pool.shareacc = + pool.shareinv = pool.best_sdiff = 0; + ws_item = first_in_ktree(workerstatus_root, ctx); + while (ws_item) { + DATA_WORKERSTATUS(workerstatus, ws_item); + workerstatus->diffacc = workerstatus->diffinv = + workerstatus->shareacc = workerstatus->shareinv = 0.0; + ws_item = next_in_ktree(ctx); + } + K_WUNLOCK(workerstatus_free); + +} + +/* Currently only used at the end of the startup + * Will need to add locking if it's used, later, after startup completes */ +static void set_block_share_counters() +{ + K_TREE_CTX ctx[1]; + K_ITEM *ss_item, ss_look, *ws_item; + WORKERSTATUS *workerstatus; + SHARESUMMARY *sharesummary, looksharesummary; + + INIT_SHARESUMMARY(&ss_look); + + zero_on_new_block(); + + ws_item = NULL; + /* From the end backwards so we can skip the workinfoid's we don't + * want by jumping back to just before the current worker when the + * workinfoid goes below the limit */ + ss_item = last_in_ktree(sharesummary_root, ctx); + while (ss_item) { + DATA_SHARESUMMARY(sharesummary, ss_item); + if (sharesummary->workinfoid < pool.workinfoid) { + // Skip back to the next worker + looksharesummary.userid = sharesummary->userid; + STRNCPY(looksharesummary.workername, + sharesummary->workername); + looksharesummary.workinfoid = -1; + ss_look.data = (void *)(&looksharesummary); + ss_item = find_before_in_ktree(sharesummary_root, &ss_look, + cmp_sharesummary, ctx); + continue; + } + + /* Check for user/workername change for new workerstatus + * The tree has user/workername grouped together in order + * so this will only be once per user/workername */ + if (!ws_item || + sharesummary->userid != workerstatus->userid || + strcmp(sharesummary->workername, workerstatus->workername)) { + /* This is to trigger a console error if it is missing + * since it should always exist + * However, it is simplest to simply create it + * and keep going */ + ws_item = find_workerstatus(sharesummary->userid, + sharesummary->workername, + __FILE__, __func__, __LINE__); + if (!ws_item) { + ws_item = find_create_workerstatus(sharesummary->userid, + sharesummary->workername, + __FILE__, __func__, __LINE__); + } + DATA_WORKERSTATUS(workerstatus, ws_item); + } + + pool.diffacc += sharesummary->diffacc; + pool.diffinv += sharesummary->diffsta + sharesummary->diffdup + + sharesummary->diffhi + sharesummary->diffrej; + workerstatus->diffacc += sharesummary->diffacc; + workerstatus->diffinv += sharesummary->diffsta + sharesummary->diffdup + + sharesummary->diffhi + sharesummary->diffrej; + workerstatus->shareacc += sharesummary->shareacc; + workerstatus->shareinv += sharesummary->sharesta + sharesummary->sharedup + + sharesummary->sharehi + sharesummary->sharerej; + + ss_item = prev_in_ktree(ctx); + } +} + /* All data is loaded, now update workerstatus fields - * Since shares are all part of a sharesummary, there's no need to search shares - */ + TODO: combine set_block_share_counters() with this? */ static void workerstatus_ready() { K_TREE_CTX ws_ctx[1], us_ctx[1], ss_ctx[1]; @@ -2400,46 +2510,63 @@ static void workerstatus_ready() } } -static void workerstatus_update(AUTHS *auths, SHARES *shares, USERSTATS *userstats, - SHARESUMMARY *sharesummary) +#define workerstatus_update(_auths, _shares, _userstats) \ + _workerstatus_update(_auths, _shares, _userstats, WHERE_FFL_HERE) + +static void _workerstatus_update(AUTHS *auths, SHARES *shares, + USERSTATS *userstats, WHERE_FFL_ARGS) { WORKERSTATUS *row; K_ITEM *item; if (auths) { - item = find_create_workerstatus(auths->userid, auths->workername); - DATA_WORKERSTATUS(row, item); - if (tv_newer(&(row->last_auth), &(auths->createdate))) - copy_tv(&(row->last_auth), &(auths->createdate)); - } - - if (startup_complete && shares) { - item = find_create_workerstatus(shares->userid, shares->workername); - DATA_WORKERSTATUS(row, item); - if (tv_newer(&(row->last_share), &(shares->createdate))) { - copy_tv(&(row->last_share), &(shares->createdate)); - row->last_diff = shares->diff; + item = find_workerstatus(auths->userid, auths->workername, + file, func, line); + if (item) { + DATA_WORKERSTATUS(row, item); + if (tv_newer(&(row->last_auth), &(auths->createdate))) + copy_tv(&(row->last_auth), &(auths->createdate)); } } - if (startup_complete && userstats) { - item = find_create_workerstatus(userstats->userid, userstats->workername); - DATA_WORKERSTATUS(row, item); - if (userstats->idle) { - if (tv_newer(&(row->last_idle), &(userstats->statsdate))) - copy_tv(&(row->last_idle), &(userstats->statsdate)); + if (startup_complete && shares) { + if (shares->errn == SE_NONE) { + pool.diffacc += shares->diff; + pool.shareacc++; } else { - if (tv_newer(&(row->last_stats), &(userstats->statsdate))) - copy_tv(&(row->last_stats), &(userstats->statsdate)); + pool.diffinv += shares->diff; + pool.shareinv++; + } + item = find_workerstatus(shares->userid, shares->workername, + file, func, line); + if (item) { + DATA_WORKERSTATUS(row, item); + if (tv_newer(&(row->last_share), &(shares->createdate))) { + copy_tv(&(row->last_share), &(shares->createdate)); + row->last_diff = shares->diff; + } + if (shares->errn == SE_NONE) { + row->diffacc += shares->diff; + row->shareacc++; + } else { + row->diffinv += shares->diff; + row->shareinv++; + } } } - if (startup_complete && sharesummary) { - item = find_create_workerstatus(sharesummary->userid, sharesummary->workername); - DATA_WORKERSTATUS(row, item); - if (tv_newer(&(row->last_share), &(sharesummary->lastshare))) { - copy_tv(&(row->last_share), &(sharesummary->lastshare)); - row->last_diff = sharesummary->lastdiffacc; + if (startup_complete && userstats) { + item = find_workerstatus(userstats->userid, userstats->workername, + file, func, line); + if (item) { + DATA_WORKERSTATUS(row, item); + if (userstats->idle) { + if (tv_newer(&(row->last_idle), &(userstats->statsdate))) + copy_tv(&(row->last_idle), &(userstats->statsdate)); + } else { + if (tv_newer(&(row->last_stats), &(userstats->statsdate))) + copy_tv(&(row->last_stats), &(userstats->statsdate)); + } } } } @@ -2972,6 +3099,9 @@ unitem: else { workers_root = add_to_ktree(workers_root, item, cmp_workers); k_add_head(workers_store, item); + // Ensure there is a matching workerstatus + find_create_workerstatus(userid, workername, + __FILE__, __func__, __LINE__); } K_WUNLOCK(workers_free); @@ -3250,6 +3380,13 @@ static bool workers_fill(PGconn *conn) workers_root = add_to_ktree(workers_root, item, cmp_workers); k_add_head(workers_store, item); + + /* Make sure a workerstatus exists for each worker + * This is to ensure that code can use the workerstatus tree + * to reference other tables and not miss workers in the + * other tables */ + find_create_workerstatus(row->userid, row->workername, + __FILE__, __func__, __LINE__); } if (!ok) k_add_head(workers_free, item); @@ -4483,14 +4620,6 @@ static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *wor } if (!sharesummary->reset) { - if (sharesummary->workinfoid >= pool.workinfoid) { - // Negate coz the shares will re-add - pool.diffacc -= sharesummary->diffacc; - pool.diffinv -= (sharesummary->diffsta + - sharesummary->diffdup + - sharesummary->diffhi + - sharesummary->diffrej); - } zero_sharesummary(sharesummary, cd, shares->diff); sharesummary->reset = true; } @@ -4498,7 +4627,7 @@ static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *wor } if (!confirm_sharesummary) - workerstatus_update(NULL, shares, NULL, NULL); + workerstatus_update(NULL, shares, NULL); sharesummary_update(conn, shares, NULL, NULL, by, code, inet, cd); @@ -4623,14 +4752,6 @@ static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username, } if (!sharesummary->reset) { - if (sharesummary->workinfoid >= pool.workinfoid) { - // Negate coz the shares will re-add - pool.diffacc -= sharesummary->diffacc; - pool.diffinv -= (sharesummary->diffsta + - sharesummary->diffdup + - sharesummary->diffhi + - sharesummary->diffrej); - } zero_sharesummary(sharesummary, cd, 0.0); sharesummary->reset = true; } @@ -4803,32 +4924,22 @@ static bool _sharesummary_update(PGconn *conn, SHARES *s_row, SHAREERRORS *e_row case SE_NONE: row->diffacc += s_row->diff; row->shareacc++; - if (row->workinfoid >= pool.workinfoid) - pool.diffacc += s_row->diff; break; case SE_STALE: row->diffsta += s_row->diff; row->sharesta++; - if (row->workinfoid >= pool.workinfoid) - pool.diffinv += s_row->diff; break; case SE_DUPE: row->diffdup += s_row->diff; row->sharedup++; - if (row->workinfoid >= pool.workinfoid) - pool.diffinv += s_row->diff; break; case SE_HIGH_DIFF: row->diffhi += s_row->diff; row->sharehi++; - if (row->workinfoid >= pool.workinfoid) - pool.diffinv += s_row->diff; break; default: row->diffrej += s_row->diff; row->sharerej++; - if (row->workinfoid >= pool.workinfoid) - pool.diffinv += s_row->diff; break; } } @@ -5193,8 +5304,6 @@ static bool sharesummary_fill(PGconn *conn) sharesummary_workinfoid_root = add_to_ktree(sharesummary_workinfoid_root, item, cmp_sharesummary_workinfoid); k_add_head(sharesummary_store, item); - workerstatus_update(NULL, NULL, NULL, row); - // A share summary is currently only shares in a single workinfo, at all 3 levels n,a,y if (tolower(row->complete[0]) == SUMMARY_NEW) { if (dbstatus.oldest_sharesummary_firstshare_n.tv_sec == 0 || @@ -5223,12 +5332,6 @@ static bool sharesummary_fill(PGconn *conn) } } - if (row->workinfoid >= pool.workinfoid) { - pool.diffacc += row->diffacc; - pool.diffinv += row->diffsta + row->diffdup + - row->diffhi + row->diffrej; - } - tick(); } if (!ok) @@ -5373,8 +5476,6 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, TXT_TO_INT("height", height, row->height); STRNCPY(row->blockhash, blockhash); - HISTORYDATEINIT(row, cd, by, code, inet); - dsp_hash(blockhash, hash_dsp, sizeof(hash_dsp)); K_WLOCK(blocks_free); @@ -5419,6 +5520,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, STRNCPY(row->nonce, nonce); TXT_TO_BIGINT("reward", reward, row->reward); + HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); par = 0; @@ -5436,6 +5538,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, HISTORYDATEPARAMS(params, par, row); PARCHK(par, params); + // db default stats values ins = "insert into blocks " "(height,blockhash,workinfoid,userid,workername," "clientid,enonce1,nonce2,nonce,reward,confirmed" @@ -5507,16 +5610,17 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, conned = true; } - STRNCPY(row->confirmed, confirmed); // New is mostly a copy of the old - row->workinfoid = oldblocks->workinfoid; - STRNCPY(row->workername, oldblocks->workername); - row->clientid = oldblocks->clientid; - STRNCPY(row->enonce1, oldblocks->enonce1); - STRNCPY(row->nonce2, oldblocks->nonce2); - STRNCPY(row->nonce, oldblocks->nonce); - row->reward = oldblocks->reward; + memcpy(row, oldblocks, sizeof(*row)); + STRNCPY(row->confirmed, confirmed); + if (confirmed[0] == BLOCKS_CONFIRM) { + row->diffacc = pool.diffacc; + row->diffinv = pool.diffinv; + row->shareacc = pool.shareacc; + row->shareinv = pool.shareinv; + } + HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATETRANSFER(trf_root, row); res = PQexec(conn, "Begin", CKPQ_WRITE); @@ -5543,17 +5647,43 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash, params[par++] = str_to_buf(row->blockhash, NULL, 0); params[par++] = tv_to_buf(cd, NULL, 0); params[par++] = str_to_buf(row->confirmed, NULL, 0); - HISTORYDATEPARAMS(params, par, row); - PARCHKVAL(par, 3 + HISTORYDATECOUNT, params); // 8 as per ins - ins = "insert into blocks " - "(height,blockhash,workinfoid,userid,workername," - "clientid,enonce1,nonce2,nonce,reward,confirmed" - HISTORYDATECONTROL ") select " - "height,blockhash,workinfoid,userid,workername," - "clientid,enonce1,nonce2,nonce,reward," - "$3,$4,$5,$6,$7,$8 from blocks where " - "blockhash=$1 and expirydate=$2"; + if (confirmed[0] == BLOCKS_CONFIRM) { + params[par++] = double_to_buf(row->diffacc, NULL, 0); + params[par++] = double_to_buf(row->diffinv, NULL, 0); + params[par++] = double_to_buf(row->shareacc, NULL, 0); + params[par++] = double_to_buf(row->shareinv, NULL, 0); + HISTORYDATEPARAMS(params, par, row); + PARCHKVAL(par, 7 + HISTORYDATECOUNT, params); // 12 as per ins + + ins = "insert into blocks " + "(height,blockhash,workinfoid,userid,workername," + "clientid,enonce1,nonce2,nonce,reward,confirmed," + "diffacc,diffinv,shareacc,shareinv,elapsed," + "statsconfirmed" + HISTORYDATECONTROL ") select " + "height,blockhash,workinfoid,userid,workername," + "clientid,enonce1,nonce2,nonce,reward," + "$3,$4,$5,$6,$7,elapsed,statsconfirmed," + "$8,$9,$10,$11,$12 from blocks where " + "blockhash=$1 and expirydate=$2"; + } else { + HISTORYDATEPARAMS(params, par, row); + PARCHKVAL(par, 3 + HISTORYDATECOUNT, params); // 8 as per ins + + ins = "insert into blocks " + "(height,blockhash,workinfoid,userid,workername," + "clientid,enonce1,nonce2,nonce,reward,confirmed," + "diffacc,diffinv,shareacc,shareinv,elapsed," + "statsconfirmed" + HISTORYDATECONTROL ") select " + "height,blockhash,workinfoid,userid,workername," + "clientid,enonce1,nonce2,nonce,reward," + "$3,diffacc,diffinv,shareacc,shareinv,elapsed," + "statsconfirmed" + "$4,$5,$6,$7,$8 from blocks where " + "blockhash=$1 and expirydate=$2"; + } res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); rescode = PQresultStatus(res); @@ -5608,7 +5738,8 @@ flail: switch (confirmed[0]) { case BLOCKS_NEW: blk = true; - tmp[0] = '\0'; + tv_to_buf(&(row->createdate), cd_buf, sizeof(cd_buf)); + snprintf(tmp, sizeof(tmp), " UTC:%s", cd_buf); break; case BLOCKS_CONFIRM: blk = true; @@ -5625,8 +5756,8 @@ flail: 100.0 * pool.diffacc / wdiff); } } - if (pool.diffacc >= 1000000.0) { - suffix_string(pool.diffacc, est, sizeof(est)-1, 1); + if (pool.diffacc >= 1000.0) { + suffix_string(pool.diffacc, est, sizeof(est)-1, 0); strcat(est, " "); } tv_to_buf(&(row->createdate), cd_buf, sizeof(cd_buf)); @@ -5637,8 +5768,7 @@ flail: pool.diffacc, est, pct, cd_buf); if (pool.workinfoid < row->workinfoid) { pool.workinfoid = row->workinfoid; - pool.diffacc = pool.diffinv = - pool.best_sdiff = 0.0; + zero_on_new_block(); } break; case BLOCKS_ORPHAN: @@ -5667,14 +5797,15 @@ static bool blocks_fill(PGconn *conn) BLOCKS *row; char *field; char *sel; - int fields = 11; + int fields = 17; bool ok; LOGDEBUG("%s(): select", __func__); sel = "select " "height,blockhash,workinfoid,userid,workername," - "clientid,enonce1,nonce2,nonce,reward,confirmed" + "clientid,enonce1,nonce2,nonce,reward,confirmed," + "diffacc,diffinv,shareacc,shareinv,elapsed,statsconfirmed" HISTORYDATECONTROL " from blocks"; res = PQexec(conn, sel, CKPQ_READ); @@ -5756,6 +5887,36 @@ static bool blocks_fill(PGconn *conn) break; TXT_TO_STR("confirmed", field, row->confirmed); + PQ_GET_FLD(res, i, "diffacc", field, ok); + if (!ok) + break; + TXT_TO_DOUBLE("diffacc", field, row->diffacc); + + PQ_GET_FLD(res, i, "diffinv", field, ok); + if (!ok) + break; + TXT_TO_DOUBLE("diffinv", field, row->diffinv); + + PQ_GET_FLD(res, i, "shareacc", field, ok); + if (!ok) + break; + TXT_TO_DOUBLE("shareacc", field, row->shareacc); + + PQ_GET_FLD(res, i, "shareinv", field, ok); + if (!ok) + break; + TXT_TO_DOUBLE("shareinv", field, row->shareinv); + + PQ_GET_FLD(res, i, "elapsed", field, ok); + if (!ok) + break; + TXT_TO_BIGINT("elapsed", field, row->elapsed); + + PQ_GET_FLD(res, i, "statsconfirmed", field, ok); + if (!ok) + break; + TXT_TO_STR("statsconfirmed", field, row->statsconfirmed); + HISTORYDATEFLDS(res, i, row, ok); if (!ok) break; @@ -6108,7 +6269,7 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username, K_WUNLOCK(auths_free); // Update even if DB fails - workerstatus_update(row, NULL, NULL, NULL); + workerstatus_update(row, NULL, NULL); if (conn == NULL) { conn = dbconnect(); @@ -6252,7 +6413,7 @@ static bool auths_fill(PGconn *conn) auths_root = add_to_ktree(auths_root, item, cmp_auths); k_add_head(auths_store, item); - workerstatus_update(row, NULL, NULL, NULL); + workerstatus_update(row, NULL, NULL); if (tv_newer(&(dbstatus.newest_createdate_auths), &(row->createdate))) copy_tv(&(dbstatus.newest_createdate_auths), &(row->createdate)); @@ -6751,7 +6912,7 @@ static bool userstats_add(char *poolinstance, char *elapsed, char *username, } } - workerstatus_update(NULL, NULL, row, NULL); + workerstatus_update(NULL, NULL, row); /* group at full key: userid,createdate,poolinstance,workername i.e. ignore instance and group together down at workername */ @@ -6959,7 +7120,7 @@ static bool userstats_fill(PGconn *conn) cmp_userstats_workerstatus); k_add_head(userstats_store, item); - workerstatus_update(NULL, NULL, row, NULL); + workerstatus_update(NULL, NULL, row); if (userstats_starttimeband(row, &statsdate)) { if (tv_newer(&(dbstatus.newest_starttimeband_userstats), &statsdate)) copy_tv(&(dbstatus.newest_starttimeband_userstats), &statsdate); @@ -7416,6 +7577,11 @@ static bool setup_data() if (!reload() || everyone_die) return false; + set_block_share_counters(); + + if (everyone_die) + return false; + workerstatus_ready(); userstats_workerstatus_root = free_ktree(userstats_workerstatus_root, NULL); @@ -7881,7 +8047,7 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused K_TREE *trf_root) { K_TREE_CTX ctx[1]; - K_ITEM *b_item; + K_ITEM *b_item, *w_item; BLOCKS *blocks; char reply[1024] = ""; char tmp[1024]; @@ -7940,6 +8106,44 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, blocks_confirmed(blocks->confirmed), FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + double_to_buf(blocks->diffacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(blocks->diffinv, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffinv:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(blocks->shareacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shareacc:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(blocks->shareinv, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shareinv:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + bigint_to_buf(blocks->elapsed, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "elapsed:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + w_item = find_workinfo(blocks->workinfoid); + if (w_item) { + char wdiffbin[TXT_SML+1]; + double wdiff; + WORKINFO *workinfo; + DATA_WORKINFO(workinfo, w_item); + hex2bin(wdiffbin, workinfo->bits, 4); + wdiff = diff_from_nbits(wdiffbin); + snprintf(tmp, sizeof(tmp), + "netdiff:%d=%.1f%c", + rows, wdiff, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + } else { + snprintf(tmp, sizeof(tmp), + "netdiff:%d=?%c", rows, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + } + rows++; } b_item = prev_in_ktree(ctx); @@ -7949,7 +8153,8 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, "rows=%d%cflds=%s%c", rows, FLDSEP, "height,blockhash,nonce,reward,workername,firstcreatedate," - "createdate,status", FLDSEP); + "createdate,status,diffacc,diffinv,shareacc,shareinv,elapsed," + "netdiff", FLDSEP); APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks", FLDSEP, ""); @@ -8267,18 +8472,25 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, double w_hashrate5m, w_hashrate1hr; int64_t w_elapsed; tv_t w_lastshare; - double w_lastdiff; + double w_lastdiff, w_diffacc, w_diffinv; + double w_shareacc, w_shareinv; w_hashrate5m = w_hashrate1hr = 0.0; w_elapsed = -1; w_lastshare.tv_sec = 0; - w_lastdiff = 0; + w_lastdiff = w_diffacc = w_diffinv = + w_shareacc = w_shareinv = 0; - ws_item = find_workerstatus(users->userid, workers->workername); + ws_item = find_workerstatus(users->userid, workers->workername, + __FILE__, __func__, __LINE__); if (ws_item) { DATA_WORKERSTATUS(workerstatus, ws_item); w_lastshare.tv_sec = workerstatus->last_share.tv_sec; w_lastdiff = workerstatus->last_diff; + w_diffacc = workerstatus->diffacc; + w_diffinv = workerstatus->diffinv; + w_shareacc = workerstatus->shareacc; + w_shareinv = workerstatus->shareinv; } // find last stored userid record @@ -8334,6 +8546,22 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, snprintf(tmp, sizeof(tmp), "w_lastdiff:%d=%s%c", rows, reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + double_to_buf((int)(w_diffacc), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "w_diffacc:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf((int)(w_diffinv), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "w_diffinv:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf((int)(w_shareacc), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "w_shareacc:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf((int)(w_shareinv), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "w_shareinv:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + userstats_workername_root = free_ktree(userstats_workername_root, NULL); K_RUNLOCK(userstats_free); } @@ -8346,8 +8574,10 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id, snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%s%c", rows, FLDSEP, - "workername,difficultydefault,idlenotificationenabled,idlenotificationtime", - stats ? ",w_hashrate5m,w_hashrate1hr,w_elapsed,w_lastshare,w_lastdiff" : "", + "workername,difficultydefault,idlenotificationenabled," + "idlenotificationtime", + stats ? ",w_hashrate5m,w_hashrate1hr,w_elapsed,w_lastshare," + "w_lastdiff,w_diffacc,w_diffinv,w_shareacc,w_shareinv" : "", FLDSEP); APPEND_REALLOC(buf, off, len, tmp); @@ -9166,6 +9396,14 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, pool.diffinv, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), "blockshareacc=%.1f%c", + pool.shareacc, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + snprintf(tmp, sizeof(tmp), "blockshareinv=%.1f%c", + pool.shareinv, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + // TODO: assumes only one poolinstance (for now) p_item = last_in_ktree(poolstats_root, ctx); if (p_item) {