Browse Source

Merge branch 'master' of bitbucket.org:ckolivas/ckpool

master
Con Kolivas 10 years ago
parent
commit
79367129f3
  1. 4
      pool/page.php
  2. 18
      pool/page_pplns.php
  3. 5
      pool/prime.php
  4. 19
      src/ckdb.c
  5. 21
      src/ckdb.h
  6. 229
      src/ckdb_cmd.c
  7. 49
      src/ckdb_data.c
  8. 30
      src/ckdb_dbio.c

4
pool/page.php

@ -110,8 +110,8 @@ span.err {color:red; font-weight:bold; font-size:120%;}
span.alert {color:red; font-weight:bold; font-size:250%;} span.alert {color:red; font-weight:bold; font-size:250%;}
input.tiny {width: 0px; height: 0px; margin: 0px; padding: 0px; outline: none; border: 0px;} input.tiny {width: 0px; height: 0px; margin: 0px; padding: 0px; outline: none; border: 0px;}
#n42 {margin:0; position: relative; color:#fff; background:#07e;} #n42 {margin:0; position: relative; color:#fff; background:#07e;}
#n42 a {color:#fff; text-decoration:none; margin: 4px;} #n42 a {color:#fff; text-decoration:none; padding: 6px; display:block;}
#n42 td {min-width: 100px; float: left; vertical-align: top; padding: 2px;} #n42 td {min-width: 100px; float: left; vertical-align: top; padding: 0px 2px;}
#n42 td.navboxr {float: right;} #n42 td.navboxr {float: right;}
#n42 td.nav {position: relative;} #n42 td.nav {position: relative;}
#n42 div.sub {left: 0px; z-index: 42; position: absolute; visibility: hidden;} #n42 div.sub {left: 0px; z-index: 42; position: absolute; visibility: hidden;}

18
pool/page_pplns.php

@ -14,7 +14,7 @@ function stnum($num)
return $b4.$fmt.$af; return $b4.$fmt.$af;
} }
# #
# ... Of course ... check the output and add the txin # ... Of course ... check the output and add the txin ... etc.
function calctx($ans, $count, $miner_sat, $diffacc_total) function calctx($ans, $count, $miner_sat, $diffacc_total)
{ {
$pg = '<br><table cellpadding=0 cellspacing=0 border=0>'; $pg = '<br><table cellpadding=0 cellspacing=0 border=0>';
@ -159,6 +159,7 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
$ans['miner_sat'] = $miner_sat; $ans['miner_sat'] = $miner_sat;
$data = array( 'Block' => 'block', $data = array( 'Block' => 'block',
'Block Status' => 'block_status',
'Block Hash' => 'block_hash', 'Block Hash' => 'block_hash',
'Block Reward (Satoshis)' => 'block_reward', 'Block Reward (Satoshis)' => 'block_reward',
'Miner Reward (Satoshis)' => 'miner_sat', 'Miner Reward (Satoshis)' => 'miner_sat',
@ -182,6 +183,21 @@ Block: <input type=text name=blk size=10 value='$blkuse'>
$pg = '<br><a href=https://blockchain.info/block-height/'; $pg = '<br><a href=https://blockchain.info/block-height/';
$pg .= $ans['block'].'>Blockchain '.$ans['block']."</a><br>\n"; $pg .= $ans['block'].'>Blockchain '.$ans['block']."</a><br>\n";
if (strlen($ans['block_extra']) > 0)
{
$pg .= '<br><span class=err>';
$msg = $ans['block_status'].' - '.$ans['block_extra'];
$pg .= str_replace(' ', '&nbsp;', $msg)."</span><br>\n";
}
if (strlen($ans['share_status']) > 0)
{
$pg .= '<br><span class=err>';
$msg = $ans['share_status']." - Can't be paid out yet";
$pg .= str_replace(' ', '&nbsp;', $msg)."</span><br>\n";
}
$pg .= "<br><table callpadding=0 cellspacing=0 border=0>\n"; $pg .= "<br><table callpadding=0 cellspacing=0 border=0>\n";
$pg .= '<tr class=title>'; $pg .= '<tr class=title>';
$pg .= '<td class=dl>Name</td>'; $pg .= '<td class=dl>Name</td>';

5
pool/prime.php

@ -69,8 +69,9 @@ function check()
'API' => 'api' 'API' => 'api'
), ),
'Help' => array( 'Help' => array(
'Help' => 'help', 'Payouts' => 'payout',
'Payouts' => 'payout' 'Workers ' => 'workers',
'Blocks' => 'blocks'
) )
); );
tryLogInOut(); tryLogInOut();

19
src/ckdb.c

