From 939c17cd87c761ac89b07ddcee16bd8b57d7195c Mon Sep 17 00:00:00 2001 From: kanoi Date: Sun, 1 Mar 2015 20:03:39 +1100 Subject: [PATCH 01/36] ckdb/php - a useful payments page --- pool/page_payments.php | 43 ++++++++++++++++++-- src/ckdb.h | 2 +- src/ckdb_cmd.c | 89 +++++++++++++++++++++++------------------- 3 files changed, 89 insertions(+), 45 deletions(-) diff --git a/pool/page_payments.php b/pool/page_payments.php index 280b0a6c..15abade3 100644 --- a/pool/page_payments.php +++ b/pool/page_payments.php @@ -1,5 +1,10 @@ \n"; $pg .= ""; - $pg .= "Date"; + $pg .= "Block"; $pg .= "Address"; + $pg .= "Status"; $pg .= "BTC"; + $pg .= ""; $pg .= "\n"; if ($ans['STATUS'] == 'ok') { + $all = array(); $count = $ans['rows']; for ($i = 0; $i < $count; $i++) + { + $all[] = array('payoutid' => $ans['payoutid:'.$i], + 'height' => $ans['height:'.$i], + 'payaddress' => $ans['payaddress:'.$i], + 'amount' => $ans['amount:'.$i], + 'paydate' => $ans['paydate:'.$i]); + } + usort($all, 'sortheight'); + $hasdust = false; + for ($i = 0; $i < $count; $i++) { if (($i % 2) == 0) $row = 'even'; @@ -28,11 +46,28 @@ function dopayments($data, $user) $row = 'odd'; $pg .= ""; - $pg .= ''.$ans['paydate:'.$i].''; - $pg .= ''.$ans['payaddress:'.$i].''; - $pg .= ''.btcfmt($ans['amount:'.$i]).''; + $pg .= ''.$all[$i]['height'].''; + $pg .= ''.$all[$i]['payaddress'].''; + $pg .= ' '; + $amount = $all[$i]['amount']; + if ($amount < '10000') + { + $dust = '*'; + $hasdust = true; + } + else + $dust = ' '; + $pg .= ''.btcfmt($amount).''; + $pg .= "$dust"; $pg .= "\n"; } + if ($hasdust === true) + { + $pg .= ''; + $pg .= '* '; + $pg .= 'Dust payments are not automatically sent out'; + $pg .= ''; + } } $pg .= "\n"; diff --git a/src/ckdb.h b/src/ckdb.h index 34c91f7c..e7717ef7 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.007" +#define CKDB_VERSION DB_VERSION"-1.008" #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 a9c32c77..38cebbe4 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -1092,9 +1092,11 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notcd, __maybe_unused K_TREE *trf_root) { - K_ITEM *i_username, *u_item, *p_item; + K_ITEM *i_username, *u_item, *p_item, *p2_item, *po_item; K_TREE_CTX ctx[1]; - PAYMENTS *payments, curr; + K_STORE *pay_store; + PAYMENTS *payments, *last_payments = NULL; + PAYOUTS *payouts; USERS *users; char reply[1024] = ""; char tmp[1024]; @@ -1102,6 +1104,7 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, char *buf; size_t len, off; int rows; + bool pok; LOGDEBUG("%s(): cmd '%s'", __func__, cmd); @@ -1116,65 +1119,71 @@ static char *cmd_payments(__maybe_unused PGconn *conn, char *cmd, char *id, return strdup("bad"); DATA_USERS(users, u_item); - bzero(&curr, sizeof(curr)); APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC(buf, off, len, "ok."); rows = 0; - - K_RLOCK(payments_free); + pay_store = k_new_store(payments_free); + K_WLOCK(payments_free); p_item = find_first_payments(users->userid, ctx); DATA_PAYMENTS_NULL(payments, p_item); /* TODO: allow to see details of a single payoutid * if it has multiple items (percent payout user) */ while (p_item && payments->userid == users->userid) { if (CURRENT(&(payments->expirydate))) { - if (curr.payoutid && curr.payoutid != payments->payoutid) { - tv_to_buf(&(curr.paydate), reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "paydate:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); - - str_to_buf(curr.payaddress, reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "payaddress:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); - - bigint_to_buf(curr.amount, reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "amount:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); - - rows++; - bzero(&curr, sizeof(curr)); + if (!last_payments || payments->payoutid != last_payments->payoutid) { + p2_item = k_unlink_head(payments_free); + DATA_PAYMENTS_NULL(last_payments, p2_item); + memcpy(last_payments, payments, sizeof(*last_payments)); + k_add_tail(pay_store, p2_item); + } else { + STRNCPY(last_payments->payaddress, "*Multiple"); + last_payments->amount += payments->amount; } - if (!curr.payoutid) { - curr.payoutid = payments->payoutid; - copy_tv(&(curr.paydate), &(payments->paydate)); - STRNCPY(curr.payaddress, payments->payaddress); - } else - STRNCPY(curr.payaddress, "*Multiple"); - curr.amount += payments->amount; } p_item = next_in_ktree(ctx); DATA_PAYMENTS_NULL(payments, p_item); } - K_RUNLOCK(payments_free); - if (curr.payoutid) { - tv_to_buf(&(curr.paydate), reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "paydate:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); + K_WUNLOCK(payments_free); + + p_item = pay_store->head; + while (p_item) { + DATA_PAYMENTS(payments, p_item); + pok = false; + K_RLOCK(payouts_free); + po_item = find_payoutid(payments->payoutid); + DATA_PAYOUTS_NULL(payouts, po_item); + if (p_item && PAYGENERATED(payouts->status)) + pok = true; + K_RUNLOCK(payouts_free); + if (pok) { + bigint_to_buf(payouts->payoutid, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "payoutid:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); - str_to_buf(curr.payaddress, reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "payaddress:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); + int_to_buf(payouts->height, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "height:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); - bigint_to_buf(curr.amount, reply, sizeof(reply)); - snprintf(tmp, sizeof(tmp), "amount:%d=%s%c", rows, reply, FLDSEP); - APPEND_REALLOC(buf, off, len, tmp); + str_to_buf(payments->payaddress, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "payaddress:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); - rows++; + bigint_to_buf(payments->amount, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "amount:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + tv_to_buf(&(payments->paydate), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "paydate:%d=%s%c", rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + rows++; + } + p_item = p_item->next; } snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", rows, FLDSEP, - "paydate,payaddress,amount", FLDSEP); + "payoutid,height,payaddress,amount,paydate", FLDSEP); APPEND_REALLOC(buf, off, len, tmp); snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Payments", FLDSEP, ""); From 23033b0ff1b51a668fa64ab7fae90cfcdca91e55 Mon Sep 17 00:00:00 2001 From: kanoi Date: Sun, 1 Mar 2015 20:59:28 +1100 Subject: [PATCH 02/36] ckdb - separate valid and invalid last_share/last_share_inv --- src/ckdb.c | 2 ++ src/ckdb.h | 3 ++- src/ckdb_cmd.c | 10 +++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index 222682db..23e88ba7 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -279,6 +279,7 @@ bool everyone_die = false; tv_t last_heartbeat; tv_t last_workinfo; tv_t last_share; +tv_t last_share_inv; tv_t last_auth; cklock_t last_lock; @@ -3250,6 +3251,7 @@ static void *listener(void *arg) setnow(&last_heartbeat); copy_tv(&last_workinfo, &last_heartbeat); copy_tv(&last_share, &last_heartbeat); + copy_tv(&last_share_inv, &last_heartbeat); copy_tv(&last_auth, &last_heartbeat); ck_wunlock(&last_lock); diff --git a/src/ckdb.h b/src/ckdb.h index e7717ef7..f9d554b5 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.008" +#define CKDB_VERSION DB_VERSION"-1.009" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -274,6 +274,7 @@ extern bool everyone_die; extern tv_t last_heartbeat; extern tv_t last_workinfo; extern tv_t last_share; +extern tv_t last_share_inv; extern tv_t last_auth; extern cklock_t last_lock; diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 38cebbe4..16c6de30 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -1954,8 +1954,13 @@ wiconf: return strdup("failed.DATA"); } else { // Only flag a successful share + int32_t errn; + TXT_TO_INT("errn", transfer_data(i_errn), errn); ck_wlock(&last_lock); - setnow(&last_share); + if (errn == SE_NONE) + setnow(&last_share); + else + setnow(&last_share_inv); ck_wunlock(&last_lock); } LOGDEBUG("%s.ok.added %s", id, transfer_data(i_nonce)); @@ -2492,6 +2497,9 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id, ftv_to_buf(&last_share, reply, siz); snprintf(tmp, sizeof(tmp), "lastsh=%s%c", reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + ftv_to_buf(&last_share_inv, reply, siz); + snprintf(tmp, sizeof(tmp), "lastshinv=%s%c", reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); ftv_to_buf(&last_auth, reply, siz); ck_wunlock(&last_lock); snprintf(tmp, sizeof(tmp), "lastau=%s%c", reply, FLDSEP); From b1e72ea7f3bcb2d7e623ad9c0cba1ed89ef9e3a2 Mon Sep 17 00:00:00 2001 From: kanoi Date: Sun, 1 Mar 2015 23:01:25 +1100 Subject: [PATCH 03/36] ckdd/php - MPayouts - mining payouts --- pool/base.php | 20 +++++++++ pool/db.php | 12 +++++ pool/prime.php | 1 + src/ckdb.c | 2 + src/ckdb.h | 3 +- src/ckdb_cmd.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 1 deletion(-) diff --git a/pool/base.php b/pool/base.php index 1c9824f2..4a64a75e 100644 --- a/pool/base.php +++ b/pool/base.php @@ -63,6 +63,26 @@ function howlongago($sec) return $des; } # +function howmanyhrs($sec) +{ + if ($sec < 60) + $des = $sec.'s'; + else + { + $min = floor($sec / 60); + $sec -= $min * 60; + if ($min < 60) + $des = $min.'m '.$sec.'s'; + else + { + $hr = floor($min / 60); + $min -= $hr * 60; + $des = $hr.'hr '.$min.'m '.$sec.'s'; + } + } + return $des; +} +# function btcfmt($amt) { $amt /= 100000000; diff --git a/pool/db.php b/pool/db.php index 7002d0d5..cd9d347c 100644 --- a/pool/db.php +++ b/pool/db.php @@ -258,6 +258,18 @@ function getPayments($user) return repDecode($rep); } # +function getMPayouts($user) +{ + if ($user == false) + showIndex(); + $flds = array('username' => $user); + $msg = msgEncode('mpayouts', 'mp', $flds, $user); + $rep = sendsockreply('getMPayments', $msg); + if (!$rep) + dbdown(); + return repDecode($rep); +} +# function getBlocks($user) { if ($user == false) diff --git a/pool/prime.php b/pool/prime.php index 0cfe79af..56973cda 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -67,6 +67,7 @@ function check() 'Home' => '' ), 'Account' => array( + 'MPayouts' => 'mpayouts', 'Payments' => 'payments', 'Settings' => 'settings', 'User Settings' => 'userset' diff --git a/src/ckdb.c b/src/ckdb.c index 23e88ba7..2c8d44c3 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -2664,6 +2664,7 @@ static void *socketer(__maybe_unused void *arg) case CMD_PPLNS: case CMD_PPLNS2: case CMD_PAYOUTS: + case CMD_MPAYOUTS: case CMD_DSP: case CMD_BLOCKSTATUS: if (!startup_complete) { @@ -2883,6 +2884,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) case CMD_PPLNS: case CMD_PPLNS2: case CMD_PAYOUTS: + case CMD_MPAYOUTS: case CMD_USERSTATUS: case CMD_MARKS: LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored", diff --git a/src/ckdb.h b/src/ckdb.h index f9d554b5..35de904e 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.009" +#define CKDB_VERSION DB_VERSION"-1.010" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -342,6 +342,7 @@ enum cmd_values { CMD_PPLNS, CMD_PPLNS2, CMD_PAYOUTS, + CMD_MPAYOUTS, CMD_USERSTATUS, CMD_MARKS, CMD_END diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 16c6de30..31659147 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4271,6 +4271,122 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, LOGWARNING("%s.%s", id, reply); return strdup(reply); } + +static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) +{ + K_ITEM *i_username, *u_item, *mp_item, *po_item; + K_TREE_CTX ctx[1]; + MININGPAYOUTS *mp; + PAYOUTS *payouts; + USERS *users; + char reply[1024] = ""; + char tmp[1024]; + size_t siz = sizeof(reply); + char *buf; + size_t len, off; + int rows; + + LOGDEBUG("%s(): cmd '%s'", __func__, cmd); + + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); + if (!i_username) + return strdup(reply); + + K_RLOCK(users_free); + u_item = find_users(transfer_data(i_username)); + K_RUNLOCK(users_free); + if (!u_item) + return strdup("bad"); + DATA_USERS(users, u_item); + + APPEND_REALLOC_INIT(buf, off, len); + APPEND_REALLOC(buf, off, len, "ok."); + rows = 0; + K_RLOCK(payouts_free); + po_item = last_in_ktree(payouts_root, ctx); + DATA_PAYOUTS_NULL(payouts, po_item); + /* TODO: allow to see details of a single payoutid + * if it has multiple items (percent payout user) */ + while (po_item) { + if (CURRENT(&(payouts->expirydate)) && + PAYGENERATED(payouts->status)) { + // Not locked ... for now + mp_item = find_miningpayouts(payouts->payoutid, + users->userid); + if (mp_item) { + DATA_MININGPAYOUTS(mp, mp_item); + + bigint_to_buf(payouts->payoutid, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "payoutid:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + int_to_buf(payouts->height, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "height:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + bigint_to_buf(payouts->elapsed, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "elapsed:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + bigint_to_buf(mp->amount, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "amount:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(mp->diffacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + bigint_to_buf(payouts->minerreward, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "minerreward:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(payouts->diffused, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffused:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + str_to_buf(payouts->status, reply, + sizeof(reply)); + snprintf(tmp, sizeof(tmp), "status:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + rows++; + } + } + po_item = prev_in_ktree(ctx); + DATA_PAYOUTS_NULL(payouts, po_item); + } + K_RUNLOCK(miningpayouts_free); + + snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", + rows, FLDSEP, + "payoutid,height,elapsed,amount,diffacc,minerreward,diffused,status", + FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "MiningPayouts", FLDSEP, ""); + APPEND_REALLOC(buf, off, len, tmp); + + LOGDEBUG("%s.ok.%s", id, transfer_data(i_username)); + return buf; +} + static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, @@ -4932,6 +5048,7 @@ struct CMDS ckdb_cmds[] = { { CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM ACCESS_WEB }, { CMD_PPLNS2, "pplns2", false, false, cmd_pplns2, ACCESS_SYSTEM ACCESS_WEB }, { CMD_PAYOUTS, "payouts", false, false, cmd_payouts, ACCESS_SYSTEM }, + { CMD_MPAYOUTS, "mpayouts", false, false, cmd_mpayouts, ACCESS_SYSTEM ACCESS_WEB }, { CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB }, { CMD_MARKS, "marks", false, false, cmd_marks, ACCESS_SYSTEM }, { CMD_END, NULL, false, false, NULL, NULL } From 924e52b435ae96d79085c03fffe9e1aad0a2bb4f Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 2 Mar 2015 08:50:20 +1100 Subject: [PATCH 04/36] ckdb/php - user shift report page --- pool/base.php | 8 +- pool/db.php | 12 +++ pool/page_blocks.php | 2 +- pool/page_shifts.php | 62 ++++++++++++++++ pool/prime.php | 1 + src/ckdb.c | 2 + src/ckdb.h | 4 +- src/ckdb_cmd.c | 173 ++++++++++++++++++++++++++++++++++++++++++- src/ckdb_data.c | 28 +++++++ 9 files changed, 288 insertions(+), 4 deletions(-) create mode 100644 pool/page_shifts.php diff --git a/pool/base.php b/pool/base.php index 4a64a75e..5b24c4ab 100644 --- a/pool/base.php +++ b/pool/base.php @@ -63,8 +63,9 @@ function howlongago($sec) return $des; } # -function howmanyhrs($sec) +function howmanyhrs($tot) { + $sec = round($tot); if ($sec < 60) $des = $sec.'s'; else @@ -89,6 +90,11 @@ function btcfmt($amt) return number_format($amt, 8); } # +function utcd($when) +{ + return gmdate('Y-m-d H:i:s+00', round($when)); +} +# global $sipre; # max of uint64 is ~1.845x10^19, 'Z' is above that (10^21) # max of uint256 is ~1.158x10^77, which is well above 'Y' (10^24) diff --git a/pool/db.php b/pool/db.php index cd9d347c..6c85e9cd 100644 --- a/pool/db.php +++ b/pool/db.php @@ -270,6 +270,18 @@ function getMPayouts($user) return repDecode($rep); } # +function getShifts($user) +{ + if ($user == false) + showIndex(); + $flds = array('username' => $user); + $msg = msgEncode('shifts', 'shift', $flds, $user); + $rep = sendsockreply('getShifts', $msg); + if (!$rep) + dbdown(); + return repDecode($rep); +} +# function getBlocks($user) { if ($user == false) diff --git a/pool/page_blocks.php b/pool/page_blocks.php index 4040ed5b..7d8a35e8 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -184,7 +184,7 @@ function doblocks($data, $user) if ($user !== null) $pg .= "".htmlspecialchars($ans['workername:'.$i]).''; $pg .= "".btcfmt($ans['reward:'.$i]).''; - $pg .= "".gmdate('Y-m-d H:i:s+00', $ans['firstcreatedate:'.$i]).''; + $pg .= "".utcd($ans['firstcreatedate:'.$i]).''; $pg .= "".$stat.''; $pg .= "$stara$acc"; $pg .= "$bpct"; diff --git a/pool/page_shifts.php b/pool/page_shifts.php new file mode 100644 index 00000000..0704bf02 --- /dev/null +++ b/pool/page_shifts.php @@ -0,0 +1,62 @@ +\n"; + $pg .= ""; + $pg .= "Shift"; + $pg .= "Start"; + $pg .= "Elapsed"; + $pg .= "Your Diff"; + $pg .= "Avg Hs"; + $pg .= "Shares"; + $pg .= "Avg Share"; + $pg .= "\n"; + if ($ans['STATUS'] != 'ok') + $pg = '

