|
|
|
@ -46,8 +46,8 @@
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#define DB_VLOCK "1" |
|
|
|
|
#define DB_VERSION "0.7" |
|
|
|
|
#define CKDB_VERSION DB_VERSION"-0.106" |
|
|
|
|
#define DB_VERSION "0.8" |
|
|
|
|
#define CKDB_VERSION DB_VERSION"-0.202" |
|
|
|
|
|
|
|
|
|
#define WHERE_FFL " - from %s %s() line %d" |
|
|
|
|
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ |
|
|
|
@ -128,8 +128,6 @@ static char *restorefrom;
|
|
|
|
|
* ckdb aborting and needing a complete restart resolves it |
|
|
|
|
* The users table, required for the authorise messages, is always updated |
|
|
|
|
* immediately and is not affected by ckpool messages until we |
|
|
|
|
* TODO: allow bitcoin addresses - this will also need to be handled |
|
|
|
|
* while filling the queue during reload, once we allow BTC addresses |
|
|
|
|
* During the reload, when checking the timeframe for summarisation, we |
|
|
|
|
* use the current last userstats createdate as 'now' to avoid touching a |
|
|
|
|
* timeframe where data could still be waiting to be loaded |
|
|
|
@ -767,6 +765,7 @@ enum cmd_values {
|
|
|
|
|
CMD_LOGLEVEL, |
|
|
|
|
CMD_SHARELOG, |
|
|
|
|
CMD_AUTH, |
|
|
|
|
CMD_ADDRAUTH, |
|
|
|
|
CMD_ADDUSER, |
|
|
|
|
CMD_NEWPASS, |
|
|
|
|
CMD_CHKPASS, |
|
|
|
@ -841,6 +840,8 @@ static K_LIST *transfer_free;
|
|
|
|
|
// older version missing field defaults
|
|
|
|
|
static TRANSFER auth_1 = { "poolinstance", "", auth_1.value }; |
|
|
|
|
static K_ITEM auth_poolinstance = { "tmp", NULL, NULL, (void *)(&auth_1) }; |
|
|
|
|
static TRANSFER auth_2 = { "preauth", FALSE_STR, auth_2.value }; |
|
|
|
|
static K_ITEM auth_preauth = { "tmp", NULL, NULL, (void *)(&auth_2) }; |
|
|
|
|
static TRANSFER poolstats_1 = { "elapsed", "0", poolstats_1.value }; |
|
|
|
|
static K_ITEM poolstats_elapsed = { "tmp", NULL, NULL, (void *)(&poolstats_1) }; |
|
|
|
|
static TRANSFER userstats_1 = { "elapsed", "0", userstats_1.value }; |
|
|
|
@ -1043,7 +1044,7 @@ static K_LIST *optioncontrol_free;
|
|
|
|
|
static K_STORE *optioncontrol_store; |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
// TODO: aging/discarding workinfo,shares
|
|
|
|
|
// TODO: discarding workinfo,shares
|
|
|
|
|
// WORKINFO workinfo.id.json={...}
|
|
|
|
|
typedef struct workinfo { |
|
|
|
|
int64_t workinfoid; |
|
|
|
@ -1254,6 +1255,7 @@ typedef struct auths {
|
|
|
|
|
int32_t clientid; |
|
|
|
|
char enonce1[TXT_SML+1]; |
|
|
|
|
char useragent[TXT_BIG+1]; |
|
|
|
|
char preauth[TXT_FLAG+1]; |
|
|
|
|
HISTORYDATECONTROLFIELDS; |
|
|
|
|
} AUTHS; |
|
|
|
|
|
|
|
|
@ -2475,7 +2477,7 @@ unparam:
|
|
|
|
|
return ok; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool users_add(PGconn *conn, char *username, char *emailaddress, |
|
|
|
|
static K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, |
|
|
|
|
char *passwordhash, char *by, char *code, char *inet, |
|
|
|
|
tv_t *cd, K_TREE *trf_root) |
|
|
|
|
{ |
|
|
|
@ -2568,7 +2570,10 @@ unitem:
|
|
|
|
|
} |
|
|
|
|
K_WUNLOCK(users_free); |
|
|
|
|
|
|
|
|
|
return ok; |
|
|
|
|
if (ok) |
|
|
|
|
return item; |
|
|
|
|
else |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static bool users_fill(PGconn *conn) |
|
|
|
@ -3158,7 +3163,7 @@ static bool payments_fill(PGconn *conn)
|
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): select", __func__); |
|
|
|
|
|
|
|
|
|
// TODO: handle selecting a subset, eg 20 per web page
|
|
|
|
|
// TODO: handle selecting a subset, eg 20 per web page (in blocklist also)
|
|
|
|
|
sel = "select " |
|
|
|
|
"userid,paydate,payaddress,originaltxn,amount,committxn,commitblockhash" |
|
|
|
|
HISTORYDATECONTROL |
|
|
|
@ -3481,20 +3486,6 @@ static bool _sharesummary_update(PGconn *conn, SHARES *s_row, SHAREERRORS *e_row
|
|
|
|
|
static cmp_t cmp_sharesummary_workinfoid(K_ITEM *a, K_ITEM *b); |
|
|
|
|
static cmp_t cmp_shares(K_ITEM *a, K_ITEM *b); |
|
|
|
|
|
|
|
|
|
/* N.B. a DB check can be done to find sharesummaries that have missed being
|
|
|
|
|
* aged (and a possible problem with the aging process): |
|
|
|
|
* e.g. for a date D in the past of at least a few hours |
|
|
|
|
* select count(*) from sharesummary where createdate<'D' and complete='n'; |
|
|
|
|
* and can be easily corrected: |
|
|
|
|
* update sharesummary set complete='a' where createdate<'D' and complete='n'; |
|
|
|
|
* It's important to make sure the D value is far enough in the past such that |
|
|
|
|
* all the matching sharesummary records in ckdb have certainly completed |
|
|
|
|
* ckdb would need to restart to get the updated DB information though it would |
|
|
|
|
* not affect current ckdb code |
|
|
|
|
* TODO: This will happen until auto aging is added here - since ckpool can not reliably |
|
|
|
|
* age all workinfo that was active when it exits (e.g. a crash) so best to not |
|
|
|
|
* try, but get ckdb to auto age old unaged data |
|
|
|
|
*/ |
|
|
|
|
static 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, |
|
|
|
@ -4000,7 +3991,6 @@ static bool shares_add(PGconn *conn, char *workinfoid, char *username, char *wor
|
|
|
|
|
|
|
|
|
|
shares = DATA_SHARES(s_item); |
|
|
|
|
|
|
|
|
|
// TODO: allow BTC address later?
|
|
|
|
|
K_RLOCK(users_free); |
|
|
|
|
u_item = find_users(username); |
|
|
|
|
K_RUNLOCK(users_free); |
|
|
|
@ -4097,9 +4087,6 @@ unitem:
|
|
|
|
|
|
|
|
|
|
static bool shares_fill() |
|
|
|
|
{ |
|
|
|
|
// TODO: reload shares from workinfo from log file
|
|
|
|
|
// and verify workinfo while doing that
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -4143,7 +4130,6 @@ static bool shareerrors_add(PGconn *conn, char *workinfoid, char *username,
|
|
|
|
|
|
|
|
|
|
shareerrors = DATA_SHAREERRORS(s_item); |
|
|
|
|
|
|
|
|
|
// TODO: allow BTC address later?
|
|
|
|
|
K_RLOCK(users_free); |
|
|
|
|
u_item = find_users(username); |
|
|
|
|
K_RUNLOCK(users_free); |
|
|
|
@ -4234,9 +4220,6 @@ unitem:
|
|
|
|
|
|
|
|
|
|
static bool shareerrors_fill() |
|
|
|
|
{ |
|
|
|
|
// TODO: reload shareerrors from workinfo from log file
|
|
|
|
|
// and verify workinfo while doing that
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -4836,6 +4819,38 @@ void sharesummary_reload()
|
|
|
|
|
PQfinish(conn); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: do this better ... :)
|
|
|
|
|
static void dsp_hash(char *hash, char *buf, size_t siz) |
|
|
|
|
{ |
|
|
|
|
char *ptr; |
|
|
|
|
|
|
|
|
|
ptr = hash + strlen(hash) - (siz - 1) - 8; |
|
|
|
|
if (ptr < hash) |
|
|
|
|
ptr = hash; |
|
|
|
|
STRNCPYSIZ(buf, ptr, siz); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void dsp_blocks(K_ITEM *item, FILE *stream) |
|
|
|
|
{ |
|
|
|
|
char createdate_buf[DATE_BUFSIZ], expirydate_buf[DATE_BUFSIZ]; |
|
|
|
|
BLOCKS *b = NULL; |
|
|
|
|
char hash_dsp[16+1]; |
|
|
|
|
|
|
|
|
|
if (!item) |
|
|
|
|
fprintf(stream, "%s() called with (null) item\n", __func__); |
|
|
|
|
else { |
|
|
|
|
b = DATA_BLOCKS(item); |
|
|
|
|
|
|
|
|
|
dsp_hash(b->blockhash, hash_dsp, sizeof(hash_dsp)); |
|
|
|
|
tv_to_buf(&(b->createdate), createdate_buf, sizeof(createdate_buf)); |
|
|
|
|
tv_to_buf(&(b->expirydate), expirydate_buf, sizeof(expirydate_buf)); |
|
|
|
|
fprintf(stream, " hi=%d hash='%.16s' uid=%"PRId64" w='%s' " |
|
|
|
|
"cd=%s ed=%s\n", |
|
|
|
|
b->height, hash_dsp, b->userid, b->workername, |
|
|
|
|
createdate_buf, expirydate_buf); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// order by height asc,blockhash asc,expirydate desc
|
|
|
|
|
static cmp_t cmp_blocks(K_ITEM *a, K_ITEM *b) |
|
|
|
|
{ |
|
|
|
@ -4896,7 +4911,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
K_TREE_CTX ctx[1]; |
|
|
|
|
K_ITEM *b_item, *u_item, *old_b_item; |
|
|
|
|
char cd_buf[DATE_BUFSIZ]; |
|
|
|
|
char blk_dsp[16+1], *ptr; |
|
|
|
|
char hash_dsp[16+1]; |
|
|
|
|
BLOCKS *row; |
|
|
|
|
char *upd, *ins; |
|
|
|
|
char *params[11 + HISTORYDATECOUNT]; |
|
|
|
@ -4918,11 +4933,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
|
|
|
|
|
HISTORYDATEINIT(row, cd, by, code, inet); |
|
|
|
|
|
|
|
|
|
// TODO: do this better ... :)
|
|
|
|
|
ptr = blockhash + strlen(blockhash) - (sizeof(blk_dsp)-1) - 8; |
|
|
|
|
if (ptr < blockhash) |
|
|
|
|
ptr = blockhash; |
|
|
|
|
STRNCPY(blk_dsp, ptr); |
|
|
|
|
dsp_hash(blockhash, hash_dsp, sizeof(hash_dsp)); |
|
|
|
|
|
|
|
|
|
K_WLOCK(blocks_free); |
|
|
|
|
old_b_item = find_blocks(row->height, blockhash); |
|
|
|
@ -4940,7 +4951,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
__func__, |
|
|
|
|
blocks_confirmed(DATA_BLOCKS(old_b_item)->confirmed), |
|
|
|
|
blocks_confirmed(confirmed), |
|
|
|
|
height, blk_dsp, cd_buf); |
|
|
|
|
height, hash_dsp, cd_buf); |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
@ -5007,7 +5018,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
"Ignored: Block: %s/...%s/%s", |
|
|
|
|
__func__, |
|
|
|
|
blocks_confirmed(confirmed), |
|
|
|
|
height, blk_dsp, cd_buf); |
|
|
|
|
height, hash_dsp, cd_buf); |
|
|
|
|
goto flail; |
|
|
|
|
} |
|
|
|
|
want = BLOCKS_CONFIRM; |
|
|
|
@ -5017,7 +5028,7 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
tv_to_buf(cd, cd_buf, sizeof(cd_buf)); |
|
|
|
|
LOGERR("%s(): Can't %s a non-existent Block: %s/...%s/%s", |
|
|
|
|
__func__, blocks_confirmed(confirmed), |
|
|
|
|
height, blk_dsp, cd_buf); |
|
|
|
|
height, hash_dsp, cd_buf); |
|
|
|
|
goto flail; |
|
|
|
|
} |
|
|
|
|
if (confirmed[0] == BLOCKS_CONFIRM) |
|
|
|
@ -5026,15 +5037,14 @@ static bool blocks_add(PGconn *conn, char *height, char *blockhash,
|
|
|
|
|
k_add_head(blocks_free, b_item); |
|
|
|
|
K_WUNLOCK(blocks_free); |
|
|
|
|
// No mismatch messages during startup
|
|
|
|
|
if (!startup_complete) { |
|
|
|
|
if (startup_complete) { |
|
|
|
|
tv_to_buf(cd, cd_buf, sizeof(cd_buf)); |
|
|
|
|
LOGERR("%s(): Request Status: %s requires Status: %s. " |
|
|
|
|
LOGERR("%s(): New Status: %s requires Status: %c. " |
|
|
|
|
"Ignored: Status: %s, Block: %s/...%s/%s", |
|
|
|
|
__func__, |
|
|
|
|
blocks_confirmed(confirmed), |
|
|
|
|
blocks_confirmed(BLOCKS_CONFIRM_STR), |
|
|
|
|
blocks_confirmed(confirmed), want, |
|
|
|
|
blocks_confirmed(DATA_BLOCKS(old_b_item)->confirmed), |
|
|
|
|
height, blk_dsp, cd_buf); |
|
|
|
|
height, hash_dsp, cd_buf); |
|
|
|
|
} |
|
|
|
|
goto flail; |
|
|
|
|
} |
|
|
|
@ -5174,9 +5184,10 @@ flail:
|
|
|
|
|
} |
|
|
|
|
tv_to_buf(&(DATA_BLOCKS(b_item)->createdate), cd_buf, sizeof(cd_buf)); |
|
|
|
|
snprintf(tmp, sizeof(tmp), |
|
|
|
|
" Reward: %f, User: %s, Worker: %s, ShareEst: %.1f %s%s%% UTC:%s", |
|
|
|
|
" Reward: %f, Worker: %s, ShareEst: %.1f %s%s%% UTC:%s", |
|
|
|
|
BTC_TO_D(DATA_BLOCKS(b_item)->reward), |
|
|
|
|
username, workername, pool.diffacc, est, pct, cd_buf); |
|
|
|
|
DATA_BLOCKS(b_item)->workername, |
|
|
|
|
pool.diffacc, est, pct, cd_buf); |
|
|
|
|
if (pool.workinfoid < DATA_BLOCKS(b_item)->workinfoid) { |
|
|
|
|
pool.workinfoid = DATA_BLOCKS(b_item)->workinfoid; |
|
|
|
|
pool.diffacc = pool.differr = |
|
|
|
@ -5194,7 +5205,7 @@ flail:
|
|
|
|
|
LOGWARNING("%s(): %sStatus: %s, Block: %s/...%s%s", |
|
|
|
|
__func__, blk ? "BLOCK! " : "", |
|
|
|
|
blocks_confirmed(confirmed), |
|
|
|
|
height, blk_dsp, tmp); |
|
|
|
|
height, hash_dsp, tmp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ok; |
|
|
|
@ -5574,8 +5585,9 @@ static cmp_t cmp_auths(K_ITEM *a, K_ITEM *b)
|
|
|
|
|
|
|
|
|
|
static char *auths_add(PGconn *conn, char *poolinstance, char *username, |
|
|
|
|
char *workername, char *clientid, char *enonce1, |
|
|
|
|
char *useragent, char *by, char *code, char *inet, |
|
|
|
|
tv_t *cd, bool igndup, K_TREE *trf_root) |
|
|
|
|
char *useragent, char *preauth, char *by, char *code, |
|
|
|
|
char *inet, tv_t *cd, bool igndup, K_TREE *trf_root, |
|
|
|
|
bool addressuser) |
|
|
|
|
{ |
|
|
|
|
ExecStatusType rescode; |
|
|
|
|
bool conned = false; |
|
|
|
@ -5587,7 +5599,7 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username,
|
|
|
|
|
AUTHS *row; |
|
|
|
|
char *ins; |
|
|
|
|
char *secuserid = NULL; |
|
|
|
|
char *params[7 + HISTORYDATECOUNT]; |
|
|
|
|
char *params[8 + HISTORYDATECOUNT]; |
|
|
|
|
int par; |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): add", __func__); |
|
|
|
@ -5601,8 +5613,18 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username,
|
|
|
|
|
K_RLOCK(users_free); |
|
|
|
|
u_item = find_users(username); |
|
|
|
|
K_RUNLOCK(users_free); |
|
|
|
|
if (!u_item) { |
|
|
|
|
if (addressuser) { |
|
|
|
|
if (conn == NULL) { |
|
|
|
|
conn = dbconnect(); |
|
|
|
|
conned = true; |
|
|
|
|
} |
|
|
|
|
u_item = users_add(conn, username, EMPTY, EMPTY, |
|
|
|
|
by, code, inet, cd, trf_root); |
|
|
|
|
} |
|
|
|
|
if (!u_item) |
|
|
|
|
goto unitem; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
STRNCPY(row->poolinstance, poolinstance); |
|
|
|
|
row->userid = DATA_USERS(u_item)->userid; |
|
|
|
@ -5614,6 +5636,7 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username,
|
|
|
|
|
TXT_TO_INT("clientid", clientid, row->clientid); |
|
|
|
|
STRNCPY(row->enonce1, enonce1); |
|
|
|
|
STRNCPY(row->useragent, useragent); |
|
|
|
|
STRNCPY(row->preauth, preauth); |
|
|
|
|
|
|
|
|
|
HISTORYDATEINIT(row, cd, by, code, inet); |
|
|
|
|
HISTORYDATETRANSFER(trf_root, row); |
|
|
|
@ -5623,6 +5646,9 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username,
|
|
|
|
|
k_add_head(auths_free, a_item); |
|
|
|
|
K_WUNLOCK(auths_free); |
|
|
|
|
|
|
|
|
|
if (conned) |
|
|
|
|
PQfinish(conn); |
|
|
|
|
|
|
|
|
|
if (!igndup) { |
|
|
|
|
tv_to_buf(cd, cd_buf, sizeof(cd_buf)); |
|
|
|
|
LOGERR("%s(): Duplicate auths ignored %s/%s/%s", |
|
|
|
@ -5653,12 +5679,13 @@ static char *auths_add(PGconn *conn, char *poolinstance, char *username,
|
|
|
|
|
params[par++] = int_to_buf(row->clientid, NULL, 0); |
|
|
|
|
params[par++] = str_to_buf(row->enonce1, NULL, 0); |
|
|
|
|
params[par++] = str_to_buf(row->useragent, NULL, 0); |
|
|
|
|
params[par++] = str_to_buf(row->preauth, NULL, 0); |
|
|
|
|
HISTORYDATEPARAMS(params, par, row); |
|
|
|
|
PARCHK(par, params); |
|
|
|
|
|
|
|
|
|
ins = "insert into auths " |
|
|
|
|
"(authid,poolinstance,userid,workername,clientid,enonce1,useragent" |
|
|
|
|
HISTORYDATECONTROL ") values (" PQPARAM12 ")"; |
|
|
|
|
"(authid,poolinstance,userid,workername,clientid,enonce1,useragent,preauth" |
|
|
|
|
HISTORYDATECONTROL ") values (" PQPARAM13 ")"; |
|
|
|
|
|
|
|
|
|
res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); |
|
|
|
|
rescode = PQresultStatus(res); |
|
|
|
@ -5704,7 +5731,7 @@ static bool auths_fill(PGconn *conn)
|
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): select", __func__); |
|
|
|
|
|
|
|
|
|
// TODO: keep last x - since a user may login and mine for 100 days
|
|
|
|
|
// TODO: add/update a (single) fake auth every ~10min or 10min after the last one?
|
|
|
|
|
sel = "select " |
|
|
|
|
"authid,userid,workername,clientid,enonce1,useragent" |
|
|
|
|
HISTORYDATECONTROL |
|
|
|
@ -6810,7 +6837,6 @@ static void clean_up(ckpool_t *ckp)
|
|
|
|
|
fclose(ckp->logfp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: skip ones not needed for confirm_summaries()
|
|
|
|
|
static void alloc_storage() |
|
|
|
|
{ |
|
|
|
|
workqueue_free = k_new_list("WorkQueue", sizeof(WORKQUEUE), |
|
|
|
@ -6869,6 +6895,7 @@ static void alloc_storage()
|
|
|
|
|
ALLOC_BLOCKS, LIMIT_BLOCKS, true); |
|
|
|
|
blocks_store = k_new_store(blocks_free); |
|
|
|
|
blocks_root = new_ktree(); |
|
|
|
|
blocks_free->dsp_func = dsp_blocks; |
|
|
|
|
|
|
|
|
|
miningpayouts_free = k_new_list("MiningPayouts", sizeof(MININGPAYOUTS), |
|
|
|
|
ALLOC_MININGPAYOUTS, LIMIT_MININGPAYOUTS, true); |
|
|
|
@ -6955,9 +6982,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
|
|
|
|
|
{ |
|
|
|
|
char reply[1024] = ""; |
|
|
|
|
size_t siz = sizeof(reply); |
|
|
|
|
|
|
|
|
|
K_ITEM *i_username, *i_emailaddress, *i_passwordhash; |
|
|
|
|
bool ok; |
|
|
|
|
K_ITEM *i_username, *i_emailaddress, *i_passwordhash, *u_item; |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); |
|
|
|
|
|
|
|
|
@ -6973,12 +6998,12 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
|
|
|
|
|
if (!i_passwordhash) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
ok = users_add(conn, DATA_TRANSFER(i_username)->data, |
|
|
|
|
u_item = users_add(conn, DATA_TRANSFER(i_username)->data, |
|
|
|
|
DATA_TRANSFER(i_emailaddress)->data, |
|
|
|
|
DATA_TRANSFER(i_passwordhash)->data, |
|
|
|
|
by, code, inet, now, trf_root); |
|
|
|
|
|
|
|
|
|
if (!ok) { |
|
|
|
|
if (!u_item) { |
|
|
|
|
LOGERR("%s() %s.failed.DBE", __func__, id); |
|
|
|
|
return strdup("failed.DBE"); |
|
|
|
|
} |
|
|
|
@ -7272,6 +7297,8 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
char tmp[1024]; |
|
|
|
|
char *buf; |
|
|
|
|
size_t len, off; |
|
|
|
|
int32_t height = -1; |
|
|
|
|
tv_t first_cd = {0,0}; |
|
|
|
|
int rows; |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); |
|
|
|
@ -7282,6 +7309,10 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
K_RLOCK(blocks_free); |
|
|
|
|
b_item = last_in_ktree(blocks_root, ctx); |
|
|
|
|
while (b_item && rows < 42) { |
|
|
|
|
if (height != DATA_BLOCKS(b_item)->height) { |
|
|
|
|
height = DATA_BLOCKS(b_item)->height; |
|
|
|
|
copy_tv(&first_cd, &(DATA_BLOCKS(b_item)->createdate)); |
|
|
|
|
} |
|
|
|
|
if (CURRENT(&(DATA_BLOCKS(b_item)->expirydate))) { |
|
|
|
|
int_to_buf(DATA_BLOCKS(b_item)->height, reply, sizeof(reply)); |
|
|
|
|
snprintf(tmp, sizeof(tmp), "height%d=%s%c", rows, reply, FLDSEP); |
|
|
|
@ -7303,6 +7334,11 @@ static char *cmd_blocklist(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
snprintf(tmp, sizeof(tmp), "workername%d=%s%c", rows, reply, FLDSEP); |
|
|
|
|
APPEND_REALLOC(buf, off, len, tmp); |
|
|
|
|
|
|
|
|
|
snprintf(tmp, sizeof(tmp), |
|
|
|
|
"firstcreatedate%d=%ld%c", rows, |
|
|
|
|
first_cd.tv_sec, FLDSEP); |
|
|
|
|
APPEND_REALLOC(buf, off, len, tmp); |
|
|
|
|
|
|
|
|
|
snprintf(tmp, sizeof(tmp), |
|
|
|
|
"createdate%d=%ld%c", rows, |
|
|
|
|
DATA_BLOCKS(b_item)->createdate.tv_sec, FLDSEP); |
|
|
|
@ -8210,6 +8246,9 @@ static char *cmd_blocks_do(PGconn *conn, char *cmd, char *id, char *by,
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!ok) { |
|
|
|
|
/* Ignore during startup,
|
|
|
|
|
* another error should have shown if it matters */ |
|
|
|
|
if (startup_complete) |
|
|
|
|
LOGERR("%s() %s.failed.DBE", __func__, id); |
|
|
|
|
return strdup("failed.DBE"); |
|
|
|
|
} |
|
|
|
@ -8244,7 +8283,7 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
|
|
|
|
|
char reply[1024] = ""; |
|
|
|
|
size_t siz = sizeof(reply); |
|
|
|
|
K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid; |
|
|
|
|
K_ITEM *i_enonce1, *i_useragent; |
|
|
|
|
K_ITEM *i_enonce1, *i_useragent, *i_preauth; |
|
|
|
|
char *secuserid; |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); |
|
|
|
@ -8273,13 +8312,18 @@ static char *cmd_auth_do(PGconn *conn, char *cmd, char *id, char *by,
|
|
|
|
|
if (!i_useragent) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_preauth = optional_name(trf_root, "preauth", 1, NULL); |
|
|
|
|
if (!i_preauth) |
|
|
|
|
i_preauth = &auth_preauth; |
|
|
|
|
|
|
|
|
|
secuserid = auths_add(conn, DATA_TRANSFER(i_poolinstance)->data, |
|
|
|
|
DATA_TRANSFER(i_username)->data, |
|
|
|
|
DATA_TRANSFER(i_workername)->data, |
|
|
|
|
DATA_TRANSFER(i_clientid)->data, |
|
|
|
|
DATA_TRANSFER(i_enonce1)->data, |
|
|
|
|
DATA_TRANSFER(i_useragent)->data, |
|
|
|
|
by, code, inet, cd, igndup, trf_root); |
|
|
|
|
DATA_TRANSFER(i_preauth)->data, |
|
|
|
|
by, code, inet, cd, igndup, trf_root, false); |
|
|
|
|
|
|
|
|
|
if (!secuserid) { |
|
|
|
|
LOGDEBUG("%s() %s.failed.DBE", __func__, id); |
|
|
|
@ -8309,6 +8353,83 @@ static char *cmd_auth(PGconn *conn, char *cmd, char *id,
|
|
|
|
|
return cmd_auth_do(conn, cmd, id, by, code, inet, cd, igndup, trf_root); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static char *cmd_addrauth_do(PGconn *conn, char *cmd, char *id, char *by, |
|
|
|
|
char *code, char *inet, tv_t *cd, bool igndup, |
|
|
|
|
K_TREE *trf_root) |
|
|
|
|
{ |
|
|
|
|
char reply[1024] = ""; |
|
|
|
|
size_t siz = sizeof(reply); |
|
|
|
|
K_ITEM *i_poolinstance, *i_username, *i_workername, *i_clientid; |
|
|
|
|
K_ITEM *i_enonce1, *i_useragent, *i_preauth; |
|
|
|
|
char *secuserid; |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); |
|
|
|
|
|
|
|
|
|
i_poolinstance = optional_name(trf_root, "poolinstance", 1, NULL); |
|
|
|
|
if (!i_poolinstance) |
|
|
|
|
i_poolinstance = &auth_poolinstance; |
|
|
|
|
|
|
|
|
|
i_username = require_name(trf_root, "username", 1, NULL, reply, siz); |
|
|
|
|
if (!i_username) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_workername = require_name(trf_root, "workername", 1, NULL, reply, siz); |
|
|
|
|
if (!i_workername) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_clientid = require_name(trf_root, "clientid", 1, NULL, reply, siz); |
|
|
|
|
if (!i_clientid) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_enonce1 = require_name(trf_root, "enonce1", 1, NULL, reply, siz); |
|
|
|
|
if (!i_enonce1) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_useragent = require_name(trf_root, "useragent", 0, NULL, reply, siz); |
|
|
|
|
if (!i_useragent) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
i_preauth = require_name(trf_root, "preauth", 1, NULL, reply, siz); |
|
|
|
|
if (!i_preauth) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
secuserid = auths_add(conn, DATA_TRANSFER(i_poolinstance)->data, |
|
|
|
|
DATA_TRANSFER(i_username)->data, |
|
|
|
|
DATA_TRANSFER(i_workername)->data, |
|
|
|
|
DATA_TRANSFER(i_clientid)->data, |
|
|
|
|
DATA_TRANSFER(i_enonce1)->data, |
|
|
|
|
DATA_TRANSFER(i_useragent)->data, |
|
|
|
|
DATA_TRANSFER(i_preauth)->data, |
|
|
|
|
by, code, inet, cd, igndup, trf_root, true); |
|
|
|
|
|
|
|
|
|
if (!secuserid) { |
|
|
|
|
LOGDEBUG("%s() %s.failed.DBE", __func__, id); |
|
|
|
|
return strdup("failed.DBE"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LOGDEBUG("%s.ok.auth added for %s", id, secuserid); |
|
|
|
|
snprintf(reply, siz, "ok.%s", secuserid); |
|
|
|
|
return strdup(reply); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static char *cmd_addrauth(PGconn *conn, char *cmd, char *id, |
|
|
|
|
__maybe_unused tv_t *now, char *by, |
|
|
|
|
char *code, char *inet, tv_t *cd, |
|
|
|
|
K_TREE *trf_root) |
|
|
|
|
{ |
|
|
|
|
bool igndup = false; |
|
|
|
|
|
|
|
|
|
// confirm_summaries() doesn't call this
|
|
|
|
|
if (reloading) { |
|
|
|
|
if (tv_equal(cd, &(dbstatus.newest_createdate_auths))) |
|
|
|
|
igndup = true; |
|
|
|
|
else if (tv_newer(cd, &(dbstatus.newest_createdate_auths))) |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return cmd_addrauth_do(conn, cmd, id, by, code, inet, cd, igndup, trf_root); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static char *cmd_homepage(__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, |
|
|
|
@ -8347,7 +8468,9 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: handle orphans
|
|
|
|
|
K_RLOCK(blocks_free); |
|
|
|
|
b_item = last_in_ktree(blocks_root, ctx); |
|
|
|
|
K_RUNLOCK(blocks_free); |
|
|
|
|
if (b_item) { |
|
|
|
|
tvs_to_buf(&(DATA_BLOCKS(b_item)->createdate), reply, sizeof(reply)); |
|
|
|
|
snprintf(tmp, sizeof(tmp), "lastblock=%s%cconfirmed=%s%c", |
|
|
|
@ -8509,6 +8632,7 @@ static K_TREE *upd_add_mu(K_TREE *mu_root, K_STORE *mu_store, int64_t userid, in
|
|
|
|
|
The value of diff_want defaults to the block's network difficulty |
|
|
|
|
(block_ndiff) but can be changed with diff_times and diff_add to: |
|
|
|
|
block_ndiff * diff_times + diff_add |
|
|
|
|
N.B. diff_times and diff_add can be zero, positive or negative |
|
|
|
|
The pplns_elapsed time of the shares is from the createdate of the |
|
|
|
|
begin_workinfoid that has shares accounted to the total, |
|
|
|
|
up to the createdate of the last share |
|
|
|
@ -8573,8 +8697,10 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
blocks.height = height + 1; |
|
|
|
|
blocks.blockhash[0] = '\0'; |
|
|
|
|
look.data = (void *)(&blocks); |
|
|
|
|
K_RLOCK(blocks_free); |
|
|
|
|
b_item = find_before_in_ktree(blocks_root, &look, cmp_blocks, ctx); |
|
|
|
|
if (!b_item) { |
|
|
|
|
K_RUNLOCK(blocks_free); |
|
|
|
|
snprintf(reply, siz, "ERR.no block height %d", height); |
|
|
|
|
return strdup(reply); |
|
|
|
|
} |
|
|
|
@ -8583,6 +8709,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
break; |
|
|
|
|
b_item = prev_in_ktree(ctx); |
|
|
|
|
} |
|
|
|
|
K_RUNLOCK(blocks_free); |
|
|
|
|
if (!b_item || DATA_BLOCKS(b_item)->height != height) { |
|
|
|
|
snprintf(reply, siz, "ERR.unconfirmed block %d", height); |
|
|
|
|
return strdup(reply); |
|
|
|
@ -8600,6 +8727,13 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
hex2bin(ndiffbin, DATA_WORKINFO(w_item)->bits, 4); |
|
|
|
|
ndiff = diff_from_nbits(ndiffbin); |
|
|
|
|
diff_want = ndiff * diff_times + diff_add; |
|
|
|
|
if (diff_want < 1.0) { |
|
|
|
|
snprintf(reply, siz, |
|
|
|
|
"ERR.invalid diff_want result %f", |
|
|
|
|
diff_want); |
|
|
|
|
return strdup(reply); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
begin_workinfoid = 0; |
|
|
|
|
share_count = 0; |
|
|
|
|
total = 0; |
|
|
|
@ -8634,7 +8768,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
snprintf(reply, siz, |
|
|
|
|
"ERR.sharesummary not ready in workinfo %"PRId64, |
|
|
|
|
"ERR.sharesummary1 not ready in workinfo %"PRId64, |
|
|
|
|
DATA_SHARESUMMARY(ss_item)->workinfoid); |
|
|
|
|
goto shazbot; |
|
|
|
|
} |
|
|
|
@ -8659,7 +8793,7 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
|
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
snprintf(reply, siz, |
|
|
|
|
"ERR.sharesummary not ready in workinfo %"PRId64, |
|
|
|
|
"ERR.sharesummary2 not ready in workinfo %"PRId64, |
|
|
|
|
DATA_SHARESUMMARY(ss_item)->workinfoid); |
|
|
|
|
goto shazbot; |
|
|
|
|
} |
|
|
|
@ -8818,6 +8952,8 @@ static char *cmd_dsp(__maybe_unused PGconn *conn, __maybe_unused char *cmd,
|
|
|
|
|
if (!i_file) |
|
|
|
|
return strdup(reply); |
|
|
|
|
|
|
|
|
|
dsp_ktree(blocks_free, blocks_root, DATA_BLOCKS(i_file)->data, NULL); |
|
|
|
|
|
|
|
|
|
dsp_ktree(transfer_free, trf_root, DATA_TRANSFER(i_file)->data, NULL); |
|
|
|
|
|
|
|
|
|
dsp_ktree(sharesummary_free, sharesummary_root, DATA_TRANSFER(i_file)->data, NULL); |
|
|
|
@ -8964,6 +9100,7 @@ static struct CMDS {
|
|
|
|
|
{ CMD_SHARELOG, STR_SHAREERRORS, false, true, cmd_sharelog, ACCESS_POOL }, |
|
|
|
|
{ CMD_SHARELOG, STR_AGEWORKINFO, false, true, cmd_sharelog, ACCESS_POOL }, |
|
|
|
|
{ CMD_AUTH, "authorise", false, true, cmd_auth, ACCESS_POOL }, |
|
|
|
|
{ CMD_ADDRAUTH, "addrauth", false, true, cmd_addrauth, ACCESS_POOL }, |
|
|
|
|
{ CMD_ADDUSER, "adduser", false, false, cmd_adduser, ACCESS_WEB }, |
|
|
|
|
{ CMD_NEWPASS, "newpass", false, false, cmd_newpass, ACCESS_WEB }, |
|
|
|
|
{ CMD_CHKPASS, "chkpass", false, false, cmd_chkpass, ACCESS_WEB }, |
|
|
|
@ -9470,6 +9607,16 @@ static void *logger(__maybe_unused void *arg)
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#define STORELASTREPLY(_cmd) do { \ |
|
|
|
|
if (last_ ## _cmd) \
|
|
|
|
|
free(last_ ## _cmd); \
|
|
|
|
|
last_ ## _cmd = buf; \
|
|
|
|
|
buf = NULL; \
|
|
|
|
|
if (reply_ ## _cmd) \
|
|
|
|
|
free(reply_ ## _cmd); \
|
|
|
|
|
reply_ ## _cmd = rep; \
|
|
|
|
|
} while (0) |
|
|
|
|
|
|
|
|
|
static void *socketer(__maybe_unused void *arg) |
|
|
|
|
{ |
|
|
|
|
proc_instance_t *pi = (proc_instance_t *)arg; |
|
|
|
@ -9477,6 +9624,7 @@ static void *socketer(__maybe_unused void *arg)
|
|
|
|
|
char *end, *ans = NULL, *rep = NULL, *buf = NULL, *dot; |
|
|
|
|
char cmd[CMD_SIZ+1], id[ID_SIZ+1], reply[1024+1]; |
|
|
|
|
char *last_auth = NULL, *reply_auth = NULL; |
|
|
|
|
char *last_addrauth = NULL, *reply_addrauth = NULL; |
|
|
|
|
char *last_chkpass = NULL, *reply_chkpass = NULL; |
|
|
|
|
char *last_adduser = NULL, *reply_adduser = NULL; |
|
|
|
|
char *last_newpass = NULL, *reply_newpass = NULL; |
|
|
|
@ -9547,6 +9695,7 @@ static void *socketer(__maybe_unused void *arg)
|
|
|
|
|
* the reply without reprocessing the message |
|
|
|
|
*/ |
|
|
|
|
dup = false; |
|
|
|
|
// These are ordered approximately most likely first
|
|
|
|
|
if (last_auth && strcmp(last_auth, buf) == 0) { |
|
|
|
|
reply_last = reply_auth; |
|
|
|
|
dup = true; |
|
|
|
@ -9562,6 +9711,9 @@ static void *socketer(__maybe_unused void *arg)
|
|
|
|
|
} else if (last_newid && strcmp(last_newid, buf) == 0) { |
|
|
|
|
reply_last = reply_newid; |
|
|
|
|
dup = true; |
|
|
|
|
} else if (last_addrauth && strcmp(last_addrauth, buf) == 0) { |
|
|
|
|
reply_last = reply_auth; |
|
|
|
|
dup = true; |
|
|
|
|
} else if (last_web && strcmp(last_web, buf) == 0) { |
|
|
|
|
reply_last = reply_web; |
|
|
|
|
dup = true; |
|
|
|
@ -9636,6 +9788,7 @@ static void *socketer(__maybe_unused void *arg)
|
|
|
|
|
break; |
|
|
|
|
// Always process immediately:
|
|
|
|
|
case CMD_AUTH: |
|
|
|
|
case CMD_ADDRAUTH: |
|
|
|
|
// First message from the pool
|
|
|
|
|
if (want_first) { |
|
|
|
|
ck_wlock(&fpm_lock); |
|
|
|
@ -9662,49 +9815,22 @@ static void *socketer(__maybe_unused void *arg)
|
|
|
|
|
ans = NULL; |
|
|
|
|
switch (cmdnum) { |
|
|
|
|
case CMD_AUTH: |
|
|
|
|
if (last_auth) |
|
|
|
|
free(last_auth); |
|
|
|
|
last_auth = buf; |
|
|
|
|
buf = NULL; |
|
|
|
|
if (reply_auth) |
|
|
|
|
free(reply_auth); |
|
|
|
|
reply_auth = rep; |
|
|
|
|
STORELASTREPLY(auth); |
|
|
|
|
break; |
|
|
|
|
case CMD_ADDRAUTH: |
|
|
|
|
STORELASTREPLY(addrauth); |
|
|
|
|
break; |
|
|
|
|
case CMD_CHKPASS: |
|
|
|
|
if (last_chkpass) |
|
|
|
|
free(last_chkpass); |
|
|
|
|
last_chkpass = buf; |
|
|
|
|
buf = NULL; |
|
|
|
|
if (reply_chkpass) |
|
|
|
|
free(reply_chkpass); |
|
|
|
|
reply_chkpass = rep; |
|
|
|
|
STORELASTREPLY(chkpass); |
|
|
|
|
break; |
|
|
|
|
case CMD_ADDUSER: |
|
|
|
|
if (last_adduser) |
|
|
|
|
free(last_adduser); |
|
|
|
|
last_adduser = buf; |
|
|
|
|
buf = NULL; |
|
|
|
|
if (reply_adduser) |
|
|
|
|
free(reply_adduser); |
|
|
|
|
reply_adduser = rep; |
|
|
|
|
STORELASTREPLY(adduser); |
|
|
|
|
break; |
|
|
|
|
case CMD_NEWPASS: |
|
|
|
|
if (last_newpass) |
|
|
|
|
free(last_newpass); |
|
|
|
|
last_newpass = buf; |
|
|
|
|
buf = NULL; |
|
|
|
|
if (reply_newpass) |
|
|
|
|
free(reply_newpass); |
|
|
|
|
reply_newpass = rep; |
|
|
|
|
STORELASTREPLY(newpass); |
|
|
|
|
break; |
|
|
|
|
case CMD_NEWID: |
|
|
|
|
if (last_newid) |
|
|
|
|
free(last_newid); |
|
|
|
|
last_newid = buf; |
|
|
|
|
buf = NULL; |
|
|
|
|
if (reply_newid) |
|
|
|
|
free(reply_newid); |
|
|
|
|
reply_newid = rep; |
|
|
|
|
STORELASTREPLY(newid); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
free(rep); |
|
|
|
@ -9904,6 +10030,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
|
|
|
|
|
__func__, count, cmd); |
|
|
|
|
break; |
|
|
|
|
case CMD_AUTH: |
|
|
|
|
case CMD_ADDRAUTH: |
|
|
|
|
case CMD_POOLSTAT: |
|
|
|
|
case CMD_USERSTAT: |
|
|
|
|
case CMD_BLOCK: |
|
|
|
@ -10411,11 +10538,8 @@ static void confirm_reload()
|
|
|
|
|
/* The last workinfo we should process
|
|
|
|
|
* The reason for going past the last 'a' up to before |
|
|
|
|
* the first 'n' is in case there were shares missed between them - |
|
|
|
|
* but that should only be the case with a code bug - so it checks that |
|
|
|
|
* TODO: auto aging will clear 'n' sections inside the 'a's that |
|
|
|
|
* will always occur when ckpool restarts, since ckpool will never |
|
|
|
|
* send workinfo age records for workinfo that's active at shutdown - |
|
|
|
|
* Aging these can (for now) easily be done manually in psql */ |
|
|
|
|
* but that should only be the case with a code bug - |
|
|
|
|
* so it checks that */ |
|
|
|
|
if (dbstatus.newest_workinfoid_a > 0) { |
|
|
|
|
confirm_last_workinfoid = dbstatus.newest_workinfoid_a; |
|
|
|
|
last_reason = "newest aged"; |
|
|
|
|