@ -174,8 +174,12 @@ const char *mailpatt = "^[A-Za-z0-9_-][A-Za-z0-9_\\.-]*@[A-Za-z0-9][A-Za-z0-9\\.
const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$"; const char *idpatt = "^[_A-Za-z][_A-Za-z0-9]*$";
const char *intpatt = "^[0-9][0-9]*$"; const char *intpatt = "^[0-9][0-9]*$";
const char *hashpatt = "^[A-Fa-f0-9]*$"; const char *hashpatt = "^[A-Fa-f0-9]*$";
// TODO: bitcoind will check it properly /* BTC addresses start with '1' (one) or '3' (three),
const char *addrpatt = "^[A-Za-z0-9]*$"; * exclude: capital 'I' (eye), capital 'O' (oh),
* lowercase 'l' (elle) and '0' (zero)
* and with a simple test must be ADDR_MIN_LEN to ADDR_MAX_LEN (ckdb.h)
* bitcoind is used to fully validate them when required */
const char *addrpatt = "^[13][A-HJ-NP-Za-km-z1-9]*$";
// So the records below have the same 'name' as the klist // So the records below have the same 'name' as the klist
const char Transfer[] = "Transfer"; const char Transfer[] = "Transfer";
@ -1652,7 +1656,7 @@ static void summarise_blocks()
if (WMREADY(workmarkers->status)) { if (WMREADY(workmarkers->status)) {
lookmarkersummary.markerid = workmarkers->markerid; lookmarkersummary.markerid = workmarkers->markerid;
lookmarkersummary.userid = MAXID; lookmarkersummary.userid = MAXID;
lookmarkersummary.workername[0] = '\0'; lookmarkersummary.workername = EMPTY;
INIT_MARKERSUMMARY(&ms_look); INIT_MARKERSUMMARY(&ms_look);
ms_look.data = (void *)(&lookmarkersummary); ms_look.data = (void *)(&lookmarkersummary);
ms_item = find_before_in_ktree(markersummary_root, &ms_look, ms_item = find_before_in_ktree(markersummary_root, &ms_look,
@ -2048,6 +2052,7 @@ static void *socketer(__maybe_unused void *arg)
char *last_newid = NULL, *reply_newid = NULL; char *last_newid = NULL, *reply_newid = NULL;
char *last_setatts = NULL, *reply_setatts = NULL; char *last_setatts = NULL, *reply_setatts = NULL;
char *last_setopts = NULL, *reply_setopts = NULL; char *last_setopts = NULL, *reply_setopts = NULL;
char *last_userstatus = NULL, *reply_userstatus = NULL;
char *last_web = NULL, *reply_web = NULL; char *last_web = NULL, *reply_web = NULL;
char *reply_last, duptype[CMD_SIZ+1]; char *reply_last, duptype[CMD_SIZ+1];
enum cmd_values cmdnum; enum cmd_values cmdnum;
@ -2151,6 +2156,9 @@ static void *socketer(__maybe_unused void *arg)
} else if (last_setopts && strcmp(last_setopts, buf) == 0) { } else if (last_setopts && strcmp(last_setopts, buf) == 0) {
reply_last = reply_setopts; reply_last = reply_setopts;
dup = true; dup = true;
} else if (last_userstatus && strcmp(last_userstatus, buf) == 0) {
reply_last = reply_userstatus;
dup = true;
} else if (last_web && strcmp(last_web, buf) == 0) { } else if (last_web && strcmp(last_web, buf) == 0) {
reply_last = reply_web; reply_last = reply_web;
dup = true; dup = true;
@ -2251,6 +2259,7 @@ static void *socketer(__maybe_unused void *arg)
case CMD_BLOCKLIST: case CMD_BLOCKLIST:
case CMD_NEWID: case CMD_NEWID:
case CMD_STATS: case CMD_STATS:
case CMD_USERSTATUS:
ans = ckdb_cmds[which_cmds].func(NULL, cmd, id, &now, ans = ckdb_cmds[which_cmds].func(NULL, cmd, id, &now,
by_default, by_default,
(char *)__func__, (char *)__func__,
@ -2293,6 +2302,9 @@ static void *socketer(__maybe_unused void *arg)
case CMD_SETOPTS: case CMD_SETOPTS:
STORELASTREPLY(setopts); STORELASTREPLY(setopts);
break; break;
case CMD_USERSTATUS:
STORELASTREPLY(userstatus);
break;
// The rest // The rest
default: default:
free(rep); free(rep);
@ -2499,6 +2511,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
case CMD_DSP: case CMD_DSP:
case CMD_STATS: case CMD_STATS:
case CMD_PPLNS: case CMD_PPLNS:
case CMD_USERSTATUS:
LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored", LOGERR("%s() Message line %"PRIu64" '%s' - invalid - ignored",
__func__, count, cmd); __func__, count, cmd);
break; break;

21
src/ckdb.h

@ -52,7 +52,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "0.9.4" #define DB_VERSION "0.9.4"
#define CKDB_VERSION DB_VERSION"-0.631" #define CKDB_VERSION DB_VERSION"-0.645"
#define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL " - from %s %s() line %d"
#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ #define WHERE_FFL_HERE __FILE__, __func__, __LINE__
@ -80,6 +80,14 @@ extern const char *intpatt;
extern const char *hashpatt; extern const char *hashpatt;
extern const char *addrpatt; extern const char *addrpatt;
/* If a trimmed username is like an address but this many or more characters,
* disallow it */
#define ADDR_USER_CHECK 16
// BTC address size
#define ADDR_MIN_LEN 26
#define ADDR_MAX_LEN 34
typedef struct loadstatus { typedef struct loadstatus {
tv_t oldest_sharesummary_firstshare_n; tv_t oldest_sharesummary_firstshare_n;
tv_t newest_sharesummary_firstshare_a; tv_t newest_sharesummary_firstshare_a;
@ -295,6 +303,7 @@ enum cmd_values {
CMD_DSP, CMD_DSP,
CMD_STATS, CMD_STATS,
CMD_PPLNS, CMD_PPLNS,
CMD_USERSTATUS,
CMD_END CMD_END
}; };
@ -603,7 +612,8 @@ typedef struct transfer {
char *mvalue; char *mvalue;
} TRANSFER; } TRANSFER;
#define ALLOC_TRANSFER 64 // Suggest malloc use MMAP - 1913 = largest under 2MB
#define ALLOC_TRANSFER 1913
#define LIMIT_TRANSFER 0 #define LIMIT_TRANSFER 0
#define CULL_TRANSFER 1024 #define CULL_TRANSFER 1024
#define INIT_TRANSFER(_item) INIT_GENERIC(_item, transfer) #define INIT_TRANSFER(_item) INIT_GENERIC(_item, transfer)
@ -632,7 +642,7 @@ typedef struct users {
int64_t userid; int64_t userid;
char username[TXT_BIG+1]; char username[TXT_BIG+1];
char usertrim[TXT_BIG+1]; // Non DB field char usertrim[TXT_BIG+1]; // Non DB field
// TODO: Anything in 'status' disables the account // Anything in 'status' fails mining authentication
char status[TXT_BIG+1]; char status[TXT_BIG+1];
char emailaddress[TXT_BIG+1]; char emailaddress[TXT_BIG+1];
tv_t joineddate; tv_t joineddate;
@ -1334,6 +1344,7 @@ extern PGconn *dbconnect();
extern char *safe_text(char *txt); extern char *safe_text(char *txt);
extern void username_trim(USERS *users); extern void username_trim(USERS *users);
extern bool like_address(char *username);
extern void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS); extern void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS);
@ -1534,9 +1545,9 @@ extern char *pqerrmsg(PGconn *conn);
extern int64_t nextid(PGconn *conn, char *idname, int64_t increment, extern int64_t nextid(PGconn *conn, char *idname, int64_t increment,
tv_t *cd, char *by, char *code, char *inet); tv_t *cd, char *by, char *code, char *inet);
extern bool users_pass_email(PGconn *conn, K_ITEM *u_item, char *oldhash, extern bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash,
char *newhash, char *email, char *by, char *code, char *newhash, char *email, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root); char *inet, tv_t *cd, K_TREE *trf_root, char *status);
extern K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, extern K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress,
char *passwordhash, char *by, char *code, char *inet, char *passwordhash, char *by, char *code, char *inet,
tv_t *cd, K_TREE *trf_root); tv_t *cd, K_TREE *trf_root);