Shifts

'.$pg; + else + { + $count = $ans['rows']; + $pg = '

Last '.($count+1).' Shifts

'.$pg; + for ($i = 0; $i < $count; $i++) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $pg .= ""; + $shif = preg_replace(array('/^.* to /','/^.*fin: /'), '', $ans['shift:'.$i]); + $pg .= "$shif"; + $start = $ans['start:'.$i]; + $pg .= ''.utcd($start).''; + $nd = $ans['end:'.$i]; + $elapsed = $nd - $start; + $pg .= ''.howmanyhrs($elapsed).''; + $diffacc = $ans['diffacc:'.$i]; + $pg .= ''.difffmt($diffacc).''; + $hr = $diffacc * pow(2,32) / $elapsed; + $pg .= ''.dsprate($hr).''; + $shareacc = $ans['shareacc:'.$i]; + $pg .= ''.difffmt($shareacc).''; + if ($shareacc > 0) + $avgsh = $diffacc / $shareacc; + else + $avgsh = 0; + $pg .= ''.number_format($avgsh, 2).''; + $pg .= "\n"; + } + } + $pg .= "\n"; + + return $pg; +} +# +function show_shifts($info, $page, $menu, $name, $user) +{ + gopage($info, NULL, 'doshifts', $page, $menu, $name, $user); +} +# +?> diff --git a/pool/prime.php b/pool/prime.php index 56973cda..ced6f53d 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -73,6 +73,7 @@ function check() 'User Settings' => 'userset' ), 'Workers' => array( + 'Shifts ' => 'shifts', 'Workers ' => 'workers', 'Management' => 'workmgt', ), diff --git a/src/ckdb.c b/src/ckdb.c index 2c8d44c3..8ad9a05e 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -2665,6 +2665,7 @@ static void *socketer(__maybe_unused void *arg) case CMD_PPLNS2: case CMD_PAYOUTS: case CMD_MPAYOUTS: + case CMD_SHIFTS: case CMD_DSP: case CMD_BLOCKSTATUS: if (!startup_complete) { @@ -2885,6 +2886,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf) case CMD_PPLNS2: case CMD_PAYOUTS: case CMD_MPAYOUTS: + case CMD_SHIFTS: case CMD_USERSTATUS: case CMD_MARKS: LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored", diff --git a/src/ckdb.h b/src/ckdb.h index 35de904e..a0646a2d 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.010" +#define CKDB_VERSION DB_VERSION"-1.011" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -343,6 +343,7 @@ enum cmd_values { CMD_PPLNS2, CMD_PAYOUTS, CMD_MPAYOUTS, + CMD_SHIFTS, CMD_USERSTATUS, CMD_MARKS, CMD_END @@ -1719,6 +1720,7 @@ extern int32_t _coinbase1height(char *coinbase1, WHERE_FFL_ARGS); extern cmp_t _cmp_height(char *coinbase1a, char *coinbase1b, WHERE_FFL_ARGS); extern cmp_t cmp_workinfo_height(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); +extern K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx); extern bool workinfo_age(PGconn *conn, int64_t workinfoid, char *poolinstance, char *by, char *code, char *inet, tv_t *cd, tv_t *ss_first, tv_t *ss_last, int64_t *ss_count, diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 31659147..303be5cd 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4372,7 +4372,7 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id, po_item = prev_in_ktree(ctx); DATA_PAYOUTS_NULL(payouts, po_item); } - K_RUNLOCK(miningpayouts_free); + K_RUNLOCK(payouts_free); snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", rows, FLDSEP, @@ -4387,6 +4387,176 @@ static char *cmd_mpayouts(__maybe_unused PGconn *conn, char *cmd, char *id, return buf; } +static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, + __maybe_unused tv_t *now, __maybe_unused char *by, + __maybe_unused char *code, __maybe_unused char *inet, + __maybe_unused tv_t *notcd, + __maybe_unused K_TREE *trf_root) +{ + K_ITEM *i_username, *u_item, ms_look, *wm_item, *ms_item, *wi_item; + K_TREE_CTX wm_ctx[1], ms_ctx[1]; + WORKMARKERS *wm; + WORKINFO *wi; + MARKERSUMMARY markersummary, *ms, ms_add; + USERS *users; + char reply[1024] = ""; + char tmp[1024]; + size_t siz = sizeof(reply); + char *buf; + size_t len, off; + tv_t marker_end = { 0L, 0L }; + int rows; + + LOGDEBUG("%s(): cmd '%s'", __func__, cmd); + + i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); + if (!i_username) + return strdup(reply); + + K_RLOCK(users_free); + u_item = find_users(transfer_data(i_username)); + K_RUNLOCK(users_free); + if (!u_item) + return strdup("bad"); + DATA_USERS(users, u_item); + + APPEND_REALLOC_INIT(buf, off, len); + APPEND_REALLOC(buf, off, len, "ok."); + INIT_MARKERSUMMARY(&ms_look); + ms_look.data = (void *)(&markersummary); + rows = 0; + K_RLOCK(workmarkers_free); + wm_item = last_in_ktree(workmarkers_workinfoid_root, wm_ctx); + DATA_WORKMARKERS_NULL(wm, wm_item); + /* TODO: allow to see details of a single payoutid + * if it has multiple items (percent payout user) */ + while (rows < 98 && wm_item) { + if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) { + K_RUNLOCK(workmarkers_free); + + bzero(&ms_add, sizeof(ms_add)); + + markersummary.markerid = wm->markerid; + markersummary.userid = users->userid; + markersummary.workername = EMPTY; + K_RLOCK(markersummary_free); + ms_item = find_after_in_ktree(markersummary_root, &ms_look, + cmp_markersummary, ms_ctx); + DATA_MARKERSUMMARY_NULL(ms, ms_item); + while (ms_item && ms->markerid == wm->markerid && + ms->userid == users->userid) { + ms_add.diffacc += ms->diffacc; + ms_add.diffrej += ms->diffrej; + ms_add.shareacc += ms->shareacc; + ms_add.sharerej += ms->sharerej; + + ms_item = next_in_ktree(ms_ctx); + DATA_MARKERSUMMARY_NULL(ms, ms_item); + } + K_RUNLOCK(markersummary_free); + + if (marker_end.tv_sec == 0L) { + wi_item = next_workinfo(wm->workinfoidend, NULL); + if (!wi_item) { + /* There's no workinfo after this shift + * Unexpected ... estimate last wid+30s */ + wi_item = find_workinfo(wm->workinfoidend, NULL); + if (!wi_item) { + // Nothing is currently locked + LOGERR("%s() workmarker %"PRId64"/%s." + " missing widend %"PRId64, + __func__, wm->markerid, + wm->description, + wm->workinfoidend); + snprintf(reply, siz, "data error 1"); + return strdup(reply); + } + DATA_WORKINFO(wi, wi_item); + copy_tv(&marker_end, &(wi->createdate)); + marker_end.tv_sec += 30; + } else { + DATA_WORKINFO(wi, wi_item); + copy_tv(&marker_end, &(wi->createdate)); + } + } + + wi_item = find_workinfo(wm->workinfoidstart, NULL); + if (!wi_item) { + // Nothing is currently locked + LOGERR("%s() workmarker %"PRId64"/%s. missing " + "widstart %"PRId64, + __func__, wm->markerid, wm->description, + wm->workinfoidstart); + snprintf(reply, siz, "data error 2"); + return strdup(reply); + } + DATA_WORKINFO(wi, wi_item); + + bigint_to_buf(wm->markerid, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "markerid:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + str_to_buf(wm->description, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shift:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + ftv_to_buf(&(wi->createdate), reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "start:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + ftv_to_buf(&marker_end, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "end:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.diffacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffacc:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.diffrej, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "diffrej:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.shareacc, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "shareacc:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + double_to_buf(ms_add.sharerej, reply, sizeof(reply)); + snprintf(tmp, sizeof(tmp), "sharerej:%d=%s%c", + rows, reply, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + rows++; + + // Setup for next shift + copy_tv(&marker_end, &(wi->createdate)); + + K_RLOCK(workmarkers_free); + } + wm_item = prev_in_ktree(wm_ctx); + DATA_WORKMARKERS_NULL(wm, wm_item); + } + K_RUNLOCK(workmarkers_free); + + snprintf(tmp, sizeof(tmp), "rows=%d%cflds=%s%c", + rows, FLDSEP, + "markerid,shift,start,end,diffacc,diffrej,shareacc,sharerej", + FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + + snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Shifts", FLDSEP, ""); + APPEND_REALLOC(buf, off, len, tmp); + + LOGDEBUG("%s.ok.%s", id, transfer_data(i_username)); + return buf; +} + static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd, char *id, __maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused char *code, @@ -5049,6 +5219,7 @@ struct CMDS ckdb_cmds[] = { { CMD_PPLNS2, "pplns2", false, false, cmd_pplns2, ACCESS_SYSTEM ACCESS_WEB }, { CMD_PAYOUTS, "payouts", false, false, cmd_payouts, ACCESS_SYSTEM }, { CMD_MPAYOUTS, "mpayouts", false, false, cmd_mpayouts, ACCESS_SYSTEM ACCESS_WEB }, + { CMD_SHIFTS, "shifts", false, false, cmd_shifts, ACCESS_SYSTEM ACCESS_WEB }, { CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB }, { CMD_MARKS, "marks", false, false, cmd_marks, ACCESS_SYSTEM }, { CMD_END, NULL, false, false, NULL, NULL } diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 96649aa8..1cf72429 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -1569,6 +1569,34 @@ K_ITEM *find_workinfo(int64_t workinfoid, K_TREE_CTX *ctx) return item; } +K_ITEM *next_workinfo(int64_t workinfoid, K_TREE_CTX *ctx) +{ + WORKINFO workinfo, *wi; + K_TREE_CTX ctx0[1]; + K_ITEM look, *item; + + if (ctx == NULL) + ctx = ctx0; + + workinfo.workinfoid = workinfoid; + workinfo.expirydate.tv_sec = default_expiry.tv_sec; + workinfo.expirydate.tv_usec = default_expiry.tv_usec; + + INIT_WORKINFO(&look); + look.data = (void *)(&workinfo); + K_RLOCK(workinfo_free); + item = find_after_in_ktree(workinfo_root, &look, cmp_workinfo, ctx); + if (item) { + DATA_WORKINFO(wi, item); + while (item && !CURRENT(&(wi->expirydate))) { + item = next_in_ktree(ctx); + DATA_WORKINFO_NULL(wi, item); + } + } + K_RUNLOCK(workinfo_free); + return item; +} + bool workinfo_age(PGconn *conn, int64_t workinfoid, char *poolinstance, char *by, char *code, char *inet, tv_t *cd, tv_t *ss_first, tv_t *ss_last, int64_t *ss_count, From b5ee57a620de5d36becf3cf04bbbabcf94a14751 Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 2 Mar 2015 09:11:32 +1100 Subject: [PATCH 05/36] php - add new (missing) mining payouts php --- pool/page_mpayouts.php | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 pool/page_mpayouts.php diff --git a/pool/page_mpayouts.php b/pool/page_mpayouts.php new file mode 100644 index 00000000..16dfcc54 --- /dev/null +++ b/pool/page_mpayouts.php @@ -0,0 +1,57 @@ +Mining Payouts'; + + $ans = getMPayouts($user); + + $pg .= "\n"; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= "\n"; + if ($ans['STATUS'] == 'ok') + { + $count = $ans['rows']; + for ($i = 0; $i < $count; $i++) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $pg .= ""; + $pg .= ''; + $pg .= ''; + $diffused = $ans['diffused:'.$i]; + $pg .= ''; + $elapsed = $ans['elapsed:'.$i]; + $pg .= ''; + $diffacc = $ans['diffacc:'.$i]; + $ypct = $diffacc * 100 / $diffused; + $pg .= ''; + $pg .= ''; + $hr = $diffacc * pow(2,32) / $elapsed; + $pg .= ''; + $pg .= ''; + $pg .= "\n"; + } + } + $pg .= "
BlockMiner RewardPayout DiffElapsedYour %Your DiffYour Avg HsYour BTC
'.$ans['height:'.$i].''.btcfmt($ans['minerreward:'.$i]).''.difffmt($diffused).''.howmanyhrs($elapsed).''.number_format($ypct, 2).'%'.difffmt($diffacc).''.dsprate($hr).''.btcfmt($ans['amount:'.$i]).'
\n"; + + return $pg; +} +# +function show_mpayouts($info, $page, $menu, $name, $user) +{ + gopage($info, NULL, 'dompayouts', $page, $menu, $name, $user); +} +# +?> From 89461a37f285648c0f66e3bfaead5c2c816d3922 Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 2 Mar 2015 11:04:14 +1100 Subject: [PATCH 06/36] php - adjust mining payouts display --- pool/page_mpayouts.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pool/page_mpayouts.php b/pool/page_mpayouts.php index 16dfcc54..37acff4f 100644 --- a/pool/page_mpayouts.php +++ b/pool/page_mpayouts.php @@ -10,11 +10,12 @@ function dompayouts($data, $user) $pg .= ""; $pg .= "Block"; $pg .= "Miner Reward"; - $pg .= "Payout Diff"; - $pg .= "Elapsed"; + $pg .= "N Diff"; + $pg .= "N Range"; + $pg .= "Pool N Avg"; $pg .= "Your %"; - $pg .= "Your Diff"; - $pg .= "Your Avg Hs"; + $pg .= "Your N Diff"; + $pg .= "Your N Avg"; $pg .= "Your BTC"; $pg .= "\n"; if ($ans['STATUS'] == 'ok') @@ -34,6 +35,8 @@ function dompayouts($data, $user) $pg .= ''.difffmt($diffused).''; $elapsed = $ans['elapsed:'.$i]; $pg .= ''.howmanyhrs($elapsed).''; + $phr = $diffused * pow(2,32) / $elapsed; + $pg .= ''.siprefmt($phr).'Hs'; $diffacc = $ans['diffacc:'.$i]; $ypct = $diffacc * 100 / $diffused; $pg .= ''.number_format($ypct, 2).'%'; From 380b2977b388dd3e537eb5c9ca39db7e7424ae75 Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 2 Mar 2015 16:11:43 +1100 Subject: [PATCH 07/36] php - span classes for home highlighting --- pool/page.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pool/page.php b/pool/page.php index 633ea0d1..e4ec64dd 100644 --- a/pool/page.php +++ b/pool/page.php @@ -110,6 +110,8 @@ div.topd {background-color:#cff; border-color: #cff; border-style: solid; border .topdat {margin-left: 8px; margin-right: 24px; color:green; font-weight: bold;} span.login {float: right; margin-left: 8px; margin-right: 24px;} span.hil {color:blue;} +span.user {color:green;} +span.addr {color:brown;} span.warn {color:orange; font-weight:bold;} span.urg {color:red; font-weight:bold;} span.err {color:red; font-weight:bold; font-size:120%;} From c58936d20980cf37c9d074b8818594a1a1156ed0 Mon Sep 17 00:00:00 2001 From: kanoi Date: Mon, 2 Mar 2015 16:17:24 +1100 Subject: [PATCH 08/36] php - wording changes --- pool/page_blocks.php | 4 ++-- pool/page_shifts.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pool/page_blocks.php b/pool/page_blocks.php index 7d8a35e8..d7b7d189 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -78,7 +78,7 @@ function doblocks($data, $user) list($fg, $bg) = pctcolour(25.0); $pg .= ""; $pg .= " Green  "; - $pg .= 'is good luck. Lower Diff% and bright green is best luck.
'; + $pg .= 'is good luck. Lower Diff% and brighter green is best luck.
'; list($fg, $bg) = pctcolour(100.0); $pg .= ""; $pg .= " 100%  "; @@ -86,7 +86,7 @@ function doblocks($data, $user) list($fg, $bg) = pctcolour(400.0); $pg .= ""; $pg .= " Red  "; - $pg .= 'is bad luck. Higher Diff% and bright red is worse luck.

'; + $pg .= 'is bad luck. Higher Diff% and brighter red is worse luck.

'; $pg .= "\n"; $pg .= ""; diff --git a/pool/page_shifts.php b/pool/page_shifts.php index 0704bf02..1092482f 100644 --- a/pool/page_shifts.php +++ b/pool/page_shifts.php @@ -8,7 +8,7 @@ function doshifts($data, $user) $pg .= ""; $pg .= ""; $pg .= ""; - $pg .= ""; + $pg .= ""; $pg .= ""; $pg .= ""; $pg .= ""; From 9a4056ddad79cbbd913b9a06d870ddc8d7a33e2c Mon Sep 17 00:00:00 2001 From: kanoi Date: Tue, 3 Mar 2015 00:01:37 +1100 Subject: [PATCH 09/36] ckdb - add the block diff to block messages --- src/ckdb.h | 4 +++- src/ckdb_data.c | 21 +++++++++++++++++++++ src/ckdb_dbio.c | 9 +++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/ckdb.h b/src/ckdb.h index a0646a2d..8986339d 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.011" +#define CKDB_VERSION DB_VERSION"-1.012" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -1741,6 +1741,8 @@ void _dbhash2btchash(char *hash, char *buf, size_t siz, WHERE_FFL_ARGS); #define dsp_hash(_hash, _buf, _siz) \ _dsp_hash(_hash, _buf, _siz, WHERE_FFL_HERE) extern void _dsp_hash(char *hash, char *buf, size_t siz, WHERE_FFL_ARGS); +#define blockhash_diff(_hash) _blockhash_diff(_hash, WHERE_FFL_HERE) +extern double _blockhash_diff(char *hash, WHERE_FFL_ARGS); extern void dsp_blocks(K_ITEM *item, FILE *stream); extern cmp_t cmp_blocks(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_blocks(int32_t height, char *blockhash, K_TREE_CTX *ctx); diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 1cf72429..3878f342 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -2086,6 +2086,27 @@ void _dsp_hash(char *hash, char *buf, size_t siz, WHERE_FFL_ARGS) STRNCPYSIZ(buf, ptr, siz); } +double _blockhash_diff(char *hash, WHERE_FFL_ARGS) +{ + uchar binhash[SHA256SIZHEX >> 1]; + uchar swap[SHA256SIZHEX >> 1]; + size_t len; + + len = strlen(hash); + // code bug - check this before calling + if (len != SHA256SIZHEX) { + quitfrom(1, file, func, line, + "%s() invalid hash passed - size %d (%d)", + __func__, (int)len, SHA256SIZHEX); + } + + hex2bin(binhash, hash, sizeof(binhash)); + + flip_32(swap, binhash); + + return diff_from_target(swap); +} + void dsp_blocks(K_ITEM *item, FILE *stream) { char createdate_buf[DATE_BUFSIZ], expirydate_buf[DATE_BUFSIZ]; diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index 73573095..4db4f0ba 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -4018,6 +4018,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, K_ITEM *b_item, *u_item, *old_b_item; char cd_buf[DATE_BUFSIZ]; char hash_dsp[16+1]; + double hash_diff; BLOCKS *row, *oldblocks; USERS *users; char *upd, *ins; @@ -4038,6 +4039,7 @@ bool blocks_add(PGconn *conn, char *height, char *blockhash, STRNCPY(row->blockhash, blockhash); dsp_hash(blockhash, hash_dsp, sizeof(hash_dsp)); + hash_diff = blockhash_diff(blockhash); K_RLOCK(blocks_free); old_b_item = find_blocks(row->height, blockhash, NULL); @@ -4307,10 +4309,13 @@ flail: if (ok) { char pct[16] = "?"; char est[16] = ""; + char diff[16] = ""; K_ITEM *w_item; char tmp[256]; bool blk; + suffix_string(hash_diff, diff, sizeof(diff)-1, 0); + switch (confirmed[0]) { case BLOCKS_NEW: blk = true; @@ -4356,10 +4361,10 @@ flail: break; } - LOGWARNING("%s(): %sStatus: %s, Block: %s/...%s%s", + LOGWARNING("%s(): %sStatus: %s, Block: %s/...%s Diff %s%s", __func__, blk ? "BLOCK! " : "", blocks_confirmed(confirmed), - height, hash_dsp, tmp); + height, hash_dsp, diff, tmp); } return ok; From ca25f65e85719ba3be80af60a92616285100dde6 Mon Sep 17 00:00:00 2001 From: kanoi Date: Thu, 5 Mar 2015 18:53:31 +1100 Subject: [PATCH 10/36] php - rename 'MPayouts' to 'Rewards' and add a total --- pool/page_mpayouts.php | 20 ++++++++++++++++++-- pool/prime.php | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pool/page_mpayouts.php b/pool/page_mpayouts.php index 37acff4f..96333835 100644 --- a/pool/page_mpayouts.php +++ b/pool/page_mpayouts.php @@ -2,7 +2,7 @@ # function dompayouts($data, $user) { - $pg = '

Mining Payouts

'; + $pg = '

Mining Rewards

'; $ans = getMPayouts($user); @@ -20,6 +20,7 @@ function dompayouts($data, $user) $pg .= "
\n"; if ($ans['STATUS'] == 'ok') { + $totamt = 0; $count = $ans['rows']; for ($i = 0; $i < $count; $i++) { @@ -43,7 +44,22 @@ function dompayouts($data, $user) $pg .= ''; $hr = $diffacc * pow(2,32) / $elapsed; $pg .= ''; - $pg .= ''; + $amount = $ans['amount:'.$i]; + $totamt += $amount; + $pg .= ''; + $pg .= "\n"; + } + if ($count > 1) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $pg .= ""; + $pg .= ''; + $pg .= ''; + $pg .= ''; $pg .= "\n"; } } diff --git a/pool/prime.php b/pool/prime.php index ced6f53d..539ef33b 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -67,7 +67,7 @@ function check() 'Home' => '' ), 'Account' => array( - 'MPayouts' => 'mpayouts', + 'Rewards' => 'mpayouts', 'Payments' => 'payments', 'Settings' => 'settings', 'User Settings' => 'userset' From 663ecf7854acc509cbaf906ee54296fdac025509 Mon Sep 17 00:00:00 2001 From: kanoi Date: Thu, 5 Mar 2015 19:07:56 +1100 Subject: [PATCH 11/36] php - add descriptions to payments and mpayouts --- pool/page_mpayouts.php | 5 +++++ pool/page_payments.php | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pool/page_mpayouts.php b/pool/page_mpayouts.php index 96333835..18e0df0b 100644 --- a/pool/page_mpayouts.php +++ b/pool/page_mpayouts.php @@ -6,6 +6,11 @@ function dompayouts($data, $user) $ans = getMPayouts($user); + $pg .= "The rewards you've earned for each block the pool has found.
"; + $pg .= 'See the '; + $pg .= makeLink('payments'); + $pg .= "Payments page for the payments you've been sent.

"; + $pg .= "
ShiftStartElapsedLengthYour DiffAvg HsShares
'.difffmt($diffacc).''.dsprate($hr).''.btcfmt($ans['amount:'.$i]).''.btcfmt($amount).'
Total:'.btcfmt($totamt).'
\n"; $pg .= ""; $pg .= ""; diff --git a/pool/page_payments.php b/pool/page_payments.php index 15abade3..5bd97ff0 100644 --- a/pool/page_payments.php +++ b/pool/page_payments.php @@ -11,8 +11,9 @@ function dopayments($data, $user) $addr1 = '1KzFJddTvK9TQWsmWFKYJ9fRx9QeSATyrT'; $pg = '

Payments

'; - $pg .= 'The payout transactions on blockchain are here:'; - $pg .= " BTC

"; + $pg .= 'The payment transactions on blockchain are here:'; + $pg .= " BTC
"; + $pg .= "The payments below don't yet show when they have been sent.

"; $ans = getPayments($user); From 951f9019a9192808dd60ab28f55274ce96bb8c7e Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 11 Mar 2015 18:38:32 +1100 Subject: [PATCH 12/36] ckdb/php - more block statistics --- configure.ac | 7 ++- pool/page_blocks.php | 112 +++++++++++++++++++---------------- src/Makefile.am | 2 +- src/ckdb.c | 2 + src/ckdb.h | 29 ++++++++- src/ckdb_cmd.c | 136 +++++++++++++++++++++++++++++++++++-------- src/ckdb_data.c | 108 ++++++++++++++++++++++++++++++++++ src/ckdb_dbio.c | 12 +++- 8 files changed, 327 insertions(+), 81 deletions(-) diff --git a/configure.ac b/configure.ac index 49d28ee2..d55e77b6 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,7 @@ AC_CHECK_HEADERS(alloca.h pthread.h stdio.h math.h signal.h sys/prctl.h) AC_CHECK_HEADERS(sys/types.h sys/socket.h sys/stat.h linux/un.h netdb.h) AC_CHECK_HEADERS(stdint.h netinet/in.h netinet/tcp.h sys/ioctl.h getopt.h) AC_CHECK_HEADERS(sys/epoll.h libpq-fe.h postgresql/libpq-fe.h grp.h) +AC_CHECK_HEADERS(gsl/gsl_math.h gsl/gsl_cdf.h) PTHREAD_LIBS="-lpthread" MATH_LIBS="-lm" @@ -59,8 +60,12 @@ AC_ARG_WITH([ckdb], if test "x$ckdb" != "xno"; then AC_CHECK_LIB([pq], [main],[PQ=-lpq],echo "Error: Required library libpq-dev not found. Install it or disable postgresql support with --without-ckdb" && exit 1) + AC_CHECK_LIB([gsl], [main],[GSL=-lgsl],echo "Error: Required library gsl-dev + not found. Install it or disable support with --without-ckdb" && exit 1) + AC_CHECK_LIB([gslcblas], [main],[GSLCBLAS=-lgslcblas],echo "Error: Required library gslcblas + not found. Install it or disable support with --without-ckdb" && exit 1) AC_DEFINE([USE_CKDB], [1], [Defined to 1 if ckdb support required]) - PQ_LIBS="-lpq" + PQ_LIBS="-lpq -lgsl -lgslcblas" else PQ_LIBS="" fi diff --git a/pool/page_blocks.php b/pool/page_blocks.php index d7b7d189..1556323c 100644 --- a/pool/page_blocks.php +++ b/pool/page_blocks.php @@ -56,6 +56,43 @@ function doblocks($data, $user) if ($wantcsv === false) { + if ($ans['STATUS'] == 'ok' and isset($ans['s_rows']) and $ans['s_rows'] > 0) + { + $pg .= '

Block Statistics

'; + $pg .= "
Block
\n"; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= "\n"; + + $count = $ans['s_rows']; + for ($i = 0; $i < $count; $i++) + { + if (($i % 2) == 0) + $row = 'even'; + else + $row = 'odd'; + + $desc = $ans['s_desc:'.$i]; + $diff = number_format(100 * $ans['s_diffratio:'.$i], 2); + $mean = number_format(100 * $ans['s_diffmean:'.$i], 2); + $cdferl = number_format($ans['s_cdferl:'.$i], 4); + $luck = number_format(100 * $ans['s_luck:'.$i], 2); + + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= ""; + $pg .= "\n"; + } + $pg .= "
DescriptionDiff%Mean%CDF[Erl]Luck%
$desc Blocks$diff%$mean%$cdferl$luck%
\n"; + } + if ($ans['STATUS'] == 'ok') { $count = $ans['rows']; @@ -70,15 +107,15 @@ function doblocks($data, $user) $s = 's'; } - $pg = "

Last$num Block$s

"; + $pg .= "

Last$num Block$s

"; } else - $pg = '

Blocks

'; + $pg .= '

Blocks

'; list($fg, $bg) = pctcolour(25.0); $pg .= ""; $pg .= " Green  "; - $pg .= 'is good luck. Lower Diff% and brighter green is best luck.
'; + $pg .= 'is good luck. Lower Diff% and brighter green is better luck.
'; list($fg, $bg) = pctcolour(100.0); $pg .= ""; $pg .= " 100%  "; @@ -94,7 +131,7 @@ function doblocks($data, $user) $pg .= "Height"; if ($user !== null) $pg .= "Who"; - $pg .= "Reward"; + $pg .= "Block Reward"; $pg .= "When"; $pg .= "Status"; $pg .= "Diff"; @@ -109,7 +146,6 @@ function doblocks($data, $user) $csv = "Sequence,Height,Status,Timestamp,DiffAcc,NetDiff,Hash\n"; if ($ans['STATUS'] == 'ok') { - $tot = $ans['tot']; $count = $ans['rows']; for ($i = 0; $i < $count; $i++) { @@ -130,7 +166,7 @@ function doblocks($data, $user) $seq = ''; } else - $seq = $tot--; + $seq = $ans['seq:'.$i]; if ($stat == '1-Confirm') { if (isset($data['info']['lastheight'])) @@ -143,37 +179,34 @@ function doblocks($data, $user) } $stara = ''; - $starp = ''; - if (isset($ans['status:'.($i+1)])) - if ($ans['status:'.($i+1)] == 'Orphan' - && $stat != 'Orphan') - { - $stara = '*'; - $starp = '*'; - } + if ($stat == 'Orphan') + $stara = '*'; $diffacc = $ans['diffacc:'.$i]; $acc = number_format($diffacc, 0); $netdiff = $ans['netdiff:'.$i]; - if ($netdiff > 0) + $diffratio = $ans['diffratio:'.$i]; + $cdf = $ans['cdf:'.$i]; + $luck = $ans['luck:'.$i]; + + if ($diffratio > 0) { - $pct = 100.0 * $diffacc / $netdiff; + $pct = 100.0 * $diffratio; list($fg, $bg) = pctcolour($pct); - $bpct = "$starp".number_format($pct, 2).'%'; + $bpct = "".number_format($pct, 2).'%'; $bg = " bgcolor=$bg"; $blktot += $diffacc; if ($stat != 'Orphan') $nettot += $netdiff; - $cdfv = 1 - exp(-1 * $diffacc / $netdiff); - $cdf = number_format($cdfv, 2); + $cdfdsp = number_format($cdf, 2); } else { $bg = ''; $bpct = '?'; - $cdf = '?'; + $cdfdsp = '?'; } if ($wantcsv === false) @@ -188,7 +221,7 @@ function doblocks($data, $user) $pg .= "".$stat.''; $pg .= "$stara$acc"; $pg .= "$bpct"; - $pg .= "$cdf"; + $pg .= "$cdfdsp"; $pg .= "\n"; } else @@ -208,39 +241,16 @@ function doblocks($data, $user) echo $csv; exit(0); } - if ($nettot > 0) + if ($orph === true) { - 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 .= 'Total:'; - $pg .= ''; - $pg .= "\n"; - if ($orph === true) - { - $pg .= ' #endif +#include +#include + #include "ckpool.h" #include "libckpool.h" @@ -52,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.012" +#define CKDB_VERSION DB_VERSION"-1.020" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -192,6 +195,11 @@ extern POOLSTATUS pool; _dstoff += _srclen; \ } while(0) +#define APPEND_REALLOC_RESET(_buf, _off) do { \ + (_buf)[0] = '\0'; \ + _off = 0; \ + } while(0) + enum data_type { TYPE_STR, TYPE_BIGINT, @@ -1095,6 +1103,22 @@ typedef struct blocks { char statsconfirmed[TXT_FLAG+1]; HISTORYDATECONTROLFIELDS; bool ignore; // Non DB field + + // Calculated only when = 0 + double netdiff; + + /* Non DB fields for the web page + * Calculate them once off/recalc them when required */ + double blockdiffratio; + double blockcdf; + double blockluck; + + /* From the last found block to this one + * Orphans have these set to zero */ + double diffratio; + double diffmean; + double cdferl; + double luck; } BLOCKS; #define ALLOC_BLOCKS 100 @@ -1134,6 +1158,8 @@ extern const char *blocks_unknown; extern K_TREE *blocks_root; extern K_LIST *blocks_free; extern K_STORE *blocks_store; +extern tv_t blocks_stats_time; +extern bool blocks_stats_rebuild; // MININGPAYOUTS typedef struct miningpayouts { @@ -1750,6 +1776,7 @@ extern K_ITEM *find_prev_blocks(int32_t height); extern const char *blocks_confirmed(char *confirmed); extern void zero_on_new_block(); extern void set_block_share_counters(); +extern bool check_update_blocks_stats(tv_t *stats); extern cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_miningpayouts(int64_t payoutid, int64_t userid); extern K_ITEM *first_miningpayouts(int64_t payoutid, K_TREE_CTX *ctx); diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 303be5cd..411507e6 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -811,23 +811,30 @@ 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, *w_item; + K_ITEM *b_item; BLOCKS *blocks; char reply[1024] = ""; char tmp[1024]; - char *buf; + char *buf, *desc, desc_buf[64]; size_t len, off; int32_t height = -1; - tv_t first_cd = {0,0}; - int rows, tot; + tv_t first_cd = {0,0}, stats_tv = {0,0}, stats_tv2 = {0,0}; + int rows, srows, tot, seq; + bool has_stats; LOGDEBUG("%s(): cmd '%s'", __func__, cmd); APPEND_REALLOC_INIT(buf, off, len); APPEND_REALLOC(buf, off, len, "ok."); - rows = 0; + +redo: + K_WLOCK(blocks_free); + has_stats = check_update_blocks_stats(&stats_tv); + K_WUNLOCK(blocks_free); + + srows = rows = 0; K_RLOCK(blocks_free); - b_item = last_in_ktree(blocks_root, ctx); + b_item = first_in_ktree(blocks_root, ctx); tot = 0; while (b_item) { DATA_BLOCKS(blocks, b_item); @@ -835,16 +842,31 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, if (blocks->confirmed[0] != BLOCKS_ORPHAN) tot++; } - b_item = prev_in_ktree(ctx); + b_item = next_in_ktree(ctx); } + seq = tot; b_item = last_in_ktree(blocks_root, ctx); while (b_item && rows < 42) { DATA_BLOCKS(blocks, b_item); + /* For each block remember the initial createdate + * Reverse sort order the oldest expirydate is first + * which should be the 'n' record */ if (height != blocks->height) { height = blocks->height; copy_tv(&first_cd, &(blocks->createdate)); } if (CURRENT(&(blocks->expirydate))) { + if (blocks->confirmed[0] == BLOCKS_ORPHAN) { + snprintf(tmp, sizeof(tmp), + "seq:%d=o%c", + rows, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + } else { + snprintf(tmp, sizeof(tmp), + "seq:%d=%d%c", + rows, seq--, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + } int_to_buf(blocks->height, reply, sizeof(reply)); snprintf(tmp, sizeof(tmp), "height:%d=%s%c", rows, reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); @@ -900,21 +922,21 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, snprintf(tmp, sizeof(tmp), "elapsed:%d=%s%c", rows, reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); - w_item = find_workinfo(blocks->workinfoid, NULL); - 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); + if (has_stats) { + snprintf(tmp, sizeof(tmp), + "netdiff:%d=%.8f%cdiffratio:%d=%.8f%c" + "cdf:%d=%.8f%cluck:%d=%.8f%c", + rows, blocks->netdiff, FLDSEP, + rows, blocks->blockdiffratio, FLDSEP, + rows, blocks->blockcdf, FLDSEP, + rows, blocks->blockluck, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); } else { snprintf(tmp, sizeof(tmp), - "netdiff:%d=?%c", rows, FLDSEP); + "netdiff:%d=?%cdiffratio:%d=?%c" + "cdf:%d=?%cluck:%d=?%c", + rows, FLDSEP, rows, FLDSEP, + rows, FLDSEP, rows, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); } @@ -922,17 +944,81 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id, } b_item = prev_in_ktree(ctx); } + if (has_stats) { + seq = tot; + b_item = last_in_ktree(blocks_root, ctx); + while (b_item) { + DATA_BLOCKS(blocks, b_item); + if (CURRENT(&(blocks->expirydate)) && + blocks->confirmed[0] != BLOCKS_ORPHAN) { + desc = NULL; + if (seq == 1) { + snprintf(desc_buf, sizeof(desc_buf), + "All - Last %d", tot); + desc = desc_buf; + } else if (seq == tot - 4) { + desc = "Last 5"; + } else if (seq == tot - 9) { + desc = "Last 10"; + } else if (seq == tot - 19) { + desc = "Last 20"; + } else if (seq == tot - 41) { + desc = "Last 42"; + } + if (desc) { + snprintf(tmp, sizeof(tmp), + "s_seq:%d=%d%c" + "s_desc:%d=%s%c" + "s_diffratio:%d=%.8f%c" + "s_diffmean:%d=%.8f%c" + "s_cdferl:%d=%.8f%c" + "s_luck:%d=%.8f%c", + srows, seq, FLDSEP, + srows, desc, FLDSEP, + srows, blocks->diffratio, FLDSEP, + srows, blocks->diffmean, FLDSEP, + srows, blocks->cdferl, FLDSEP, + srows, blocks->luck, FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + srows++; + } + seq--; + } + b_item = prev_in_ktree(ctx); + } + copy_tv(&stats_tv2, &blocks_stats_time); + } K_RUNLOCK(blocks_free); + + // Only check for a redo if we used the stats values + if (has_stats) { + /* If the stats changed then redo with the new corrected values + * This isn't likely at all, but it guarantees the blocks + * page shows correct information since any code that wants + * to modify the blocks table must have it under write lock + * then flag the stats as needing to be recalculated */ + if (!tv_equal(&stats_tv, &stats_tv2)) { + APPEND_REALLOC_RESET(buf, off); + goto redo; + } + } + + snprintf(tmp, sizeof(tmp), + "s_rows=%d%cs_flds=%s%c", + srows, FLDSEP, + "s_seq,s_desc,s_diffratio,s_diffmean,s_cdferl,s_luck", + FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), - "tot=%d%crows=%d%cflds=%s%c", - tot, FLDSEP, + "rows=%d%cflds=%s%c", rows, FLDSEP, - "height,blockhash,nonce,reward,workername,firstcreatedate," + "seq,height,blockhash,nonce,reward,workername,firstcreatedate," "createdate,status,diffacc,diffinv,shareacc,shareinv,elapsed," - "netdiff", FLDSEP); + "netdiff,diffratio,cdf,luck", FLDSEP); APPEND_REALLOC(buf, off, len, tmp); - snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks", FLDSEP, ""); + snprintf(tmp, sizeof(tmp), "arn=%s%carp=%s", "Blocks,BlockStats", FLDSEP, ",s"); APPEND_REALLOC(buf, off, len, tmp); LOGDEBUG("%s.ok.%d_blocks", id, rows); diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 3878f342..5d9907f6 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -2399,6 +2399,114 @@ void set_block_share_counters() LOGWARNING("%s(): Update block counters complete", __func__); } +/* Must be under K_WLOCK(blocks_free) when called + * Call this before using the block stats and again check (under lock) + * the blocks_stats_time didn't change after you finish processing + * If it has changed, redo the processing from scratch + * If return is false, then stats aren't available + * TODO: consider storing the partial calculations in the BLOCKS structure + * and only recalc from the last block modified (remembered) + * Will be useful with a large block history */ +bool check_update_blocks_stats(tv_t *stats) +{ + static int64_t last_missing_workinfoid = 0; + static tv_t last_message = { 0L, 0L }; + K_TREE_CTX ctx[1]; + K_ITEM *b_item, *w_item; + WORKINFO *workinfo; + BLOCKS *blocks; + char ndiffbin[TXT_SML+1]; + double ok, diffacc, netsumm, diffmean, pending; + tv_t now; + + /* Wait for startup_complete rather than db_load_complete + * This avoids doing a 'long' lock stats update while reloading */ + if (!startup_complete) + return false; + + if (blocks_stats_rebuild) { + ok = diffacc = netsumm = diffmean = pending = 0.0; + b_item = last_in_ktree(blocks_root, ctx); + while (b_item) { + DATA_BLOCKS(blocks, b_item); + if (CURRENT(&(blocks->expirydate))) { + if (blocks->netdiff == 0) { + // Deadlock alert + K_RLOCK(workinfo_free); + w_item = find_workinfo(blocks->workinfoid, NULL); + K_RUNLOCK(workinfo_free); + if (!w_item) { + setnow(&now); + if (!blocks->workinfoid != last_missing_workinfoid || + tvdiff(&now, &last_message) >= 5.0) { + LOGEMERG("%s(): missing block workinfoid %" + PRId32"/%"PRId64"/%s", + __func__, blocks->height, + blocks->workinfoid, + blocks->confirmed); + } + last_missing_workinfoid = blocks->workinfoid; + copy_tv(&last_message, &now); + return false; + } + DATA_WORKINFO(workinfo, w_item); + hex2bin(ndiffbin, workinfo->bits, 4); + blocks->netdiff = diff_from_nbits(ndiffbin); + } + pending += blocks->diffacc; + + /* Stats for each blocks are independent of + * if they are orphans or not */ + if (blocks->netdiff == 0.0) + blocks->blockdiffratio = 0.0; + else + blocks->blockdiffratio = blocks->diffacc / blocks->netdiff; + blocks->blockcdf = 1.0 - exp(-1.0 * blocks->blockdiffratio); + if (blocks->blockdiffratio == 0.0) + blocks->blockluck = 0.0; + else + blocks->blockluck = 1.0 / blocks->blockdiffratio; + + /* Orphans are treated as +diffacc but no block + * i.e. they simply add shares to the later block + * and have running stats set to zero */ + if (blocks->confirmed[0] == BLOCKS_ORPHAN) { + blocks->diffratio = 0.0; + blocks->diffmean = 0.0; + blocks->cdferl = 0.0; + blocks->luck = 0.0; + } else { + ok++; + diffacc += pending; + pending = 0.0; + netsumm += blocks->netdiff; + + if (netsumm == 0.0) + blocks->diffratio = 0.0; + else + blocks->diffratio = diffacc / netsumm; + + diffmean = (diffmean * (ok - 1) + blocks->blockdiffratio) / ok; + blocks->diffmean = diffmean; + + if (diffmean == 0.0) { + blocks->cdferl = 0.0; + blocks->luck = 0.0; + } else { + blocks->cdferl = gsl_cdf_gamma_P(diffmean, ok, 1.0 / ok); + blocks->luck = 1.0 / diffmean; + } + } + } + b_item = prev_in_ktree(ctx); + } + setnow(&blocks_stats_time); + blocks_stats_rebuild = false; + } + copy_tv(stats, &blocks_stats_time); + return true; +} + /* order by payoutid asc,userid asc,expirydate asc * i.e. only one payout amount per block per user */ cmp_t cmp_miningpayouts(K_ITEM *a, K_ITEM *b) diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index 4db4f0ba..91e43fd8 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -3996,9 +3996,13 @@ unparam: blocks_root = remove_from_ktree(blocks_root, old_b_item, cmp_blocks); copy_tv(&(oldblocks->expirydate), cd); blocks_root = add_to_ktree(blocks_root, old_b_item, cmp_blocks); - } + // Copy it over to avoid having to recalculate it + row->netdiff = oldblocks->netdiff; + } else + row->netdiff = 0; blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks); k_add_head(blocks_store, b_item); + blocks_stats_rebuild = true; } K_WUNLOCK(blocks_free); @@ -4300,9 +4304,13 @@ flail: blocks_root = remove_from_ktree(blocks_root, old_b_item, cmp_blocks); copy_tv(&(oldblocks->expirydate), cd); blocks_root = add_to_ktree(blocks_root, old_b_item, cmp_blocks); - } + // Copy it over to avoid having to recalculate it + row->netdiff = oldblocks->netdiff; + } else + row->netdiff = 0; blocks_root = add_to_ktree(blocks_root, b_item, cmp_blocks); k_add_head(blocks_store, b_item); + blocks_stats_rebuild = true; } K_WUNLOCK(blocks_free); From deda01d7581d89e80bf37816d37b468cf3afcd36 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 11 Mar 2015 20:44:58 +1100 Subject: [PATCH 13/36] ckdb - allow payouts to be orphaned --- src/ckdb.h | 6 ++++- src/ckdb_cmd.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/ckdb.h b/src/ckdb.h index 54074dfb..3e02c6e2 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.020" +#define CKDB_VERSION DB_VERSION"-1.021" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -1219,6 +1219,10 @@ extern cklock_t process_pplns_lock; #define PAYOUTS_PROCESSING 'P' #define PAYOUTS_PROCESSING_STR "P" #define PAYPROCESSING(_status) ((_status)[0] == PAYOUTS_PROCESSING) +// An orphaned payout must be ignored +#define PAYOUTS_ORPHAN 'O' +#define PAYOUTS_ORPHAN_STR "O" +#define PAYORPHAN(_status) ((_status)[0] == PAYOUTS_ORPHAN) /* // EVENTLOG diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 411507e6..43741df6 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4272,6 +4272,70 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, copy_tv(&(payouts2->lastshareacc), &(payouts->lastshareacc)); payouts2->stats = strdup(payouts->stats); + ok = payouts_add(conn, true, p2_item, &old_p2_item, + by, code, inet, now, NULL, false); + if (!ok) { + snprintf(reply, siz, "failed payout %"PRId64, payoutid); + return strdup(reply); + } + DATA_PAYOUTS(payouts2, p2_item); + DATA_PAYOUTS(old_payouts2, old_p2_item); + snprintf(msg, sizeof(msg), + "payout %"PRId64" changed from '%s' to '%s' for" + "%"PRId32"/%s", + payoutid, old_payouts2->status, payouts2->status, + payouts2->height, payouts2->blockhash); + } else if (strcasecmp(action, "orphan") == 0) { + /* Change the status of a generated payout to orphaned + * Require payoutid + * Use this if the orphan process didn't automatically + * update a generated payout to orphaned + * TODO: get orphaned blocks to automatically do this */ + i_payoutid = require_name(trf_root, "payoutid", 1, + (char *)intpatt, reply, siz); + if (!i_payoutid) + return strdup(reply); + TXT_TO_BIGINT("payoutid", transfer_data(i_payoutid), payoutid); + + K_WLOCK(payouts_free); + p_item = find_payoutid(payoutid); + if (!p_item) { + K_WUNLOCK(payouts_free); + snprintf(reply, siz, + "no payout with id %"PRId64, payoutid); + return strdup(reply); + } + DATA_PAYOUTS(payouts, p_item); + if (!PAYGENERATED(payouts->status)) { + K_WUNLOCK(payouts_free); + snprintf(reply, siz, + "status !generated (%s) for payout %"PRId64, + payouts->status, payoutid); + return strdup(reply); + } + p2_item = k_unlink_head(payouts_free); + K_WUNLOCK(payouts_free); + + /* There is a risk of the p_item changing while it's unlocked, + * but since this is a manual interface it's not really likely + * and there'll be an error if something goes wrong + * It reports the old and new status */ + DATA_PAYOUTS(payouts2, p2_item); + bzero(payouts2, sizeof(*payouts2)); + payouts2->payoutid = payouts->payoutid; + payouts2->height = payouts->height; + STRNCPY(payouts2->blockhash, payouts->blockhash); + payouts2->minerreward = payouts->minerreward; + payouts2->workinfoidstart = payouts->workinfoidstart; + payouts2->workinfoidend = payouts->workinfoidend; + payouts2->elapsed = payouts->elapsed; + STRNCPY(payouts2->status, PAYOUTS_ORPHAN_STR); + payouts2->diffwanted = payouts->diffwanted; + payouts2->diffused = payouts->diffused; + payouts2->shareacc = payouts->shareacc; + copy_tv(&(payouts2->lastshareacc), &(payouts->lastshareacc)); + payouts2->stats = strdup(payouts->stats); + ok = payouts_add(conn, true, p2_item, &old_p2_item, by, code, inet, now, NULL, false); if (!ok) { From c754f1b06ddf831c6eb87563941f1ba87e981a28 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 11 Mar 2015 21:48:08 +1100 Subject: [PATCH 14/36] ckdb/php - add block B marks after the shift php shift names --- html/BTCSym.png | Bin 0 -> 387 bytes pool/page_shifts.php | 18 ++++++++++++++++-- src/ckdb.h | 2 +- src/ckdb_cmd.c | 22 +++++++++++++++++++++- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 html/BTCSym.png diff --git a/html/BTCSym.png b/html/BTCSym.png new file mode 100644 index 0000000000000000000000000000000000000000..7e2114c294e1f25a97eb325214c216ae88ae1d48 GIT binary patch literal 387 zcmV-}0et?6P)6dx00009a7bBm000XU z000XU0RWnu7ytkO2XskIMF-yl2LuZq>p2QX0003ZNklRz4u$a zZehQ;qG(7@N)U8&)1@fqMu%{Baj+>z9sLj5ghuyhb8w4j$RD6f@+49*3whU`@7~*R zdD0orf%7ZUL*kyhDv@(--5yz^-y`!DoqOwx2TD1_U|8_eElpQOoGSGj?%8G@+t6{T zlq(%r@zgUJiC|Fh-4ji}E&JxB=ML>^xCl}~X~$>NPP`YJG;2gGkp{O_2om&}Ghx;r zpHwP0!*zGKZ$XM5+V!qj@t@rC%4_S!tVtw_SS~`L0)_ZO literal 0 HcmV?d00001 diff --git a/pool/page_shifts.php b/pool/page_shifts.php index 1092482f..1230d380 100644 --- a/pool/page_shifts.php +++ b/pool/page_shifts.php @@ -28,8 +28,22 @@ function doshifts($data, $user) $row = 'odd'; $pg .= ""; - $shif = preg_replace(array('/^.* to /','/^.*fin: /'), '', $ans['shift:'.$i]); - $pg .= "$shif"; + $shifname = $ans['shift:'.$i]; + $shif = preg_replace(array('/^.* to /','/^.*fin: /'), '', $shifname); + $ablock = false; + if (preg_match('/to.*Block.* fin/', $shifname) === true) + $ablock = true; + else + { + $shifex = $ans['endmarkextra:'.$i]; + if (preg_match('/Block .* fin/', $shifex) === true) + $ablock = true; + } + if ($ablock === true) + $btc = ' '; + else + $btc = ''; + $pg .= "$shif$btc"; $start = $ans['start:'.$i]; $pg .= ''.utcd($start).''; $nd = $ans['end:'.$i]; diff --git a/src/ckdb.h b/src/ckdb.h index 3e02c6e2..e59f475a 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.021" +#define CKDB_VERSION DB_VERSION"-1.022" #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 43741df6..b61c0595 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4543,12 +4543,13 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, __maybe_unused tv_t *notcd, __maybe_unused K_TREE *trf_root) { - K_ITEM *i_username, *u_item, ms_look, *wm_item, *ms_item, *wi_item; + K_ITEM *i_username, *u_item, *m_item, ms_look, *wm_item, *ms_item, *wi_item; K_TREE_CTX wm_ctx[1], ms_ctx[1]; WORKMARKERS *wm; WORKINFO *wi; MARKERSUMMARY markersummary, *ms, ms_add; USERS *users; + MARKS *marks = NULL; char reply[1024] = ""; char tmp[1024]; size_t siz = sizeof(reply); @@ -4584,6 +4585,19 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, if (CURRENT(&(wm->expirydate)) && WMPROCESSED(wm->status)) { K_RUNLOCK(workmarkers_free); + K_RLOCK(marks_free); + m_item = find_marks(wm->workinfoidend); + K_RUNLOCK(marks_free); + DATA_MARKS_NULL(marks, m_item); + if (m_item == NULL) { + // Log it but keep going + LOGERR("%s() missing mark for markerid " + "%"PRId64"/%s widend %"PRId64, + __func__, wm->markerid, + wm->description, + wm->workinfoidend); + } + bzero(&ms_add, sizeof(ms_add)); markersummary.markerid = wm->markerid; @@ -4652,6 +4666,12 @@ static char *cmd_shifts(__maybe_unused PGconn *conn, char *cmd, char *id, rows, reply, FLDSEP); APPEND_REALLOC(buf, off, len, tmp); + snprintf(tmp, sizeof(tmp), "endmarkextra:%d=%s%c", + rows, + m_item ? marks->extra : EMPTY, + FLDSEP); + APPEND_REALLOC(buf, off, len, tmp); + ftv_to_buf(&(wi->createdate), reply, sizeof(reply)); snprintf(tmp, sizeof(tmp), "start:%d=%s%c", rows, reply, FLDSEP); From 0e27bd2d47e7ae268b2fddfc3dc4e7fd4b8a3532 Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 11 Mar 2015 23:13:39 +1100 Subject: [PATCH 15/36] php - correct shift php --- pool/page_shifts.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pool/page_shifts.php b/pool/page_shifts.php index 1230d380..b83d3ec6 100644 --- a/pool/page_shifts.php +++ b/pool/page_shifts.php @@ -31,12 +31,12 @@ function doshifts($data, $user) $shifname = $ans['shift:'.$i]; $shif = preg_replace(array('/^.* to /','/^.*fin: /'), '', $shifname); $ablock = false; - if (preg_match('/to.*Block.* fin/', $shifname) === true) + if (preg_match('/to.*Block.* fin/', $shifname) == 1) $ablock = true; else { $shifex = $ans['endmarkextra:'.$i]; - if (preg_match('/Block .* fin/', $shifex) === true) + if (preg_match('/Block .* fin/', $shifex) == 1) $ablock = true; } if ($ablock === true) From 8e324f0ba534dcb94b4442a1cd5132d9b8132d8a Mon Sep 17 00:00:00 2001 From: kanoi Date: Wed, 11 Mar 2015 23:26:23 +1100 Subject: [PATCH 16/36] ckdb - add message spacing --- src/ckdb_cmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index b61c0595..8dbc872b 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -4281,7 +4281,7 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, DATA_PAYOUTS(payouts2, p2_item); DATA_PAYOUTS(old_payouts2, old_p2_item); snprintf(msg, sizeof(msg), - "payout %"PRId64" changed from '%s' to '%s' for" + "payout %"PRId64" changed from '%s' to '%s' for " "%"PRId32"/%s", payoutid, old_payouts2->status, payouts2->status, payouts2->height, payouts2->blockhash); @@ -4345,7 +4345,7 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now, DATA_PAYOUTS(payouts2, p2_item); DATA_PAYOUTS(old_payouts2, old_p2_item); snprintf(msg, sizeof(msg), - "payout %"PRId64" changed from '%s' to '%s' for" + "payout %"PRId64" changed from '%s' to '%s' for " "%"PRId32"/%s", payoutid, old_payouts2->status, payouts2->status, payouts2->height, payouts2->blockhash); From 09a5de8e2cda85edbbe18f33b536a37f1b92409a Mon Sep 17 00:00:00 2001 From: kanoi Date: Thu, 12 Mar 2015 16:24:07 +1100 Subject: [PATCH 17/36] ckdb - correct orphan diff redistribution --- src/ckdb.h | 6 +++++- src/ckdb_cmd.c | 10 ++++++---- src/ckdb_data.c | 29 +++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/ckdb.h b/src/ckdb.h index e59f475a..ecddeebc 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.0" -#define CKDB_VERSION DB_VERSION"-1.022" +#define CKDB_VERSION DB_VERSION"-1.023" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -1113,6 +1113,10 @@ typedef struct blocks { double blockcdf; double blockluck; + /* diffacc for range calculations - includes orphans before it + * orphans have this set to 0 so they can't be double counted */ + double diffcalc; + /* From the last found block to this one * Orphans have these set to zero */ double diffratio; diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index 8dbc872b..80b1f9d1 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -960,10 +960,12 @@ redo: desc = "Last 5"; } else if (seq == tot - 9) { desc = "Last 10"; - } else if (seq == tot - 19) { - desc = "Last 20"; - } else if (seq == tot - 41) { - desc = "Last 42"; + } else if (seq == tot - 24) { + desc = "Last 25"; + } else if (seq == tot - 49) { + desc = "Last 50"; + } else if (seq == tot - 99) { + desc = "Last 100"; } if (desc) { snprintf(tmp, sizeof(tmp), diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 5d9907f6..a4227e7e 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -2425,7 +2425,26 @@ bool check_update_blocks_stats(tv_t *stats) return false; if (blocks_stats_rebuild) { - ok = diffacc = netsumm = diffmean = pending = 0.0; + /* Have to first work out the diffcalc for each block + * Orphans count towards the next valid block after the orphan + * so this has to be done in the reverse order of the range + * calculations */ + pending = 0.0; + b_item = first_in_ktree(blocks_root, ctx); + while (b_item) { + DATA_BLOCKS(blocks, b_item); + if (CURRENT(&(blocks->expirydate))) { + pending += blocks->diffacc; + if (blocks->confirmed[0] == BLOCKS_ORPHAN) + blocks->diffcalc = 0.0; + else { + blocks->diffcalc = pending; + pending = 0.0; + } + } + b_item = next_in_ktree(ctx); + } + ok = diffacc = netsumm = diffmean = 0.0; b_item = last_in_ktree(blocks_root, ctx); while (b_item) { DATA_BLOCKS(blocks, b_item); @@ -2453,8 +2472,6 @@ bool check_update_blocks_stats(tv_t *stats) hex2bin(ndiffbin, workinfo->bits, 4); blocks->netdiff = diff_from_nbits(ndiffbin); } - pending += blocks->diffacc; - /* Stats for each blocks are independent of * if they are orphans or not */ if (blocks->netdiff == 0.0) @@ -2477,8 +2494,7 @@ bool check_update_blocks_stats(tv_t *stats) blocks->luck = 0.0; } else { ok++; - diffacc += pending; - pending = 0.0; + diffacc += blocks->diffcalc; netsumm += blocks->netdiff; if (netsumm == 0.0) @@ -2486,7 +2502,8 @@ bool check_update_blocks_stats(tv_t *stats) else blocks->diffratio = diffacc / netsumm; - diffmean = (diffmean * (ok - 1) + blocks->blockdiffratio) / ok; + diffmean = ((diffmean * (ok - 1)) + + (blocks->diffcalc / blocks->netdiff)) / ok; blocks->diffmean = diffmean; if (diffmean == 0.0) { From 7283af34e542beb15c09784eae489712059fc189 Mon Sep 17 00:00:00 2001 From: kanoi Date: Thu, 12 Mar 2015 18:47:27 +1100 Subject: [PATCH 18/36] php - add a login failure message --- pool/base.php | 22 +++++++++++++++++----- pool/page.php | 4 +++- pool/prime.php | 3 +++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/pool/base.php b/pool/base.php index 5b24c4ab..a109a23c 100644 --- a/pool/base.php +++ b/pool/base.php @@ -334,7 +334,9 @@ function validUserPass($user, $pass) $key = 'ckp'.rand(1000000,9999999); $_SESSION['ckpkey'] = $key; $_SESSION[$key] = array('who' => $user, 'id' => $user); + return true; } + return false; } # function logout() @@ -364,6 +366,8 @@ function requestRegister() # function tryLogInOut() { + global $loginfailed; + // If already logged in, it will ignore User/Pass if (isset($_SESSION['ckpkey'])) { @@ -373,21 +377,29 @@ function tryLogInOut() } else { + $login = getparam('Login', false); + if (nuem($login)) + return; + $user = getparam('User', false); if ($user !== NULL) $user = loginStr($user); if (nuem($user)) + { + $loginfailed = true; return; + } $pass = getparam('Pass', false); if (nuem($pass)) + { + $loginfailed = true; return; + } - $login = getparam('Login', false); - if (nuem($login)) - return; - - validUserPass($user, $pass); + $valid = validUserPass($user, $pass); + if (!$valid) + $loginfailed = true; } } # diff --git a/pool/page.php b/pool/page.php index e4ec64dd..4ecccb6c 100644 --- a/pool/page.php +++ b/pool/page.php @@ -163,7 +163,7 @@ h1 {margin-top: 20px; float:middle; font-size: 20px;} # function pgtop($info, $dotop, $user, $douser) { - global $site_title; + global $site_title, $loginfailed; $phr = '?THs'; $plb = '?'; @@ -288,6 +288,8 @@ function pgtop($info, $dotop, $user, $douser) $top .= " You need to enable javascript to use"; $top .= " the $site_title web site."; + if ($loginfailed === true) + $top .= '
Login Failed
'; if (isset($info['u_nopayaddr'])) $top .= '
Please set a payout address on your account!
'; if (isset($info['u_noemail'])) diff --git a/pool/prime.php b/pool/prime.php index 539ef33b..6ee31cfb 100644 --- a/pool/prime.php +++ b/pool/prime.php @@ -3,6 +3,9 @@ global $stt; $stt = microtime(); # +global $loginfailed; +$loginfailed = false; +# include_once('param.php'); include_once('base.php'); # From 92dacd8513b259cdec44406ab96652f06dd2f90c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 21:10:24 +1100 Subject: [PATCH 19/36] Avoid cute locking --- src/stratifier.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 97fb1083..2116cde4 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1166,19 +1166,15 @@ static stratum_instance_t *ref_instance_by_id(sdata_t *sdata, const int64_t id) { stratum_instance_t *client; - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); client = __instance_by_id(sdata, id); if (client) { if (unlikely(client->dropped)) client = NULL; - else { - /* Upgrade to write lock to modify client refcount */ - ck_ulock(&sdata->instance_lock); + else __inc_instance_ref(client); - ck_dwilock(&sdata->instance_lock); - } } - ck_uilock(&sdata->instance_lock); + ck_wunlock(&sdata->instance_lock); return client; } @@ -1307,7 +1303,7 @@ static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessio /* Number is in BE but we don't swap either of them */ hex2bin(&enonce1_64, sessionid, slen); - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); HASH_ITER(hh, sdata->stratum_instances, client, tmp) { if (client->id == id) continue; @@ -1322,16 +1318,12 @@ static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessio /* Delete the entry once we are going to use it since there * will be a new instance with the enonce1_64 */ old_id = client->id; - - /* Upgrade to write lock to disconnect */ - ck_ulock(&sdata->instance_lock); __del_disconnected(sdata, client); - ck_dwilock(&sdata->instance_lock); ret = enonce1_64; } out_unlock: - ck_uilock(&sdata->instance_lock); + ck_wunlock(&sdata->instance_lock); out: if (ret) LOGNOTICE("Reconnecting old instance %"PRId64" to instance %"PRId64, old_id, id); @@ -1431,10 +1423,8 @@ static void drop_client(sdata_t *sdata, const int64_t id) LOGINFO("Stratifier asked to drop client %"PRId64, id); - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); client = __instance_by_id(sdata, id); - /* Upgrade to write lock */ - ck_ulock(&sdata->instance_lock); if (client && !client->dropped) { user = client->user_instance; ckp = client->ckp; @@ -2207,10 +2197,8 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, if (unlikely(len > 127)) username[127] = '\0'; - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); HASH_FIND_STR(sdata->user_instances, username, user); - /* Upgrade to write lock */ - ck_ulock(&sdata->instance_lock); if (!user) { /* New user instance. Secondary user id will be NULL */ user = ckzalloc(sizeof(user_instance_t)); @@ -3493,10 +3481,8 @@ static void srecv_process(ckpool_t *ckp, char *buf) json_object_clear(val); /* Parse the message here */ - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); client = __instance_by_id(sdata, msg->client_id); - /* Upgrade to write lock */ - ck_ulock(&sdata->instance_lock); /* If client_id instance doesn't exist yet, create one */ if (unlikely(!client)) { if (likely(!__dropped_instance(sdata, msg->client_id))) { @@ -3589,20 +3575,17 @@ static stratum_instance_t *preauth_ref_instance_by_id(sdata_t *sdata, const int6 { stratum_instance_t *client; - ck_ilock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); client = __instance_by_id(sdata, id); if (client) { if (client->dropped || client->authorising || client->authorised) client = NULL; else { - /* Upgrade to write lock to modify client data */ - ck_ulock(&sdata->instance_lock); __inc_instance_ref(client); client->authorising = true; - ck_dwilock(&sdata->instance_lock); } } - ck_uilock(&sdata->instance_lock); + ck_wunlock(&sdata->instance_lock); return client; } From 4c97df787d5e207fe83e41feddee5d59345854b1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 21:13:47 +1100 Subject: [PATCH 20/36] Remove use of upgradeable locks in connector --- src/connector.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/connector.c b/src/connector.c index f6d9f1ab..92665bed 100644 --- a/src/connector.c +++ b/src/connector.c @@ -214,12 +214,11 @@ static int drop_client(cdata_t *cdata, client_instance_t *client) int64_t client_id = 0; int fd; - ck_ilock(&cdata->lock); + ck_wlock(&cdata->lock); fd = client->fd; if (fd != -1) { client_id = client->id; - ck_ulock(&cdata->lock); Close(client->fd); HASH_DEL(cdata->clients, client); DL_APPEND(cdata->dead_clients, client); @@ -227,9 +226,8 @@ static int drop_client(cdata_t *cdata, client_instance_t *client) * epoll list. */ __dec_instance_ref(client); cdata->dead_generated++; - ck_dwilock(&cdata->lock); } - ck_uilock(&cdata->lock); + ck_wunlock(&cdata->lock); if (fd > -1) LOGINFO("Connector dropped client %"PRId64" fd %d", client_id, fd); @@ -575,17 +573,15 @@ static void send_client(cdata_t *cdata, int64_t id, char *buf) return; } - ck_ilock(&cdata->lock); + ck_wlock(&cdata->lock); HASH_FIND_I64(cdata->clients, &id, client); if (likely(client)) { fd = client->fd; /* Grab a reference to this client until the sender_send has * completed processing. */ - ck_ulock(&cdata->lock); __inc_instance_ref(client); - ck_dwilock(&cdata->lock); } - ck_uilock(&cdata->lock); + ck_wunlock(&cdata->lock); if (unlikely(fd == -1)) { ckpool_t *ckp = cdata->ckp; @@ -617,14 +613,11 @@ static client_instance_t *ref_client_by_id(cdata_t *cdata, int64_t id) { client_instance_t *client; - ck_ilock(&cdata->lock); + ck_wlock(&cdata->lock); HASH_FIND_I64(cdata->clients, &id, client); - if (client) { - ck_ulock(&cdata->lock); + if (client) __inc_instance_ref(client); - ck_dwilock(&cdata->lock); - } - ck_uilock(&cdata->lock); + ck_wunlock(&cdata->lock); return client; } From 431234a3d6c39f41c75ba0a26f4d09a854bf8fdf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 21:14:28 +1100 Subject: [PATCH 21/36] Remove option of using precarious intermediate variants of cklocks --- src/libckpool.c | 26 -------------------------- src/libckpool.h | 4 ---- 2 files changed, 30 deletions(-) diff --git a/src/libckpool.c b/src/libckpool.c index 7fc3017b..f20a8803 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -337,25 +337,6 @@ void _ck_rlock(cklock_t *lock, const char *file, const char *func, const int lin _mutex_unlock(&lock->mutex, file, func, line); } -/* Intermediate variant of cklock - behaves as a read lock but can be promoted - * to a write lock or demoted to read lock. */ -void _ck_ilock(cklock_t *lock, const char *file, const char *func, const int line) -{ - _mutex_lock(&lock->mutex, file, func, line); -} - -/* Unlock intermediate variant without changing to read or write version */ -void _ck_uilock(cklock_t *lock, const char *file, const char *func, const int line) -{ - _mutex_unlock(&lock->mutex, file, func, line); -} - -/* Upgrade intermediate variant to a write lock */ -void _ck_ulock(cklock_t *lock, const char *file, const char *func, const int line) -{ - _wr_lock(&lock->rwlock, file, func, line); -} - /* Write lock variant of cklock */ void _ck_wlock(cklock_t *lock, const char *file, const char *func, const int line) { @@ -377,13 +358,6 @@ void _ck_dwilock(cklock_t *lock, const char *file, const char *func, const int l _wr_unlock(&lock->rwlock, file, func, line); } -/* Downgrade intermediate variant to a read lock */ -void _ck_dlock(cklock_t *lock, const char *file, const char *func, const int line) -{ - _rd_lock(&lock->rwlock, file, func, line); - _mutex_unlock(&lock->mutex, file, func, line); -} - void _ck_runlock(cklock_t *lock, const char *file, const char *func, const int line) { _rd_unlock(&lock->rwlock, file, func, line); diff --git a/src/libckpool.h b/src/libckpool.h index 79f0f8fd..28ea14c9 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -166,12 +166,8 @@ static inline void flip_80(void *dest_p, const void *src_p) #define cklock_init(_lock) _cklock_init(_lock, __FILE__, __func__, __LINE__) #define ck_rlock(_lock) _ck_rlock(_lock, __FILE__, __func__, __LINE__) -#define ck_ilock(_lock) _ck_ilock(_lock, __FILE__, __func__, __LINE__) -#define ck_uilock(_lock) _ck_uilock(_lock, __FILE__, __func__, __LINE__) -#define ck_ulock(_lock) _ck_ulock(_lock, __FILE__, __func__, __LINE__) #define ck_wlock(_lock) _ck_wlock(_lock, __FILE__, __func__, __LINE__) #define ck_dwlock(_lock) _ck_dwlock(_lock, __FILE__, __func__, __LINE__) -#define ck_dwilock(_lock) _ck_dwilock(_lock, __FILE__, __func__, __LINE__) #define ck_dlock(_lock) _ck_dlock(_lock, __FILE__, __func__, __LINE__) #define ck_runlock(_lock) _ck_runlock(_lock, __FILE__, __func__, __LINE__) #define ck_wunlock(_lock) _ck_wunlock(_lock, __FILE__, __func__, __LINE__) From 9706b52965b71c2c349e5d37a68eb2625db1e121 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 21:40:24 +1100 Subject: [PATCH 22/36] Recycle used client structs instead of freeing them --- src/stratifier.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 2116cde4..8d72e98a 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -326,6 +326,7 @@ struct stratifier_data { * is sorted by enonce1_64. */ stratum_instance_t *stratum_instances; stratum_instance_t *disconnected_instances; + stratum_instance_t *recycled_instances; int stratum_generated; int disconnected_generated; @@ -905,18 +906,21 @@ static void update_base(ckpool_t *ckp, const int prio) create_pthread(pth, do_update, ur); } -static void __kill_instance(stratum_instance_t *client) +/* Instead of removing the client instance, we add it to a list of recycled + * clients allowing us to reuse it instead of callocing a new one */ +static void __kill_instance(sdata_t *sdata, stratum_instance_t *client) { free(client->workername); free(client->useragent); - free(client); + memset(client, 0, sizeof(stratum_instance_t)); + DL_APPEND(sdata->recycled_instances, client); } static void __del_disconnected(sdata_t *sdata, stratum_instance_t *client) { HASH_DEL(sdata->disconnected_instances, client); sdata->stats.disconnected--; - __kill_instance(client); + __kill_instance(sdata, client); } /* Removes a client instance we know is on the stratum_instances list and from @@ -941,7 +945,7 @@ static void drop_allclients(ckpool_t *ckp) if (!client->ref) { __del_client(sdata, client, client->user_instance); - __kill_instance(client); + __kill_instance(sdata, client); } else client->dropped = true; kills++; @@ -1215,7 +1219,7 @@ static int __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instan ret = 2; else ret = 3; - __kill_instance(client); + __kill_instance(sdata, client); } return ret; } @@ -1268,13 +1272,28 @@ static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *client, const #define dec_instance_ref(sdata, instance) _dec_instance_ref(sdata, instance, __FILE__, __func__, __LINE__) +/* If we have a no longer used stratum instance in the recycled linked list, + * use that, otherwise calloc a fresh one. */ +static stratum_instance_t *__recruit_stratum_instance(sdata_t *sdata) +{ + stratum_instance_t *client = sdata->recycled_instances; + + if (client) + DL_DELETE(sdata->recycled_instances, client); + else { + client = ckzalloc(sizeof(stratum_instance_t)); + sdata->stratum_generated++; + } + return client; +} + /* Enter with write instance_lock held */ static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t id, const int server) { - stratum_instance_t *client = ckzalloc(sizeof(stratum_instance_t)); + stratum_instance_t *client; sdata_t *sdata = ckp->data; - sdata->stratum_generated++; + client = __recruit_stratum_instance(sdata); client->id = id; client->server = server; client->diff = client->old_diff = ckp->startdiff; From 0c61ed1c09fc71a59dbdbb621b88463e289c6da8 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 21:59:37 +1100 Subject: [PATCH 23/36] Make worker count more robust by using the same locking for stats --- src/stratifier.c | 59 ++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 8d72e98a..e4f22fcb 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -923,13 +923,31 @@ static void __del_disconnected(sdata_t *sdata, stratum_instance_t *client) __kill_instance(sdata, client); } +/* Called with instance_lock held. Note stats.users is protected by + * instance lock to avoid recursive locking. */ +static void __inc_worker(sdata_t *sdata, user_instance_t *instance) +{ + sdata->stats.workers++; + if (!instance->workers++) + sdata->stats.users++; +} + +static void __dec_worker(sdata_t *sdata, user_instance_t *instance) +{ + sdata->stats.workers--; + if (!--instance->workers) + sdata->stats.users--; +} + /* Removes a client instance we know is on the stratum_instances list and from * the user client list if it's been placed on it */ static void __del_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *user) { HASH_DEL(sdata->stratum_instances, client); - if (user) + if (user) { DL_DELETE(user->clients, client); + __dec_worker(sdata, user); + } } static void drop_allclients(ckpool_t *ckp) @@ -1241,15 +1259,12 @@ static void client_drop_message(const int64_t client_id, const int dropped, cons } } -static void dec_worker(ckpool_t *ckp, user_instance_t *instance); - /* Decrease the reference count of instance. */ static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *client, const char *file, const char *func, const int line) { user_instance_t *user = client->user_instance; int64_t client_id = client->id; - ckpool_t *ckp = client->ckp; int dropped = 0, ref; ck_wlock(&sdata->instance_lock); @@ -1265,9 +1280,6 @@ static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *client, const /* This should never happen */ if (unlikely(ref < 0)) LOGERR("Instance ref count dropped below zero from %s %s:%d", file, func, line); - - if (dropped && user) - dec_worker(ckp, user); } #define dec_instance_ref(sdata, instance) _dec_instance_ref(sdata, instance, __FILE__, __func__, __LINE__) @@ -1410,35 +1422,12 @@ static void stratum_add_send(sdata_t *sdata, json_t *val, const int64_t client_i ckmsgq_add(sdata->ssends, msg); } -static void inc_worker(ckpool_t *ckp, user_instance_t *instance) -{ - sdata_t *sdata = ckp->data; - - mutex_lock(&sdata->stats_lock); - sdata->stats.workers++; - if (!instance->workers++) - sdata->stats.users++; - mutex_unlock(&sdata->stats_lock); -} - -static void dec_worker(ckpool_t *ckp, user_instance_t *instance) -{ - sdata_t *sdata = ckp->data; - - mutex_lock(&sdata->stats_lock); - sdata->stats.workers--; - if (!--instance->workers) - sdata->stats.users--; - mutex_unlock(&sdata->stats_lock); -} - static void drop_client(sdata_t *sdata, const int64_t id) { stratum_instance_t *client, *tmp; user_instance_t *user = NULL; int dropped = 0, aged = 0; time_t now_t = time(NULL); - ckpool_t *ckp = NULL; LOGINFO("Stratifier asked to drop client %"PRId64, id); @@ -1446,7 +1435,6 @@ static void drop_client(sdata_t *sdata, const int64_t id) client = __instance_by_id(sdata, id); if (client && !client->dropped) { user = client->user_instance; - ckp = client->ckp; /* If the client is still holding a reference, don't drop them * now but wait till the reference is dropped */ if (!client->ref) @@ -1469,11 +1457,6 @@ static void drop_client(sdata_t *sdata, const int64_t id) client_drop_message(id, dropped, false); if (aged) LOGINFO("Aged %d disconnected instances to dead", aged); - - /* Decrease worker count outside of instance_lock to avoid recursive - * locking */ - if (user) - dec_worker(ckp, user); } static void stratum_broadcast_message(sdata_t *sdata, const char *msg) @@ -2247,6 +2230,7 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, client->worker_instance = worker; } DL_APPEND(user->clients, client); + __inc_worker(sdata,user); ck_wunlock(&sdata->instance_lock); if (CKP_STANDALONE(ckp) && new_user) @@ -2459,9 +2443,6 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ goto out; } } - /* NOTE worker count incremented here for any client put onto user's - * list until it's dropped */ - inc_worker(ckp, user); if (CKP_STANDALONE(ckp)) ret = true; else { From d4cd88ac585dd7cf4900b022f7678f1bae975fba Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Sat, 28 Feb 2015 11:53:48 +1100 Subject: [PATCH 24/36] Add helper functions for storing messages to be dumped outside of other locks --- src/stratifier.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/stratifier.c b/src/stratifier.c index e4f22fcb..bd34bcbc 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -404,6 +404,29 @@ static const char *ckdb_ids[] = { "heartbeat" }; +/* For storing a set of messages within another lock, allowing us to dump them + * to the log outside of lock */ +static void add_msg_entry(char_entry_t **entries, char **buf) +{ + char_entry_t *entry = ckalloc(sizeof(char_entry_t)); + + entry->buf = *buf; + *buf = NULL; + DL_APPEND(*entries, entry); +} + +static void notice_msg_entries(char_entry_t **entries) +{ + char_entry_t *entry, *tmpentry; + + DL_FOREACH_SAFE(*entries, entry, tmpentry) { + DL_DELETE(*entries, entry); + LOGNOTICE("%s", entry->buf); + free(entry->buf); + free(entry); + } +} + static void generate_coinbase(const ckpool_t *ckp, workbase_t *wb) { uint64_t *u64, g64, d64 = 0; From 8b434661d72471bd8df936362f6ae29ac59e3c0c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 22:18:52 +1100 Subject: [PATCH 25/36] Add more verbose information to drop client messages using add_msg_entry --- src/stratifier.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index bd34bcbc..5f2fa039 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1448,9 +1448,11 @@ static void stratum_add_send(sdata_t *sdata, json_t *val, const int64_t client_i static void drop_client(sdata_t *sdata, const int64_t id) { stratum_instance_t *client, *tmp; + char_entry_t *entries = NULL; user_instance_t *user = NULL; int dropped = 0, aged = 0; time_t now_t = time(NULL); + char *msg; LOGINFO("Stratifier asked to drop client %"PRId64, id); @@ -1460,9 +1462,27 @@ static void drop_client(sdata_t *sdata, const int64_t id) user = client->user_instance; /* If the client is still holding a reference, don't drop them * now but wait till the reference is dropped */ - if (!client->ref) + if (!client->ref) { dropped = __drop_client(sdata, client, user); - else + switch(dropped) { + case 0: + ASPRINTF(&msg, "Unknown client %"PRId64" drop", id); + break; + case 1: + ASPRINTF(&msg, "Client %"PRId64" user %s worker %s disconnected", + id, user->username, client->workername); + break; + case 2: + ASPRINTF(&msg, "Client %"PRId64" user %s worker %s dropped", + id, user->username, client->workername); + break; + case 3: + ASPRINTF(&msg, "Workerless client %"PRId64" dropped", + id); + break; + } + add_msg_entry(&entries, &msg); + } else client->dropped = true; } @@ -1477,7 +1497,7 @@ static void drop_client(sdata_t *sdata, const int64_t id) } ck_wunlock(&sdata->instance_lock); - client_drop_message(id, dropped, false); + notice_msg_entries(&entries); if (aged) LOGINFO("Aged %d disconnected instances to dead", aged); } From b7e9291fc557b3e7aa0258fd63ba7edd888b51bc Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 22:27:36 +1100 Subject: [PATCH 26/36] Add more info to client drop messages using notice_msg_entries --- src/stratifier.c | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 5f2fa039..e13e4301 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1265,19 +1265,21 @@ static int __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instan return ret; } -static void client_drop_message(const int64_t client_id, const int dropped, const bool lazily) +static void client_drop_message(char **msg, const stratum_instance_t *client, const int64_t id, + const int dropped, const bool lazily) { switch(dropped) { - case 0: - break; case 1: - LOGNOTICE("Client %"PRId64" disconnected %s", client_id, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" user %s worker %s disconnected %s", + id, client->user_instance->username, client->workername, lazily ? "lazily" : ""); break; case 2: - LOGNOTICE("Client %"PRId64" dropped %s", client_id, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" user %s worker %s dropped %s", + id, client->user_instance->username, client->workername, lazily ? "lazily" : ""); break; case 3: - LOGNOTICE("Workerless client %"PRId64" dropped %s", client_id, lazily ? "lazily" : ""); + ASPRINTF(msg, "Workerless client %"PRId64" dropped %s", + id, lazily ? "lazily" : ""); break; } } @@ -1287,19 +1289,21 @@ static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *client, const const char *func, const int line) { user_instance_t *user = client->user_instance; - int64_t client_id = client->id; + char_entry_t *entries = NULL; int dropped = 0, ref; + char *msg; ck_wlock(&sdata->instance_lock); ref = --client->ref; /* See if there are any instances that were dropped that could not be * moved due to holding a reference and drop them now. */ - if (unlikely(client->dropped && !ref)) + if (unlikely(client->dropped && !ref)) { dropped = __drop_client(sdata, client, user); + client_drop_message(&msg, client, client->id, dropped, true); + } ck_wunlock(&sdata->instance_lock); - client_drop_message(client_id, dropped, true); - + notice_msg_entries(&entries); /* This should never happen */ if (unlikely(ref < 0)) LOGERR("Instance ref count dropped below zero from %s %s:%d", file, func, line); @@ -1464,23 +1468,7 @@ static void drop_client(sdata_t *sdata, const int64_t id) * now but wait till the reference is dropped */ if (!client->ref) { dropped = __drop_client(sdata, client, user); - switch(dropped) { - case 0: - ASPRINTF(&msg, "Unknown client %"PRId64" drop", id); - break; - case 1: - ASPRINTF(&msg, "Client %"PRId64" user %s worker %s disconnected", - id, user->username, client->workername); - break; - case 2: - ASPRINTF(&msg, "Client %"PRId64" user %s worker %s dropped", - id, user->username, client->workername); - break; - case 3: - ASPRINTF(&msg, "Workerless client %"PRId64" dropped", - id); - break; - } + client_drop_message(&msg, client, id, dropped, false); add_msg_entry(&entries, &msg); } else client->dropped = true; From b92062d6ea8dbad8b5e299a80bacd0010ecb6aef Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 22:36:28 +1100 Subject: [PATCH 27/36] Add IP address to client drop message --- src/stratifier.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index e13e4301..4e7308de 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1270,16 +1270,18 @@ static void client_drop_message(char **msg, const stratum_instance_t *client, co { switch(dropped) { case 1: - ASPRINTF(msg, "Client %"PRId64" user %s worker %s disconnected %s", - id, client->user_instance->username, client->workername, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s disconnected %s", + id, client->address, client->user_instance->username, + client->workername, lazily ? "lazily" : ""); break; case 2: - ASPRINTF(msg, "Client %"PRId64" user %s worker %s dropped %s", - id, client->user_instance->username, client->workername, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s dropped %s", + id, client->address, client->user_instance->username, + client->workername, lazily ? "lazily" : ""); break; case 3: - ASPRINTF(msg, "Workerless client %"PRId64" dropped %s", - id, lazily ? "lazily" : ""); + ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", + id, client->address, lazily ? "lazily" : ""); break; } } From 7959e72520e631c684d77c9159c92b6130f4f0f1 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 22:44:22 +1100 Subject: [PATCH 28/36] Add client IP address to notifications --- src/stratifier.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 4e7308de..b6ee1014 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2470,8 +2470,8 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ time_t now_t = time(NULL); if (now_t < user->failed_authtime + user->auth_backoff) { - LOGNOTICE("Client %"PRId64" worker %s rate limited due to failed auth attempts", - client->id, buf); + LOGNOTICE("Client %"PRId64" %s worker %s rate limited due to failed auth attempts", + client->id, client->address, buf); client->dropped = true; goto out; } @@ -2499,12 +2499,12 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ if (ret) { client->authorised = ret; user->authorised = ret; - LOGNOTICE("Authorised client %"PRId64" worker %s as user %s", client->id, buf, - user->username); + LOGNOTICE("Authorised client %"PRId64" %s worker %s as user %s", + client->id, client->address, buf, user->username); user->auth_backoff = 3; /* Reset auth backoff time */ } else { - LOGNOTICE("Client %"PRId64" worker %s failed to authorise as user %s", client->id, buf, - user->username); + LOGNOTICE("Client %"PRId64" %s worker %s failed to authorise as user %s", + client->id, client->address, buf,user->username); user->failed_authtime = time(NULL); user->auth_backoff <<= 1; /* Cap backoff time to 10 mins */ @@ -3332,7 +3332,8 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 json_t *val, *result_val; if (unlikely(client->subscribed)) { - LOGNOTICE("Client %"PRId64" trying to subscribe twice", client_id); + LOGNOTICE("Client %"PRId64" %s trying to subscribe twice", + client_id, client->address); return; } result_val = parse_subscribe(client, client_id, params_val); @@ -3352,7 +3353,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 } if (unlikely(cmdmatch(method, "mining.passthrough"))) { - LOGNOTICE("Adding passthrough client %"PRId64, client_id); + LOGNOTICE("Adding passthrough client %"PRId64" %s", client_id, client->address); /* We need to inform the connector process that this client * is a passthrough and to manage its messages accordingly. * The client_id stays on the list but we won't send anything @@ -3365,7 +3366,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 /* We should only accept subscribed requests from here on */ if (!client->subscribed) { - LOGINFO("Dropping unsubscribed client %"PRId64, client_id); + LOGINFO("Dropping unsubscribed client %"PRId64" %s", client_id, client->address); snprintf(buf, 255, "dropclient=%"PRId64, client_id); send_proc(client->ckp->connector, buf); return; @@ -3375,7 +3376,8 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 json_params_t *jp; if (unlikely(client->authorised)) { - LOGNOTICE("Client %"PRId64" trying to authorise twice", client_id); + LOGNOTICE("Client %"PRId64" %s trying to authorise twice", + client_id, client->address); return; } jp = create_json_params(client_id, method_val, params_val, id_val, address); @@ -3388,7 +3390,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 /* Dropping unauthorised clients here also allows the * stratifier process to restart since it will have lost all * the stratum instance data. Clients will just reconnect. */ - LOGINFO("Dropping unauthorised client %"PRId64, client_id); + LOGINFO("Dropping unauthorised client %"PRId64" %s", client_id, client->address); snprintf(buf, 255, "dropclient=%"PRId64, client_id); send_proc(client->ckp->connector, buf); return; @@ -3407,7 +3409,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 return; } /* Unhandled message here */ - LOGINFO("Unhandled client %"PRId64" method %s", client_id, method); + LOGINFO("Unhandled client %"PRId64" %s method %s", client_id, client->address, method); return; } @@ -3425,7 +3427,8 @@ static void parse_instance_msg(sdata_t *sdata, smsg_t *msg, stratum_instance_t * char buf[256]; if (unlikely(client->reject == 2)) { - LOGINFO("Dropping client %"PRId64" tagged for lazy invalidation", client_id); + LOGINFO("Dropping client %"PRId64" %s tagged for lazy invalidation", + client_id, client->address); snprintf(buf, 255, "dropclient=%"PRId64, client_id); send_proc(client->ckp->connector, buf); goto out; From 93eb641d21aa059ed30b33f0085137ef49f7e9ad Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 22:54:19 +1100 Subject: [PATCH 29/36] Rate limit auth backoff message --- src/stratifier.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index b6ee1014..91fcf357 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2212,6 +2212,8 @@ static void read_workerstats(ckpool_t *ckp, worker_instance_t *worker) } } +#define DEFAULT_AUTH_BACKOFF (3) /* Set initial backoff to 3 seconds */ + /* This simply strips off the first part of the workername and matches it to a * user or creates a new one. Needs to be entered with client holding a ref * count. */ @@ -2237,7 +2239,7 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, if (!user) { /* New user instance. Secondary user id will be NULL */ user = ckzalloc(sizeof(user_instance_t)); - user->auth_backoff = 3; /* Set initial backoff to 3 seconds */ + user->auth_backoff = DEFAULT_AUTH_BACKOFF; strcpy(user->username, username); new_user = true; user->id = sdata->user_instance_id++; @@ -2470,8 +2472,13 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ time_t now_t = time(NULL); if (now_t < user->failed_authtime + user->auth_backoff) { - LOGNOTICE("Client %"PRId64" %s worker %s rate limited due to failed auth attempts", - client->id, client->address, buf); + if (user->auth_backoff == DEFAULT_AUTH_BACKOFF) { + LOGNOTICE("Client %"PRId64" %s worker %s rate limited due to failed auth attempts", + client->id, client->address, buf); + } else{ + LOGINFO("Client %"PRId64" %s worker %s rate limited due to failed auth attempts", + client->id, client->address, buf); + } client->dropped = true; goto out; } @@ -2501,7 +2508,7 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ user->authorised = ret; LOGNOTICE("Authorised client %"PRId64" %s worker %s as user %s", client->id, client->address, buf, user->username); - user->auth_backoff = 3; /* Reset auth backoff time */ + user->auth_backoff = DEFAULT_AUTH_BACKOFF; /* Reset auth backoff time */ } else { LOGNOTICE("Client %"PRId64" %s worker %s failed to authorise as user %s", client->id, client->address, buf,user->username); From cb3960be5048b1045ad4c48954d731d05160a93c Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 23:05:02 +1100 Subject: [PATCH 30/36] Add client drop message before we delete structures --- src/stratifier.c | 49 ++++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 91fcf357..2655231c 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1241,48 +1241,32 @@ out: } /* Ret = 1 is disconnected, 2 is killed, 3 is workerless killed */ -static int __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *user) +static void __drop_client(sdata_t *sdata, stratum_instance_t *client, user_instance_t *user, + bool lazily, char **msg) { stratum_instance_t *old_client = NULL; - int ret; __del_client(sdata, client, user); HASH_FIND(hh, sdata->disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); /* Only keep around one copy of the old client in server mode */ if (!client->ckp->proxy && !old_client && client->enonce1_64 && client->authorised) { - ret = 1; + ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s disconnected %s", + client->id, client->address, client->user_instance->username, + client->workername, lazily ? "lazily" : ""); HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); sdata->stats.disconnected++; sdata->disconnected_generated++; client->disconnected_time = time(NULL); } else { - if (client->workername) - ret = 2; - else - ret = 3; - __kill_instance(sdata, client); - } - return ret; -} - -static void client_drop_message(char **msg, const stratum_instance_t *client, const int64_t id, - const int dropped, const bool lazily) -{ - switch(dropped) { - case 1: - ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s disconnected %s", - id, client->address, client->user_instance->username, - client->workername, lazily ? "lazily" : ""); - break; - case 2: + if (client->workername) { ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s dropped %s", - id, client->address, client->user_instance->username, + client->id, client->address, client->user_instance->username, client->workername, lazily ? "lazily" : ""); - break; - case 3: + } else { ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", - id, client->address, lazily ? "lazily" : ""); - break; + client->id, client->address, lazily ? "lazily" : ""); + } + __kill_instance(sdata, client); } } @@ -1292,16 +1276,16 @@ static void _dec_instance_ref(sdata_t *sdata, stratum_instance_t *client, const { user_instance_t *user = client->user_instance; char_entry_t *entries = NULL; - int dropped = 0, ref; char *msg; + int ref; ck_wlock(&sdata->instance_lock); ref = --client->ref; /* See if there are any instances that were dropped that could not be * moved due to holding a reference and drop them now. */ if (unlikely(client->dropped && !ref)) { - dropped = __drop_client(sdata, client, user); - client_drop_message(&msg, client, client->id, dropped, true); + __drop_client(sdata, client, user, true, &msg); + add_msg_entry(&entries, &msg); } ck_wunlock(&sdata->instance_lock); @@ -1456,8 +1440,8 @@ static void drop_client(sdata_t *sdata, const int64_t id) stratum_instance_t *client, *tmp; char_entry_t *entries = NULL; user_instance_t *user = NULL; - int dropped = 0, aged = 0; time_t now_t = time(NULL); + int aged = 0; char *msg; LOGINFO("Stratifier asked to drop client %"PRId64, id); @@ -1469,8 +1453,7 @@ static void drop_client(sdata_t *sdata, const int64_t id) /* If the client is still holding a reference, don't drop them * now but wait till the reference is dropped */ if (!client->ref) { - dropped = __drop_client(sdata, client, user); - client_drop_message(&msg, client, id, dropped, false); + __drop_client(sdata, client, user, false, &msg); add_msg_entry(&entries, &msg); } else client->dropped = true; From 5261837b8ffeb78ba85f69a982ae176abd0e9cf6 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 23:16:13 +1100 Subject: [PATCH 31/36] Add information about throttled clients, showing only when they're first throttled --- src/stratifier.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 2655231c..8460cbae 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -187,6 +187,7 @@ struct user_instance { time_t auth_time; time_t failed_authtime; /* Last time this username failed to authorise */ int auth_backoff; /* How long to reject any auth attempts since last failure */ + bool throttled; /* Have we begun rejecting auth attempts */ }; /* Combined data from workers with the same workername */ @@ -1250,18 +1251,18 @@ static void __drop_client(sdata_t *sdata, stratum_instance_t *client, user_insta HASH_FIND(hh, sdata->disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); /* Only keep around one copy of the old client in server mode */ if (!client->ckp->proxy && !old_client && client->enonce1_64 && client->authorised) { - ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s disconnected %s", - client->id, client->address, client->user_instance->username, - client->workername, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s disconnected %s", + client->id, client->address, user->throttled ? "throttled " : "", + user->username, client->workername, lazily ? "lazily" : ""); HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); sdata->stats.disconnected++; sdata->disconnected_generated++; client->disconnected_time = time(NULL); } else { if (client->workername) { - ASPRINTF(msg, "Client %"PRId64" %s user %s worker %s dropped %s", - client->id, client->address, client->user_instance->username, - client->workername, lazily ? "lazily" : ""); + ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s dropped %s", + client->id, client->address, user->throttled ? "throttled " : "", + user->username, client->workername, lazily ? "lazily" : ""); } else { ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", client->id, client->address, lazily ? "lazily" : ""); @@ -2455,7 +2456,8 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ time_t now_t = time(NULL); if (now_t < user->failed_authtime + user->auth_backoff) { - if (user->auth_backoff == DEFAULT_AUTH_BACKOFF) { + if (!user->throttled) { + user->throttled = true; LOGNOTICE("Client %"PRId64" %s worker %s rate limited due to failed auth attempts", client->id, client->address, buf); } else{ From 8916a8e1d5caf90f2b8581f188aec7b5ae9f066e Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Thu, 12 Mar 2015 23:45:34 +1100 Subject: [PATCH 32/36] Pick up the client address as soon as we generate the stratum instance to avoid passing it round repeatedly with messages --- src/stratifier.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 8460cbae..f9af16b4 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -136,7 +136,6 @@ struct json_params { json_t *params; json_t *id_val; int64_t client_id; - char address[INET6_ADDRSTRLEN]; }; typedef struct json_params json_params_t; @@ -145,7 +144,6 @@ typedef struct json_params json_params_t; struct smsg { json_t *json_msg; int64_t client_id; - char address[INET6_ADDRSTRLEN]; }; typedef struct smsg smsg_t; @@ -1314,13 +1312,15 @@ static stratum_instance_t *__recruit_stratum_instance(sdata_t *sdata) } /* Enter with write instance_lock held */ -static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t id, const int server) +static stratum_instance_t *__stratum_add_instance(ckpool_t *ckp, const int64_t id, + const char *address, const int server) { stratum_instance_t *client; sdata_t *sdata = ckp->data; client = __recruit_stratum_instance(sdata); client->id = id; + strcpy(client->address, address); client->server = server; client->diff = client->old_diff = ckp->startdiff; client->ckp = ckp; @@ -2404,8 +2404,8 @@ static void queue_delayed_auth(stratum_instance_t *client) } /* Needs to be entered with client holding a ref count. */ -static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_val, json_t **err_val, - const char *address, int *errnum) +static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_val, + json_t **err_val, int *errnum) { user_instance_t *user; ckpool_t *ckp = client->ckp; @@ -2448,7 +2448,6 @@ static json_t *parse_authorise(stratum_instance_t *client, const json_t *params_ client->user_id = user->id; ts_realtime(&now); client->start_time = now.tv_sec; - strcpy(client->address, address); /* NOTE workername is NULL prior to this so should not be used in code * till after this point */ client->workername = strdup(buf); @@ -3192,7 +3191,7 @@ static void update_client(sdata_t *sdata, const stratum_instance_t *client, cons static json_params_t *create_json_params(const int64_t client_id, const json_t *method, const json_t *params, - const json_t *id_val, const char *address) + const json_t *id_val) { json_params_t *jp = ckalloc(sizeof(json_params_t)); @@ -3200,7 +3199,6 @@ static json_params_t jp->params = json_deep_copy(params); jp->id_val = json_deep_copy(id_val); jp->client_id = client_id; - strcpy(jp->address, address); return jp; } @@ -3304,7 +3302,7 @@ static void suggest_diff(stratum_instance_t *client, const char *method, const j /* Enter with client holding ref count */ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64_t client_id, - json_t *id_val, json_t *method_val, json_t *params_val, const char *address) + json_t *id_val, json_t *method_val, json_t *params_val) { const char *method; char buf[256]; @@ -3314,7 +3312,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 * most common messages will be shares so look for those first */ method = json_string_value(method_val); if (likely(cmdmatch(method, "mining.submit") && client->authorised)) { - json_params_t *jp = create_json_params(client_id, method_val, params_val, id_val, address); + json_params_t *jp = create_json_params(client_id, method_val, params_val, id_val); ckmsgq_add(sdata->sshareq, jp); return; @@ -3372,7 +3370,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 client_id, client->address); return; } - jp = create_json_params(client_id, method_val, params_val, id_val, address); + jp = create_json_params(client_id, method_val, params_val, id_val); ckmsgq_add(sdata->sauthq, jp); return; } @@ -3395,7 +3393,7 @@ static void parse_method(sdata_t *sdata, stratum_instance_t *client, const int64 /* Covers both get_transactions and get_txnhashes */ if (cmdmatch(method, "mining.get")) { - json_params_t *jp = create_json_params(client_id, method_val, params_val, id_val, address); + json_params_t *jp = create_json_params(client_id, method_val, params_val, id_val); ckmsgq_add(sdata->stxnq, jp); return; @@ -3456,7 +3454,7 @@ static void parse_instance_msg(sdata_t *sdata, smsg_t *msg, stratum_instance_t * send_json_err(sdata, client_id, id_val, "-1:params not found"); goto out; } - parse_method(sdata, client, client_id, id_val, method, params, msg->address); + parse_method(sdata, client, client_id, id_val, method, params); out: free_smsg(msg); } @@ -3464,6 +3462,7 @@ out: static void srecv_process(ckpool_t *ckp, char *buf) { bool noid = false, dropped = false; + char address[INET6_ADDRSTRLEN]; sdata_t *sdata = ckp->data; stratum_instance_t *client; smsg_t *msg; @@ -3495,7 +3494,7 @@ static void srecv_process(ckpool_t *ckp, char *buf) free(msg); goto out; } - strcpy(msg->address, json_string_value(val)); + strcpy(address, json_string_value(val)); json_object_clear(val); val = json_object_get(msg->json_msg, "server"); @@ -3515,7 +3514,7 @@ static void srecv_process(ckpool_t *ckp, char *buf) if (unlikely(!client)) { if (likely(!__dropped_instance(sdata, msg->client_id))) { noid = true; - client = __stratum_add_instance(ckp, msg->client_id, server); + client = __stratum_add_instance(ckp, msg->client_id, address, server); } else dropped = true; } else if (unlikely(client->dropped)) @@ -3634,7 +3633,7 @@ static void sauth_process(ckpool_t *ckp, json_params_t *jp) goto out; } - result_val = parse_authorise(client, jp->params, &err_val, jp->address, &errnum); + result_val = parse_authorise(client, jp->params, &err_val, &errnum); if (json_is_true(result_val)) { char *buf; From 0900b5d5c5b84ead8d8fd031278cdc97a2095cdb Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 13 Mar 2015 09:36:53 +1100 Subject: [PATCH 33/36] Check for no user in __drop_client --- src/stratifier.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index f9af16b4..4c191dc3 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -1258,9 +1258,15 @@ static void __drop_client(sdata_t *sdata, stratum_instance_t *client, user_insta client->disconnected_time = time(NULL); } else { if (client->workername) { - ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s dropped %s", - client->id, client->address, user->throttled ? "throttled " : "", - user->username, client->workername, lazily ? "lazily" : ""); + if (user) { + ASPRINTF(msg, "Client %"PRId64" %s %suser %s worker %s dropped %s", + client->id, client->address, user->throttled ? "throttled " : "", + user->username, client->workername, lazily ? "lazily" : ""); + } else { + ASPRINTF(msg, "Client %"PRId64" %s no user worker %s dropped %s", + client->id, client->address, client->workername, + lazily ? "lazily" : ""); + } } else { ASPRINTF(msg, "Workerless client %"PRId64" %s dropped %s", client->id, client->address, lazily ? "lazily" : ""); From 03149c1354a395b4510173b958b17b04668db741 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 13 Mar 2015 11:27:46 +1100 Subject: [PATCH 34/36] Create the user if it doesn't already exist in set_worker_mindiff --- src/stratifier.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index 4c191dc3..d6fe069d 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2204,6 +2204,30 @@ static void read_workerstats(ckpool_t *ckp, worker_instance_t *worker) #define DEFAULT_AUTH_BACKOFF (3) /* Set initial backoff to 3 seconds */ +static user_instance_t *__create_user(sdata_t *sdata, const char *username) +{ + user_instance_t *user = ckzalloc(sizeof(user_instance_t)); + + user->auth_backoff = DEFAULT_AUTH_BACKOFF; + strcpy(user->username, username); + user->id = sdata->user_instance_id++; + HASH_ADD_STR(sdata->user_instances, username, user); + return user; +} + +static user_instance_t *get_user(sdata_t *sdata, const char *username) +{ + user_instance_t *user; + + ck_wlock(&sdata->instance_lock); + HASH_FIND_STR(sdata->user_instances, username, user); + if (unlikely(!user)) + user = __create_user(sdata, username); + ck_wunlock(&sdata->instance_lock); + + return user; +} + /* This simply strips off the first part of the workername and matches it to a * user or creates a new one. Needs to be entered with client holding a ref * count. */ @@ -2228,12 +2252,8 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, HASH_FIND_STR(sdata->user_instances, username, user); if (!user) { /* New user instance. Secondary user id will be NULL */ - user = ckzalloc(sizeof(user_instance_t)); - user->auth_backoff = DEFAULT_AUTH_BACKOFF; - strcpy(user->username, username); + user = __create_user(sdata, username); new_user = true; - user->id = sdata->user_instance_id++; - HASH_ADD_STR(sdata->user_instances, username, user); } client->user_instance = user; DL_FOREACH(user->worker_instances, tmp) { @@ -3220,15 +3240,7 @@ static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindif strsep(&ignore, "._"); /* Find the user first */ - ck_rlock(&sdata->instance_lock); - HASH_FIND_STR(sdata->user_instances, username, user); - ck_runlock(&sdata->instance_lock); - - /* They may just have not connected yet */ - if (!user) { - LOGINFO("Failed to find user %s in set_worker_mindiff", username); - return; - } + user = get_user(sdata, username); /* Then find the matching worker user */ ck_rlock(&sdata->instance_lock); From dda8187e4996c77372f7b541488ef2f8bbccf2bf Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 13 Mar 2015 11:51:08 +1100 Subject: [PATCH 35/36] Create workers if they don't already exist when set_worker_mindiff is called --- src/stratifier.c | 75 +++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index d6fe069d..0a728239 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2215,6 +2215,7 @@ static user_instance_t *__create_user(sdata_t *sdata, const char *username) return user; } +/* Find user by username or create one if it doesn't already exist */ static user_instance_t *get_user(sdata_t *sdata, const char *username) { user_instance_t *user; @@ -2228,6 +2229,45 @@ static user_instance_t *get_user(sdata_t *sdata, const char *username) return user; } +static worker_instance_t *__create_worker(user_instance_t *user, const char *workername) +{ + worker_instance_t *worker = ckzalloc(sizeof(worker_instance_t)); + + worker->workername = strdup(workername); + worker->user_instance = user; + DL_APPEND(user->worker_instances, worker); + worker->start_time = time(NULL); + return worker; +} + +static worker_instance_t *__get_worker(user_instance_t *user, const char *workername) +{ + worker_instance_t *worker = NULL, *tmp; + + DL_FOREACH(user->worker_instances, tmp) { + if (!safecmp(workername, tmp->workername)) { + worker = tmp; + break; + } + } + return worker; +} + +/* Find worker amongst a user's workers by workername or create one if it + * doesn't yet exist. */ +static worker_instance_t *get_worker(sdata_t *sdata, user_instance_t *user, const char *workername) +{ + worker_instance_t *worker; + + ck_wlock(&sdata->instance_lock); + worker = __get_worker(user, workername); + if (!worker) + worker = __create_worker(user, workername); + ck_wunlock(&sdata->instance_lock); + + return worker; +} + /* This simply strips off the first part of the workername and matches it to a * user or creates a new one. Needs to be entered with client holding a ref * count. */ @@ -2237,7 +2277,6 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, char *base_username = strdupa(workername), *username; bool new_user = false, new_worker = false; sdata_t *sdata = ckp->data; - worker_instance_t *tmp; user_instance_t *user; int len; @@ -2256,23 +2295,12 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, new_user = true; } client->user_instance = user; - DL_FOREACH(user->worker_instances, tmp) { - if (!safecmp(workername, tmp->workername)) { - client->worker_instance = tmp; - break; - } - } + client->worker_instance = __get_worker(user, workername); /* Create one worker instance for combined data from workers of the * same name */ if (!client->worker_instance) { - worker_instance_t *worker = ckzalloc(sizeof(worker_instance_t)); - - worker->workername = strdup(workername); - worker->user_instance = user; - DL_APPEND(user->worker_instances, worker); + client->worker_instance = __create_worker(user, workername); new_worker = true; - worker->start_time = time(NULL); - client->worker_instance = worker; } DL_APPEND(user->clients, client); __inc_worker(sdata,user); @@ -3230,11 +3258,11 @@ static json_params_t static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindiff) { - worker_instance_t *worker = NULL, *tmp; char *username = strdupa(workername), *ignore; - user_instance_t *user = NULL; stratum_instance_t *client; sdata_t *sdata = ckp->data; + worker_instance_t *worker; + user_instance_t *user; ignore = username; strsep(&ignore, "._"); @@ -3243,20 +3271,7 @@ static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindif user = get_user(sdata, username); /* Then find the matching worker user */ - ck_rlock(&sdata->instance_lock); - DL_FOREACH(user->worker_instances, tmp) { - if (!safecmp(workername, tmp->workername)) { - worker = tmp; - break; - } - } - ck_runlock(&sdata->instance_lock); - - /* They may just not be connected at the moment */ - if (!worker) { - LOGINFO("Failed to find worker %s in set_worker_mindiff", workername); - return; - } + worker = get_worker(sdata, user, workername); if (mindiff < 1) { LOGINFO("Worker %s requested invalid diff %d", worker->workername, mindiff); From f6abc404d5907bc85c6776634ebab35229ceb8b2 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 13 Mar 2015 12:15:35 +1100 Subject: [PATCH 36/36] Change parsing of ckdb response, expecting an array of workers --- src/stratifier.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/stratifier.c b/src/stratifier.c index 0a728239..2f38a53d 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -2322,6 +2322,22 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, return user; } +static void set_worker_mindiff(ckpool_t *ckp, const char *workername, int mindiff); + +static void parse_worker_diffs(ckpool_t *ckp, json_t *worker_array) +{ + json_t *worker_entry; + char *workername; + size_t index; + int mindiff; + + json_array_foreach(worker_array, index, worker_entry) { + json_get_string(&workername, worker_entry, "workername"); + json_get_int(&mindiff, worker_entry, "difficultydefault"); + set_worker_mindiff(ckp, workername, mindiff); + } +} + /* Send this to the database and parse the response to authorise a user * and get SUID parameters back. We don't add these requests to the sdata->ckdbqueue * since we have to wait for the response but this is done from the authoriser @@ -2396,8 +2412,10 @@ static int send_recv_auth(stratum_instance_t *client) if (unlikely(!val)) LOGWARNING("AUTH JSON decode failed(%d): %s", err_val.line, err_val.text); else { + json_t *worker_array = json_object_get(val, "workers"); + json_get_string(&secondaryuserid, val, "secondaryuserid"); - json_get_int(&worker->mindiff, val, "difficultydefault"); + parse_worker_diffs(ckp, worker_array); client->suggest_diff = worker->mindiff; if (!user->auth_time) user->auth_time = time(NULL);