diff --git a/pool/db.php b/pool/db.php
index 02028a90..7002d0d5 100644
--- a/pool/db.php
+++ b/pool/db.php
@@ -234,6 +234,18 @@ function getWorkers($user, $stats = 'Y')
return repDecode($rep);
}
#
+function getPercents($user, $stats = 'Y')
+{
+ if ($user == false)
+ showIndex();
+ $flds = array('username' => $user, 'stats' => $stats, 'percent' => 'Y');
+ $msg = msgEncode('workers', 'work', $flds, $user);
+ $rep = sendsockreply('getPercents', $msg);
+ if (!$rep)
+ dbdown();
+ return repDecode($rep);
+}
+#
function getPayments($user)
{
if ($user == false)
diff --git a/pool/page_api.php b/pool/page_api.php
index 82fbf0a6..234d4235 100644
--- a/pool/page_api.php
+++ b/pool/page_api.php
@@ -29,8 +29,7 @@ function show_api($info, $page, $menu, $name, $user)
no_api($jfu);
if (nuem($work))
{
- if ($info === NULL)
- $info = homeInfo($u);
+ $info = homeInfo($u);
if ($info === false)
no_api($jfu);
$rep = fldEncode($info, 'lastbc', true);
@@ -47,9 +46,26 @@ function show_api($info, $page, $menu, $name, $user)
}
else
{
- $ans = getWorkers($u);
+ $info = homeInfo($u);
+ if ($info === false)
+ no_api($jfu);
+
+ $per = false;
+ if (is_array($info) && isset($info['u_multiaddr']))
+ {
+ $percent = getparam('percent', true);
+ if (!nuem($percent))
+ $per = true;
+ }
+
+ if ($per === true)
+ $ans = getPercents($u);
+ else
+ $ans = getWorkers($u);
+
if ($ans === false)
no_api($jfu);
+
$rep = fldEncode($ans, 'rows', true);
$rows = $ans['rows'];
$flds = explode(',', $ans['flds']);
diff --git a/pool/page_percent.php b/pool/page_percent.php
new file mode 100644
index 00000000..2cd5b887
--- /dev/null
+++ b/pool/page_percent.php
@@ -0,0 +1,174 @@
+';
+ $pg .= '
Address | ';
+ $pg .= 'Shares | ';
+ $pg .= 'Diff | ';
+ $pg .= 'Invalid | ';
+ $pg .= 'Block % | ';
+ $pg .= 'Hash Rate | ';
+ $pg .= 'Ratio | ';
+ $pg .= 'Addr % | ';
+ $pg .= "\n";
+ return $pg;
+}
+#
+function perhashorder($a, $b)
+{
+ return $b['payratio'] - $a['payratio'];
+}
+#
+function peruser($data, $user, &$offset, &$totshare, &$totdiff,
+ &$totinvalid, &$totrate, &$blockacc,
+ &$blockreward, $srt = false)
+{
+ $ans = getPercents($user);
+
+ $pg = '';
+ if ($ans['STATUS'] == 'ok')
+ {
+ if (isset($ans['blockacc']))
+ $blockacc = $ans['blockacc'];
+ if (isset($ans['blockreward']))
+ $blockreward = $ans['blockreward'];
+ $all = array();
+ $count = $ans['rows'];
+ for ($i = 0; $i < $count; $i++)
+ {
+ $all[] = array('payaddress' => $ans['payaddress:'.$i],
+ 'payratio' => $ans['payratio:'.$i],
+ 'paypercent' => $ans['paypercent:'.$i],
+ 'p_shareacc' => $ans['p_shareacc:'.$i],
+ 'p_diffacc' => $ans['p_diffacc:'.$i],
+ 'p_diffinv' => $ans['p_diffinv:'.$i],
+ 'p_uhr' => $ans['p_hashrate5m:'.$i]);
+ }
+
+ if ($srt)
+ usort($all, 'perhashorder');
+
+ for ($i = 0; $i < $count; $i++)
+ {
+ if ((($offset) % 2) == 0)
+ $row = 'even';
+ else
+ $row = 'odd';
+
+ $pg .= "";
+ $pg .= ''.$all[$i]['payaddress'].' | ';
+
+ $shareacc = number_format($all[$i]['p_shareacc'], 0);
+ $totshare += $all[$i]['p_shareacc'];
+ $diffacc = number_format($all[$i]['p_diffacc'], 0);
+ $totdiff += $all[$i]['p_diffacc'];
+ $pg .= "$shareacc | ";
+ $pg .= "$diffacc | ";
+
+ $dtot = $all[$i]['p_diffacc'] + $all[$i]['p_diffinv'];
+ if ($dtot > 0)
+ $rej = number_format(100.0 * $all[$i]['p_diffinv'] / $dtot, 3);
+ else
+ $rej = '0';
+ $totinvalid += $all[$i]['p_diffinv'];
+
+ $pg .= "$rej% | ";
+
+ if ($blockacc <= 0)
+ $blkpct = ' ';
+ else
+ $blkpct = number_format(100.0 * $all[$i]['p_diffacc'] / $blockacc, 3) . '%';
+
+ $pg .= "$blkpct | ";
+
+ $uhr = $all[$i]['p_uhr'];
+ if ($uhr == '?')
+ $uhr = '?GHs';
+ else
+ {
+ $totrate += $uhr;
+ $uhr = dsprate($uhr);
+ }
+ $pg .= "$uhr | ";
+
+ $pg .= ''.$all[$i]['payratio'].' | ';
+ $paypct = number_format($all[$i]['paypercent'], 3);
+ $pg .= "$paypct% | ";
+
+ $pg .= "
\n";
+
+ $offset++;
+ }
+ }
+ return $pg;
+}
+#
+function pertotal($offset, $totshare, $totdiff, $totinvalid, $totrate, $blockacc, $blockreward)
+{
+ $pg = '';
+ $totrate = dsprate($totrate);
+ if (($offset % 2) == 0)
+ $row = 'even';
+ else
+ $row = 'odd';
+ $pg .= "Total: | ";
+ $shareacc = number_format($totshare, 0);
+ $pg .= "$shareacc | ";
+ $diffacc = number_format($totdiff, 0);
+ $pg .= "$diffacc | ";
+ $dtot = $totdiff + $totinvalid;
+ if ($dtot > 0)
+ $rej = number_format(100.0 * $totinvalid / $dtot, 3);
+ else
+ $rej = '0';
+ $pg .= "$rej% | ";
+ if ($blockacc <= 0)
+ $blkpct = ' ';
+ else
+ $blkpct = number_format(100.0 * $totdiff / $blockacc, 3) . '%';
+ $pg .= "$blkpct | ";
+ $pg .= "$totrate | ";
+ $pg .= " |
\n";
+ return $pg;
+}
+#
+function dopercent($data, $user)
+{
+ $pg = 'Address Percents
';
+
+ $pg .= "\n";
+
+ $totshare = 0;
+ $totdiff = 0;
+ $totinvalid = 0;
+ $totrate = 0;
+ $offset = 0;
+ $blockacc = 0;
+ $blockreward = 0;
+
+ $pg .= pertitle($data, $user);
+ $pg .= peruser($data, $user, $offset, $totshare, $totdiff, $totinvalid,
+ $totrate, $blockacc, $blockreward, true);
+ $pg .= pertotal($offset, $totshare, $totdiff, $totinvalid, $totrate,
+ $blockacc, $blockreward);
+
+ if ($blockacc > 0 && $blockreward > 0)
+ {
+ $btc = btcfmt($totdiff / $blockacc * $blockreward);
+ $pg .= '';
+ $pg .= " Payout est if block found at 100%: ~$btc BTC";
+ $pg .= ' |
';
+ }
+
+ $pg .= "
\n";
+
+ return $pg;
+}
+#
+function show_percent($info, $page, $menu, $name, $user)
+{
+ gopage($info, NULL, 'dopercent', $page, $menu, $name, $user);
+}
+#
+?>
diff --git a/pool/prime.php b/pool/prime.php
index af2bf796..135bea3e 100644
--- a/pool/prime.php
+++ b/pool/prime.php
@@ -13,8 +13,10 @@ function process($p, $user, $menu)
{
if (isset($menu['Account']))
$menu['Account']['Addresses'] = 'addrmgt';
+ if (isset($menu['Workers']))
+ $menu['Workers']['Percents'] = 'percent';
}
- if ($user == 'Kano' || $user == 'ckolivas' || $user == 'wvr2' || $user == 'aphorise')
+ if ($user == 'Kano' || $user == 'ckolivas')
{
$menu['Admin']['ckp'] = 'ckp';
$menu['Admin']['PPLNS'] = 'pplns';
diff --git a/src/ckdb.h b/src/ckdb.h
index 07584c2a..f3a1e885 100644
--- a/src/ckdb.h
+++ b/src/ckdb.h
@@ -52,7 +52,7 @@
#define DB_VLOCK "1"
#define DB_VERSION "0.9.6"
-#define CKDB_VERSION DB_VERSION"-0.760"
+#define CKDB_VERSION DB_VERSION"-0.770"
#define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__
diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c
index 9f3ae8bb..4030804c 100644
--- a/src/ckdb_cmd.c
+++ b/src/ckdb_cmd.c
@@ -1141,12 +1141,256 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf;
}
+static char *cmd_percent(char *cmd, char *id, tv_t *now, USERS *users)
+{
+ K_ITEM w_look, *w_item, us_look, *us_item, *ws_item;
+ K_TREE_CTX w_ctx[1], us_ctx[1], pay_ctx[1];
+ WORKERS lookworkers, *workers;
+ WORKERSTATUS *workerstatus;
+ USERSTATS lookuserstats, *userstats;
+ char tmp[1024];
+ char *buf;
+ size_t len, off;
+ int rows;
+
+ K_TREE *userstats_workername_root = new_ktree();
+ K_TREE_CTX usw_ctx[1];
+ double t_hashrate5m = 0, t_hashrate1hr = 0;
+ double t_hashrate24hr = 0;
+ double t_diffacc = 0, t_diffinv = 0;
+ double t_diffsta = 0, t_diffdup = 0;
+ double t_diffhi = 0, t_diffrej = 0;
+ double t_shareacc = 0, t_shareinv = 0;
+ double t_sharesta = 0, t_sharedup = 0;
+ double t_sharehi = 0, t_sharerej = 0;
+
+ K_ITEM *pa_item;
+ PAYMENTADDRESSES *pa;
+ int64_t paytotal;
+ double ratio;
+
+ LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
+
+ APPEND_REALLOC_INIT(buf, off, len);
+ APPEND_REALLOC(buf, off, len, "ok.");
+ snprintf(tmp, sizeof(tmp), "blockacc=%.1f%c",
+ pool.diffacc, FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+ snprintf(tmp, sizeof(tmp), "blockreward=%"PRId64"%c",
+ pool.reward, FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ INIT_WORKERS(&w_look);
+ INIT_USERSTATS(&us_look);
+
+ // Add up all user's worker stats to be divided into payout percentages
+ lookworkers.userid = users->userid;
+ lookworkers.workername[0] = '\0';
+ lookworkers.expirydate.tv_sec = 0;
+ lookworkers.expirydate.tv_usec = 0;
+ w_look.data = (void *)(&lookworkers);
+ w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
+ DATA_WORKERS_NULL(workers, w_item);
+ while (w_item && workers->userid == users->userid) {
+ if (CURRENT(&(workers->expirydate))) {
+ ws_item = find_workerstatus(users->userid, workers->workername,
+ __FILE__, __func__, __LINE__);
+ if (ws_item) {
+ DATA_WORKERSTATUS(workerstatus, ws_item);
+ t_diffacc += workerstatus->diffacc;
+ t_diffinv += workerstatus->diffinv;
+ t_diffsta += workerstatus->diffsta;
+ t_diffdup += workerstatus->diffdup;
+ t_diffhi += workerstatus->diffhi;
+ t_diffrej += workerstatus->diffrej;
+ t_shareacc += workerstatus->shareacc;
+ t_shareinv += workerstatus->shareinv;
+ t_sharesta += workerstatus->sharesta;
+ t_sharedup += workerstatus->sharedup;
+ t_sharehi += workerstatus->sharehi;
+ t_sharerej += workerstatus->sharerej;
+ }
+
+ // find last stored userstats record
+ lookuserstats.userid = users->userid;
+ lookuserstats.statsdate.tv_sec = date_eot.tv_sec;
+ lookuserstats.statsdate.tv_usec = date_eot.tv_usec;
+ // find/cmp doesn't get to here
+ lookuserstats.poolinstance[0] = '\0';
+ lookuserstats.workername[0] = '\0';
+ us_look.data = (void *)(&lookuserstats);
+ K_RLOCK(userstats_free);
+ us_item = find_before_in_ktree(userstats_root, &us_look, cmp_userstats, us_ctx);
+ DATA_USERSTATS_NULL(userstats, us_item);
+ while (us_item && userstats->userid == lookuserstats.userid) {
+ if (strcmp(userstats->workername, workers->workername) == 0) {
+ if (tvdiff(now, &(userstats->statsdate)) < USERSTATS_PER_S) {
+ if (!find_in_ktree(userstats_workername_root, us_item,
+ cmp_userstats_workername, usw_ctx)) {
+ t_hashrate5m += userstats->hashrate5m;
+ t_hashrate1hr += userstats->hashrate1hr;
+ t_hashrate24hr += userstats->hashrate24hr;
+ userstats_workername_root =
+ add_to_ktree(userstats_workername_root,
+ us_item,
+ cmp_userstats_workername);
+ }
+ } else
+ break;
+
+ }
+ us_item = prev_in_ktree(us_ctx);
+ DATA_USERSTATS_NULL(userstats, us_item);
+ }
+ K_RUNLOCK(userstats_free);
+ }
+ w_item = next_in_ktree(w_ctx);
+ DATA_WORKERS_NULL(workers, w_item);
+ }
+
+ userstats_workername_root = free_ktree(userstats_workername_root, NULL);
+
+ // Calculate total payratio
+ paytotal = 0;
+ K_RLOCK(paymentaddresses_free);
+ pa_item = find_paymentaddresses(users->userid, pay_ctx);
+ DATA_PAYMENTADDRESSES(pa, pa_item);
+ while (pa_item && CURRENT(&(pa->expirydate)) &&
+ pa->userid == users->userid) {
+ paytotal += pa->payratio;
+ pa_item = prev_in_ktree(pay_ctx);
+ DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
+ }
+ if (paytotal == 0)
+ paytotal = 1;
+
+ // Divide totals into payout percentages
+ rows = 0;
+ pa_item = find_paymentaddresses(users->userid, pay_ctx);
+ DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
+ while (pa_item && CURRENT(&(pa->expirydate)) &&
+ pa->userid == users->userid) {
+ ratio = (double)(pa->payratio) / (double)paytotal;
+
+ snprintf(tmp, sizeof(tmp), "payaddress:%d=%s%c",
+ rows, pa->payaddress, FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "payratio:%d=%"PRId32"%c",
+ rows, pa->payratio, FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "paypercent:%d=%.6f%c",
+ rows, ratio * 100.0, FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_hashrate5m:%d=%.1f%c", rows,
+ (double)t_hashrate5m * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_hashrate1hr:%d=%.1f%c", rows,
+ (double)t_hashrate1hr * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_hashrate24hr:%d=%.1f%c", rows,
+ (double)t_hashrate24hr * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffacc:%d=%.1f%c", rows,
+ (double)t_diffacc * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffinv:%d=%.1f%c", rows,
+ (double)t_diffinv * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffsta:%d=%.1f%c", rows,
+ (double)t_diffsta * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffdup:%d=%.1f%c", rows,
+ (double)t_diffdup * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffhi:%d=%.1f%c", rows,
+ (double)t_diffhi * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_diffrej:%d=%.1f%c", rows,
+ (double)t_diffrej * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_shareacc:%d=%.1f%c", rows,
+ (double)t_shareacc * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_shareinv:%d=%.1f%c", rows,
+ (double)t_shareinv * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_sharesta:%d=%.1f%c", rows,
+ (double)t_sharesta * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_sharedup:%d=%.1f%c", rows,
+ (double)t_sharedup * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_sharehi:%d=%.1f%c", rows,
+ (double)t_sharehi * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "p_sharerej:%d=%.1f%c", rows,
+ (double)t_sharerej * ratio,
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ rows++;
+
+ pa_item = prev_in_ktree(pay_ctx);
+ DATA_PAYMENTADDRESSES_NULL(pa, pa_item);
+ }
+
+ snprintf(tmp, sizeof(tmp),
+ "rows=%d%cflds=%s%c",
+ rows, FLDSEP,
+ "payaddress,payratio,paypercent,"
+ "p_hashrate5m,p_hashrate1hr,p_hashrate24hr,"
+ "p_diffacc,p_diffinv,"
+ "p_diffsta,p_diffdup,p_diffhi,p_diffrej,"
+ "p_shareacc,p_shareinv,"
+ "p_sharesta,p_sharedup,p_sharehi,p_sharerej",
+ FLDSEP);
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Percents", FLDSEP, "");
+ APPEND_REALLOC(buf, off, len, tmp);
+
+ LOGDEBUG("%s.ok.%s", id, users->username);
+ return buf;
+}
+
static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
- __maybe_unused tv_t *now, __maybe_unused char *by,
+ tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root)
{
- K_ITEM *i_username, *i_stats, w_look, *u_item, *w_item, us_look, *us_item, *ws_item;
+ K_ITEM *i_username, *i_stats, *i_percent, w_look, *u_item, *w_item;
+ K_ITEM *ua_item, us_look, *us_item, *ws_item;
K_TREE_CTX w_ctx[1], us_ctx[1];
WORKERS lookworkers, *workers;
WORKERSTATUS *workerstatus;
@@ -1157,7 +1401,7 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
size_t siz = sizeof(reply);
char *buf;
size_t len, off;
- bool stats;
+ bool stats, percent;
int rows;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@@ -1179,16 +1423,19 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
else
stats = (strcasecmp(transfer_data(i_stats), TRUE_STR) == 0);
- INIT_WORKERS(&w_look);
- INIT_USERSTATS(&us_look);
+ percent = false;
+ K_RLOCK(useratts_free);
+ ua_item = find_useratts(users->userid, USER_MULTI_PAYOUT);
+ K_RUNLOCK(useratts_free);
+ if (ua_item) {
+ i_percent = optional_name(trf_root, "percent", 1, NULL, reply, siz);
+ if (i_percent)
+ percent = (strcasecmp(transfer_data(i_stats), TRUE_STR) == 0);
+ }
+
+ if (percent)
+ return cmd_percent(cmd, id, now, users);
- lookworkers.userid = users->userid;
- lookworkers.workername[0] = '\0';
- lookworkers.expirydate.tv_sec = 0;
- lookworkers.expirydate.tv_usec = 0;
- w_look.data = (void *)(&lookworkers);
- w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
- DATA_WORKERS_NULL(workers, w_item);
APPEND_REALLOC_INIT(buf, off, len);
APPEND_REALLOC(buf, off, len, "ok.");
snprintf(tmp, sizeof(tmp), "blockacc=%.1f%c",
@@ -1198,6 +1445,16 @@ static char *cmd_workers(__maybe_unused PGconn *conn, char *cmd, char *id,
pool.reward, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
+ INIT_WORKERS(&w_look);
+ INIT_USERSTATS(&us_look);
+
+ lookworkers.userid = users->userid;
+ lookworkers.workername[0] = '\0';
+ lookworkers.expirydate.tv_sec = 0;
+ lookworkers.expirydate.tv_usec = 0;
+ w_look.data = (void *)(&lookworkers);
+ w_item = find_after_in_ktree(workers_root, &w_look, cmp_workers, w_ctx);
+ DATA_WORKERS_NULL(workers, w_item);
rows = 0;
while (w_item && workers->userid == users->userid) {
if (CURRENT(&(workers->expirydate))) {