229
src/ckdb_cmd.c

@ -15,7 +15,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
{ {
char reply[1024] = ""; char reply[1024] = "";
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
K_ITEM *i_username, *i_emailaddress, *i_passwordhash, *u_item; K_ITEM *i_username, *i_emailaddress, *i_passwordhash, *u_item = NULL;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd); LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
@ -23,11 +23,22 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
if (!i_username) if (!i_username)
return strdup(reply); return strdup(reply);
i_emailaddress = require_name(trf_root, "emailaddress", 7, (char *)mailpatt, reply, siz); /* If a username added from the web site looks like an address
* then disallow it - a false positive is not an issue
* Allowing it will create a security issue - someone could create
* an account with someone else's, as yet unused, payout address
* and redirect the payout to another payout address.
* ... and the person who owns the payout address can't check that
* in advance, they'll just find out with their first payout not
* arriving at their payout address */
if (!like_address(transfer_data(i_username))) {
i_emailaddress = require_name(trf_root, "emailaddress", 7,
(char *)mailpatt, reply, siz);
if (!i_emailaddress) if (!i_emailaddress)
return strdup(reply); return strdup(reply);
i_passwordhash = require_name(trf_root, "passwordhash", 64, (char *)hashpatt, reply, siz); i_passwordhash = require_name(trf_root, "passwordhash", 64,
(char *)hashpatt, reply, siz);
if (!i_passwordhash) if (!i_passwordhash)
return strdup(reply); return strdup(reply);
@ -35,6 +46,7 @@ static char *cmd_adduser(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
transfer_data(i_emailaddress), transfer_data(i_emailaddress),
transfer_data(i_passwordhash), transfer_data(i_passwordhash),
by, code, inet, now, trf_root); by, code, inet, now, trf_root);
}
if (!u_item) { if (!u_item) {
LOGERR("%s() %s.failed.DBE", __func__, id); LOGERR("%s() %s.failed.DBE", __func__, id);
@ -85,12 +97,13 @@ static char *cmd_newpass(__maybe_unused PGconn *conn, char *cmd, char *id,
K_RUNLOCK(users_free); K_RUNLOCK(users_free);
if (u_item) { if (u_item) {
ok = users_pass_email(NULL, u_item, ok = users_update(NULL, u_item,
oldhash, oldhash,
transfer_data(i_newhash), transfer_data(i_newhash),
NULL, NULL,
by, code, inet, now, by, code, inet, now,
trf_root); trf_root,
NULL);
} else } else
ok = false; ok = false;
} }
@ -223,7 +236,8 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
email = NULL; email = NULL;
} }
i_address = optional_name(trf_root, "address", i_address = optional_name(trf_root, "address",
27, (char *)addrpatt, ADDR_MIN_LEN,
(char *)addrpatt,
reply, siz); reply, siz);
if (i_address) if (i_address)
address = transfer_data(i_address); address = transfer_data(i_address);
@ -248,10 +262,12 @@ static char *cmd_userset(PGconn *conn, char *cmd, char *id,
} }
if (email && *email) { if (email && *email) {
ok = users_pass_email(conn, u_item, NULL, ok = users_update(conn, u_item,
NULL, email, NULL, NULL,
by, code, inet, email,
now, trf_root); by, code, inet, now,
trf_root,
NULL);
if (!ok) { if (!ok) {
reason = "email error"; reason = "email error";
goto struckout; goto struckout;
@ -2909,6 +2925,9 @@ static K_TREE *upd_add_mu(K_TREE *mu_root, K_STORE *mu_store, int64_t userid, in
(also summarising diffacc per user) (also summarising diffacc per user)
then keep stepping back until we complete the current begin_workinfoid then keep stepping back until we complete the current begin_workinfoid
(also summarising diffacc per user) (also summarising diffacc per user)
While we are still below diff_want
find each workmarker and add on the full set of worksummary
diffacc shares (also summarising diffacc per user)
This will give us the total number of diff1 shares (diffacc_total) This will give us the total number of diff1 shares (diffacc_total)
to use for the payment calculations to use for the payment calculations
The value of diff_want defaults to the block's network difficulty The value of diff_want defaults to the block's network difficulty
@ -2922,21 +2941,26 @@ static K_TREE *upd_add_mu(K_TREE *mu_root, K_STORE *mu_store, int64_t userid, in
diffacc_user * 2^32 / pplns_elapsed diffacc_user * 2^32 / pplns_elapsed
PPLNS fraction of the payout would be: PPLNS fraction of the payout would be:
diffacc_user / diffacc_total diffacc_user / diffacc_total
N.B. 'begin' means the oldest back in time and 'end' means the newest
'end' should usually be the info of the found block with the pplns
data going back in time to 'begin'
*/ */
/* TODO: redesign to include workmarkers
* ... before next payout that extends into a markersummary ... */
static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id, static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
__maybe_unused tv_t *now, __maybe_unused char *by, __maybe_unused tv_t *now, __maybe_unused char *by,
__maybe_unused char *code, __maybe_unused char *inet, __maybe_unused char *code, __maybe_unused char *inet,
__maybe_unused tv_t *notcd, K_TREE *trf_root) __maybe_unused tv_t *notcd, K_TREE *trf_root)
{ {
char reply[1024], tmp[1024], *buf; char reply[1024], tmp[1024], *buf, *block_extra, *share_status = EMPTY;
size_t siz = sizeof(reply); size_t siz = sizeof(reply);
K_ITEM *i_height, *i_difftimes, *i_diffadd, *i_allowaged; K_ITEM *i_height, *i_difftimes, *i_diffadd, *i_allowaged;
K_ITEM b_look, ss_look, *b_item, *w_item, *ss_item; K_ITEM b_look, ss_look, *b_item, *w_item, *ss_item;
K_ITEM wm_look, *wm_item, ms_look, *ms_item;
K_ITEM *mu_item, *wb_item, *u_item; K_ITEM *mu_item, *wb_item, *u_item;
SHARESUMMARY looksharesummary, *sharesummary; SHARESUMMARY looksharesummary, *sharesummary;
WORKMARKERS lookworkmarkers, *workmarkers;
MARKERSUMMARY lookmarkersummary, *markersummary;
MININGPAYOUTS *miningpayouts; MININGPAYOUTS *miningpayouts;
WORKINFO *workinfo; WORKINFO *workinfo;
TRANSFER *transfer; TRANSFER *transfer;
@ -2945,12 +2969,12 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
K_STORE *mu_store; K_STORE *mu_store;
USERS *users; USERS *users;
int32_t height; int32_t height;
int64_t workinfoid, end_workinfoid; int64_t workinfoid, end_workinfoid = 0;
int64_t begin_workinfoid; int64_t begin_workinfoid;
int64_t share_count; int64_t share_count;
char tv_buf[DATE_BUFSIZ]; char tv_buf[DATE_BUFSIZ];
tv_t cd, begin_tv, block_tv, end_tv; tv_t cd, begin_tv, block_tv, end_tv;
K_TREE_CTX ctx[1]; K_TREE_CTX ctx[1], wm_ctx[1], ms_ctx[1];
double ndiff, total, elapsed; double ndiff, total, elapsed;
double diff_times = 1.0; double diff_times = 1.0;
double diff_add = 0.0; double diff_add = 0.0;
@ -2996,16 +3020,28 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
} }
DATA_BLOCKS_NULL(blocks, b_item); DATA_BLOCKS_NULL(blocks, b_item);
while (b_item && blocks->height == height) { while (b_item && blocks->height == height) {
if (blocks->confirmed[0] == BLOCKS_CONFIRM) // Allow any state, but report it
if (CURRENT(&(blocks->expirydate)))
break; break;
b_item = prev_in_ktree(ctx); b_item = prev_in_ktree(ctx);
DATA_BLOCKS_NULL(blocks, b_item); DATA_BLOCKS_NULL(blocks, b_item);
} }
K_RUNLOCK(blocks_free); K_RUNLOCK(blocks_free);
if (!b_item || blocks->height != height) { if (!b_item || blocks->height != height) {
snprintf(reply, siz, "ERR.unconfirmed block %d", height); snprintf(reply, siz, "ERR.no current block %d", height);
return strdup(reply); return strdup(reply);
} }
switch (blocks->confirmed[0]) {
case BLOCKS_NEW:
block_extra = "Can't be paid out yet";
break;
case BLOCKS_ORPHAN:
block_extra = "Can't be paid out";
break;
default:
block_extra = EMPTY;
break;
}
workinfoid = blocks->workinfoid; workinfoid = blocks->workinfoid;
copy_tv(&block_tv, &(blocks->createdate)); copy_tv(&block_tv, &(blocks->createdate));
copy_tv(&end_tv, &(blocks->createdate)); copy_tv(&end_tv, &(blocks->createdate));
@ -3031,31 +3067,26 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
share_count = 0; share_count = 0;
total = 0; total = 0;
mu_store = k_new_store(miningpayouts_free);
mu_root = new_ktree();
looksharesummary.workinfoid = workinfoid; looksharesummary.workinfoid = workinfoid;
looksharesummary.userid = MAXID; looksharesummary.userid = MAXID;
looksharesummary.workername[0] = '\0'; looksharesummary.workername[0] = '\0';
INIT_SHARESUMMARY(&ss_look); INIT_SHARESUMMARY(&ss_look);
ss_look.data = (void *)(&looksharesummary); ss_look.data = (void *)(&looksharesummary);
K_RLOCK(sharesummary_free); K_RLOCK(sharesummary_free);
K_RLOCK(workmarkers_free);
K_RLOCK(markersummary_free);
ss_item = find_before_in_ktree(sharesummary_workinfoid_root, &ss_look, ss_item = find_before_in_ktree(sharesummary_workinfoid_root, &ss_look,
cmp_sharesummary_workinfoid, ctx); cmp_sharesummary_workinfoid, ctx);
if (!ss_item) { DATA_SHARESUMMARY_NULL(sharesummary, ss_item);
K_RUNLOCK(sharesummary_free); if (ss_item)
snprintf(reply, siz,
"ERR.no shares found with or before "
"workinfo %"PRId64,
workinfoid);
return strdup(reply);
}
DATA_SHARESUMMARY(sharesummary, ss_item);
mu_store = k_new_store(miningpayouts_free);
mu_root = new_ktree();
end_workinfoid = sharesummary->workinfoid; end_workinfoid = sharesummary->workinfoid;
/* add up all sharesummaries until >= diff_want /* add up all sharesummaries until >= diff_want
* also record the latest lastshare - that will be the end pplns time * also record the latest lastshare - that will be the end pplns time
* which will be >= block_tv */ * which will be >= block_tv */
while (ss_item && total < diff_want) { while (total < diff_want && ss_item) {
switch (sharesummary->complete[0]) { switch (sharesummary->complete[0]) {
case SUMMARY_CONFIRM: case SUMMARY_CONFIRM:
break; break;
@ -3063,14 +3094,9 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
if (allow_aged) if (allow_aged)
break; break;
default: default:
K_RUNLOCK(sharesummary_free); share_status = "Not ready1";
snprintf(reply, siz,
"ERR.sharesummary1 not ready in "
"workinfo %"PRId64,
sharesummary->workinfoid);
goto shazbot;
} }
share_count++; share_count += sharesummary->sharecount;
total += (int64_t)(sharesummary->diffacc); total += (int64_t)(sharesummary->diffacc);
begin_workinfoid = sharesummary->workinfoid; begin_workinfoid = sharesummary->workinfoid;
if (tv_newer(&end_tv, &(sharesummary->lastshare))) if (tv_newer(&end_tv, &(sharesummary->lastshare)))
@ -3091,12 +3117,10 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
if (allow_aged) if (allow_aged)
break; break;
default: default:
K_RUNLOCK(sharesummary_free); if (share_status == EMPTY)
snprintf(reply, siz, share_status = "Not ready2";
"ERR.sharesummary2 not ready in " else
"workinfo %"PRId64, share_status = "Not ready1+2";
sharesummary->workinfoid);
goto shazbot;
} }
share_count++; share_count++;
total += (int64_t)(sharesummary->diffacc); total += (int64_t)(sharesummary->diffacc);
@ -3106,6 +3130,50 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
ss_item = prev_in_ktree(ctx); ss_item = prev_in_ktree(ctx);
DATA_SHARESUMMARY_NULL(sharesummary, ss_item); DATA_SHARESUMMARY_NULL(sharesummary, ss_item);
} }
/* If we haven't met or exceeded the required N,
* move on to the markersummaries */
if (total < diff_want) {
lookworkmarkers.expirydate.tv_sec = default_expiry.tv_sec;
lookworkmarkers.expirydate.tv_usec = default_expiry.tv_usec;
lookworkmarkers.workinfoidend = begin_workinfoid;
INIT_WORKMARKERS(&wm_look);
wm_look.data = (void *)(&lookworkmarkers);
wm_item = find_before_in_ktree(workmarkers_root, &wm_look,
cmp_workmarkers, wm_ctx);
DATA_WORKMARKERS_NULL(workmarkers, wm_item);
while (total < diff_want && wm_item && CURRENT(&(workmarkers->expirydate))) {
if (WMREADY(workmarkers->status)) {
lookmarkersummary.markerid = workmarkers->markerid;
lookmarkersummary.userid = MAXID;
lookmarkersummary.workername = EMPTY;
INIT_MARKERSUMMARY(&ms_look);
ms_look.data = (void *)(&lookmarkersummary);
ms_item = find_before_in_ktree(markersummary_root, &ms_look,
cmp_markersummary, ms_ctx);
DATA_MARKERSUMMARY_NULL(markersummary, ms_item);
// add the whole markerid
while (ms_item && markersummary->markerid == workmarkers->markerid) {
if (end_workinfoid == 0)
end_workinfoid = workmarkers->workinfoidend;
share_count += markersummary->sharecount;
total += (int64_t)(markersummary->diffacc);
begin_workinfoid = workmarkers->workinfoidstart;
if (tv_newer(&end_tv, &(markersummary->lastshare)))
copy_tv(&end_tv, &(markersummary->lastshare));
mu_root = upd_add_mu(mu_root, mu_store,
markersummary->userid,
(int64_t)(markersummary->diffacc));
ms_item = prev_in_ktree(ms_ctx);
DATA_MARKERSUMMARY_NULL(markersummary, ms_item);
}
}
wm_item = prev_in_ktree(wm_ctx);
DATA_WORKMARKERS_NULL(workmarkers, wm_item);
}
}
K_RUNLOCK(markersummary_free);
K_RUNLOCK(workmarkers_free);
K_RUNLOCK(sharesummary_free); K_RUNLOCK(sharesummary_free);
if (total == 0.0) { if (total == 0.0) {
@ -3140,6 +3208,13 @@ static char *cmd_pplns(__maybe_unused PGconn *conn, char *cmd, char *id,
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "block_reward=%"PRId64"%c", blocks->reward, FLDSEP); snprintf(tmp, sizeof(tmp), "block_reward=%"PRId64"%c", blocks->reward, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "block_status=%s%c",
blocks_confirmed(blocks->confirmed), FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "block_extra=%s%c", block_extra, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "share_status=%s%c", share_status, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "workername=%s%c", blocks->workername, FLDSEP); snprintf(tmp, sizeof(tmp), "workername=%s%c", blocks->workername, FLDSEP);
APPEND_REALLOC(buf, off, len, tmp); APPEND_REALLOC(buf, off, len, tmp);
snprintf(tmp, sizeof(tmp), "nonce=%s%c", blocks->nonce, FLDSEP); snprintf(tmp, sizeof(tmp), "nonce=%s%c", blocks->nonce, FLDSEP);
@ -3379,6 +3454,69 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id,
return buf; return buf;
} }
// TODO: add to heartbeat to disable the miner if active and status != ""
static char *cmd_userstatus(PGconn *conn, char *cmd, char *id, tv_t *now, char *by,
char *code, char *inet, __maybe_unused tv_t *cd,
K_TREE *trf_root)
{
char reply[1024] = "";
size_t siz = sizeof(reply);
K_ITEM *i_username, *i_userid, *i_status, *u_item;
int64_t userid;
char *status;
USERS *users;
bool ok;
LOGDEBUG("%s(): cmd '%s'", __func__, cmd);
i_username = optional_name(trf_root, "username", 3, (char *)userpatt, reply, siz);
i_userid = optional_name(trf_root, "userid", 1, (char *)intpatt, reply, siz);
// Either username or userid
if (!i_username && !i_userid) {
snprintf(reply, siz, "failed.invalid/missing userinfo");
LOGERR("%s.%s", id, reply);
return strdup(reply);
}
// A zero length status re-enables it
i_status = require_name(trf_root, "status", 0, NULL, reply, siz);
if (!i_status)
return strdup(reply);
status = transfer_data(i_status);
K_RLOCK(users_free);
if (i_username)
u_item = find_users(transfer_data(i_username));
else {
TXT_TO_BIGINT("userid", transfer_data(i_userid), userid);
u_item = find_userid(userid);
}
K_RUNLOCK(users_free);
if (!u_item)
ok = false;
else {
ok = users_update(conn, u_item,
NULL, NULL,
NULL,
by, code, inet, now,
trf_root,
status);
}
if (!ok) {
LOGERR("%s() %s.failed.DBE", __func__, id);
return strdup("failed.DBE");
}
DATA_USERS(users, u_item);
snprintf(reply, siz, "ok.updated %"PRId64" %s status %s",
users->userid,
users->username,
status[0] ? "disabled" : "enabled");
LOGWARNING("%s.%s", id, reply);
return strdup(reply);
}
// TODO: limit access by having seperate sockets for each // TODO: limit access by having seperate sockets for each
#define ACCESS_POOL "p" #define ACCESS_POOL "p"
#define ACCESS_SYSTEM "s" #define ACCESS_SYSTEM "s"
@ -3479,7 +3617,8 @@ struct CMDS ckdb_cmds[] = {
{ CMD_GETOPTS, "getopts", false, false, cmd_getopts, ACCESS_WEB }, { CMD_GETOPTS, "getopts", false, false, cmd_getopts, ACCESS_WEB },
{ CMD_SETOPTS, "setopts", false, false, cmd_setopts, ACCESS_WEB }, { CMD_SETOPTS, "setopts", false, false, cmd_setopts, ACCESS_WEB },
{ CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM }, { CMD_DSP, "dsp", false, false, cmd_dsp, ACCESS_SYSTEM },
{ CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM }, { CMD_STATS, "stats", true, false, cmd_stats, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM }, { CMD_PPLNS, "pplns", false, false, cmd_pplns, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_USERSTATUS,"userstatus", false, false, cmd_userstatus, ACCESS_SYSTEM ACCESS_WEB },
{ CMD_END, NULL, false, false, NULL, NULL } { CMD_END, NULL, false, false, NULL, NULL }
}; };

49
src/ckdb_data.c

@ -67,6 +67,55 @@ void username_trim(USERS *users)
} }
} }
/* Is the trimmed username like an address?
* False positive is OK (i.e. 'like')
* Before checking, it is trimmed to avoid web display confusion
* Length check is done before trimming - this may give a false
* positive on any username with lots of trim characters ... which is OK */
bool like_address(char *username)
{
char *tmp, *front, *trail;
size_t len;
regex_t re;
int ret;
len = strlen(username);
if (len < ADDR_USER_CHECK)
return false;
tmp = strdup(username);
front = tmp;
while (*front && TRIM_IGNORE(*front))
front++;
trail = front + strlen(front) - 1;
while (trail >= front) {
if (TRIM_IGNORE(*trail))
*(trail--) = '\0';
else
break;
}
if (regcomp(&re, addrpatt, REG_NOSUB) != 0) {
LOGEMERG("%s(): failed to compile addrpatt '%s'",
__func__, addrpatt);
free(tmp);
// This will disable adding any new usernames ...
return true;
}
ret = regexec(&re, front, (size_t)0, NULL, 0);
regfree(&re);
if (ret == 0) {
free(tmp);
return true;
}
free(tmp);
return false;
}
void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS) void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS)
{ {
char *tmp; char *tmp;

30
src/ckdb_dbio.c

@ -304,9 +304,10 @@ cleanup:
return lastid; return lastid;
} }
bool users_pass_email(PGconn *conn, K_ITEM *u_item, char *oldhash, // status was added to the end so type checking intercepts new mistakes
bool users_update(PGconn *conn, K_ITEM *u_item, char *oldhash,
char *newhash, char *email, char *by, char *code, char *newhash, char *email, char *by, char *code,
char *inet, tv_t *cd, K_TREE *trf_root) char *inet, tv_t *cd, K_TREE *trf_root, char *status)
{ {
ExecStatusType rescode; ExecStatusType rescode;
bool conned = false; bool conned = false;
@ -315,7 +316,7 @@ bool users_pass_email(PGconn *conn, K_ITEM *u_item, char *oldhash,
USERS *row, *users; USERS *row, *users;
char *upd, *ins; char *upd, *ins;
bool ok = false; bool ok = false;
char *params[5 + HISTORYDATECOUNT]; char *params[6 + HISTORYDATECOUNT];
bool hash; bool hash;
int n, par = 0; int n, par = 0;
@ -337,14 +338,18 @@ bool users_pass_email(PGconn *conn, K_ITEM *u_item, char *oldhash,
DATA_USERS(row, item); DATA_USERS(row, item);
memcpy(row, users, sizeof(*row)); memcpy(row, users, sizeof(*row));
// Update one, leave the other
// Update each one supplied
if (hash) { if (hash) {
// New salt each password change // New salt each password change
make_salt(row); make_salt(row);
password_hash(row->username, newhash, row->salt, password_hash(row->username, newhash, row->salt,
row->passwordhash, sizeof(row->passwordhash)); row->passwordhash, sizeof(row->passwordhash));
} else }
if (email)
STRNCPY(row->emailaddress, email); STRNCPY(row->emailaddress, email);
if (status)
STRNCPY(row->status, status);
HISTORYDATEINIT(row, cd, by, code, inet); HISTORYDATEINIT(row, cd, by, code, inet);
HISTORYDATETRANSFER(trf_root, row); HISTORYDATETRANSFER(trf_root, row);
@ -384,21 +389,22 @@ bool users_pass_email(PGconn *conn, K_ITEM *u_item, char *oldhash,
par = 0; par = 0;
params[par++] = bigint_to_buf(row->userid, NULL, 0); params[par++] = bigint_to_buf(row->userid, NULL, 0);
params[par++] = tv_to_buf(cd, NULL, 0); params[par++] = tv_to_buf(cd, NULL, 0);
// Copy them both in - one will be new and one will be old // Copy them all in - at least one will be new
params[par++] = str_to_buf(row->status, NULL, 0);
params[par++] = str_to_buf(row->emailaddress, NULL, 0); params[par++] = str_to_buf(row->emailaddress, NULL, 0);
params[par++] = str_to_buf(row->passwordhash, NULL, 0); params[par++] = str_to_buf(row->passwordhash, NULL, 0);
// New salt for each password change (or recopy old) // New salt for each password change (or recopy old)
params[par++] = str_to_buf(row->salt, NULL, 0); params[par++] = str_to_buf(row->salt, NULL, 0);
HISTORYDATEPARAMS(params, par, row); HISTORYDATEPARAMS(params, par, row);
PARCHKVAL(par, 5 + HISTORYDATECOUNT, params); // 10 as per ins PARCHKVAL(par, 6 + HISTORYDATECOUNT, params); // 11 as per ins
ins = "insert into users " ins = "insert into users "
"(userid,username,status,emailaddress,joineddate," "(userid,username,status,emailaddress,joineddate,"
"passwordhash,secondaryuserid,salt" "passwordhash,secondaryuserid,salt"
HISTORYDATECONTROL ") select " HISTORYDATECONTROL ") select "
"userid,username,status,$3,joineddate," "userid,username,$3,$4,joineddate,"
"$4,secondaryuserid,$5," "$5,secondaryuserid,$6,"
"$6,$7,$8,$9,$10 from users where " "$7,$8,$9,$10,$11 from users where "
"userid=$1 and expirydate=$2"; "userid=$1 and expirydate=$2";
res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); res = PQexecParams(conn, ins, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
@ -4055,6 +4061,10 @@ bool auths_add(PGconn *conn, char *poolinstance, char *username,
} }
DATA_USERS(*users, u_item); DATA_USERS(*users, u_item);
// Any status content means disallow mining
if ((*users)->status[0])
goto unitem;
STRNCPY(row->poolinstance, poolinstance); STRNCPY(row->poolinstance, poolinstance);
row->userid = (*users)->userid; row->userid = (*users)->userid;
// since update=false, a dup will be ok and do nothing when igndup=true // since update=false, a dup will be ok and do nothing when igndup=true

Loading…
Cancel
Save