Browse Source

ckdb - enable payouts expiry and a block minerreward override

master
kanoi 10 years ago
parent
commit
9f859f0f78
  1. 2
      src/ckdb.c
  2. 6
      src/ckdb.h
  3. 27
      src/ckdb_cmd.c
  4. 57
      src/ckdb_data.c
  5. 278
      src/ckdb_dbio.c

2
src/ckdb.c

@ -805,7 +805,7 @@ static bool getdata3()
goto sukamudai; goto sukamudai;
if (!(ok = markersummary_fill(conn)) || everyone_die) if (!(ok = markersummary_fill(conn)) || everyone_die)
goto sukamudai; goto sukamudai;
if (!confirm_sharesummary) if (!confirm_sharesummary && !everyone_die)
ok = poolstats_fill(conn); ok = poolstats_fill(conn);
sukamudai: sukamudai:

6
src/ckdb.h

@ -55,7 +55,7 @@
#define DB_VLOCK "1" #define DB_VLOCK "1"
#define DB_VERSION "1.0.0" #define DB_VERSION "1.0.0"
#define CKDB_VERSION DB_VERSION"-1.105" #define CKDB_VERSION DB_VERSION"-1.110"
#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__
@ -1974,6 +1974,8 @@ extern void sequence_report(bool lock);
#define PPLNSDIFFTIMES "pplns_diff_times" #define PPLNSDIFFTIMES "pplns_diff_times"
#define PPLNSDIFFADD "pplns_diff_add" #define PPLNSDIFFADD "pplns_diff_add"
#define REWARDOVERRIDE "MinerReward"
// Data free functions (first) // Data free functions (first)
extern void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull); extern void free_msgline_data(K_ITEM *item, bool t_lock, bool t_cull);
extern void free_workinfo_data(K_ITEM *item); extern void free_workinfo_data(K_ITEM *item);
@ -2371,6 +2373,8 @@ extern void payouts_add_ram(bool ok, K_ITEM *p_item, K_ITEM *old_p_item,
extern bool payouts_add(PGconn *conn, bool add, K_ITEM *p_item, extern bool payouts_add(PGconn *conn, bool add, K_ITEM *p_item,
K_ITEM **old_p_item, char *by, char *code, char *inet, K_ITEM **old_p_item, char *by, char *code, char *inet,
tv_t *cd, K_TREE *trf_root, bool already); tv_t *cd, K_TREE *trf_root, bool already);
extern K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now,
bool lock);
extern bool payouts_fill(PGconn *conn); extern bool payouts_fill(PGconn *conn);
extern bool auths_add(PGconn *conn, char *poolinstance, char *username, extern bool auths_add(PGconn *conn, char *poolinstance, char *username,
char *workername, char *clientid, char *enonce1, char *workername, char *clientid, char *enonce1,

27
src/ckdb_cmd.c

@ -4520,34 +4520,27 @@ static char *cmd_payouts(PGconn *conn, char *cmd, char *id, tv_t *now,
"%"PRId32"/%s", "%"PRId32"/%s",
payoutid, old_payouts2->status, payouts2->status, payoutid, old_payouts2->status, payouts2->status,
payouts2->height, payouts2->blockhash); payouts2->height, payouts2->blockhash);
/*
} else if (strcasecmp(action, "expire") == 0) { } else if (strcasecmp(action, "expire") == 0) {
/ TODO: Expire the payout - effectively deletes it /* Expire the payout - effectively deletes it
* Require payoutid * Require payoutid
* If any payments are paid then don't allow it / * TODO: If any payments are paid then don't allow it */
i_payoutid = require_name(trf_root, "payoutid", 1, i_payoutid = require_name(trf_root, "payoutid", 1,
(char *)intpatt, reply, siz); (char *)intpatt, reply, siz);
if (!i_payoutid) if (!i_payoutid)
return strdup(reply); return strdup(reply);
TXT_TO_BIGINT("payoutid", transfer_data(i_payoutid), payoutid); TXT_TO_BIGINT("payoutid", transfer_data(i_payoutid), payoutid);
K_WLOCK(payouts_free); p_item = payouts_full_expire(conn, payoutid, now, true);
p_item = find_payoutid(payoutid);
if (!p_item) { if (!p_item) {
K_WUNLOCK(payouts_free); snprintf(reply, siz, "failed payout %"PRId64, payoutid);
snprintf(reply, siz,
"no payout with id %"PRId64, payoutid);
return strdup(reply); return strdup(reply);
} }
p2_item = k_unlink_head(payouts_free); DATA_PAYOUTS(payouts, p_item);
K_WUNLOCK(payouts_free); snprintf(msg, sizeof(msg),
"payout %"PRId64" block %"PRId32" reward %"PRId64
DATA_PAYOUTS(payouts2, p2_item); " status '%s'",
bzero(payouts2, sizeof(*payouts2)); payouts->payoutid, payouts->height,
payouts2->payoutid = payouts->payoutid; payouts->minerreward, payouts->status);
...
*/
} else if (strcasecmp(action, "process") == 0) { } else if (strcasecmp(action, "process") == 0) {
/* Generate a payout /* Generate a payout
* Require height, blockhash and addrdate * Require height, blockhash and addrdate

57
src/ckdb_data.c

@ -1563,6 +1563,28 @@ cmp_t cmp_optioncontrol(K_ITEM *a, K_ITEM *b)
return c; return c;
} }
#define reward_override_name(_height, _buf, _siz) \
_reward_override_name(_height, _buf, _siz, WHERE_FFL_HERE)
static bool _reward_override_name(int32_t height, char *buf, size_t siz,
WHERE_FFL_ARGS)
{
char tmp[128];
size_t len;
snprintf(tmp, sizeof(tmp), REWARDOVERRIDE"_%"PRId32, height);
// Code bug - detect and notify truncation coz that would be bad :P
len = strlen(tmp) + 1;
if (len > siz) {
LOGEMERG("%s(): Invalid size %d passed - required %d" WHERE_FFL,
__func__, (int)siz, (int)len, WHERE_FFL_PASS);
return false;
}
strcpy(buf, tmp);
return true;
}
// Must be R or W locked before call // Must be R or W locked before call
K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height) K_ITEM *find_optioncontrol(char *optionname, tv_t *now, int32_t height)
{ {
@ -2996,7 +3018,7 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
K_TREE *mu_root = NULL; K_TREE *mu_root = NULL;
int usercount; int usercount;
double ndiff, total_diff, diff_want, elapsed; double ndiff, total_diff, diff_want, elapsed;
char ndiffbin[TXT_SML+1]; char ndiffbin[TXT_SML+1], rewardbuf[32];
double diff_times, diff_add; double diff_times, diff_add;
char cd_buf[CDATE_BUFSIZ]; char cd_buf[CDATE_BUFSIZ];
tv_t end_tv = { 0L, 0L }; tv_t end_tv = { 0L, 0L };
@ -3365,6 +3387,39 @@ bool process_pplns(int32_t height, char *blockhash, tv_t *addr_cd)
d64 = blocks->reward * 9 / 1000; d64 = blocks->reward * 9 / 1000;
g64 = blocks->reward - d64; g64 = blocks->reward - d64;
payouts->minerreward = g64; payouts->minerreward = g64;
/* We can hard code a miner reward for a block in optioncontrol
* if it ever needs adjusting - so just expire the payout and
* re-process the reward ... before it's paid */
bool oname;
oname = reward_override_name(blocks->height, rewardbuf,
sizeof(rewardbuf));
if (oname) {
OPTIONCONTROL *oc;
K_ITEM *oc_item;
// optioncontrol must be default limits or below these limits
oc_item = find_optioncontrol(rewardbuf, &now, blocks->height+1);
if (oc_item) {
int64_t override, delta;
char *moar = "more";
double per;
DATA_OPTIONCONTROL(oc, oc_item);
override = (int64_t)atol(oc->optionvalue);
delta = override - g64;
if (delta < 0) {
moar = "less";
delta = -delta;
}
per = 100.0 * (double)delta / (double)g64;
LOGWARNING("%s(): *** block %"PRId32" payout reward"
" overridden, was %"PRId64" now %"PRId64
" = %"PRId64" (%.4f%%) %s",
__func__, blocks->height,
g64, override, delta, per, moar);
payouts->minerreward = override;
}
}
payouts->workinfoidstart = begin_workinfoid; payouts->workinfoidstart = begin_workinfoid;
payouts->workinfoidend = end_workinfoid; payouts->workinfoidend = end_workinfoid;
payouts->elapsed = elapsed; payouts->elapsed = elapsed;

278
src/ckdb_dbio.c

@ -2302,6 +2302,7 @@ nostart:
DATA_OPTIONCONTROL(optioncontrol, old_item); DATA_OPTIONCONTROL(optioncontrol, old_item);
optioncontrol_root = remove_from_ktree(optioncontrol_root, old_item, optioncontrol_root = remove_from_ktree(optioncontrol_root, old_item,
cmp_optioncontrol); cmp_optioncontrol);
k_unlink_item(optioncontrol_store, old_item);
FREENULL(optioncontrol->optionvalue); FREENULL(optioncontrol->optionvalue);
k_add_head(optioncontrol_free, old_item); k_add_head(optioncontrol_free, old_item);
} }
@ -3605,44 +3606,6 @@ bool sharesummaries_to_markersummaries(PGconn *conn, WORKMARKERS *workmarkers,
ms_item = ms_item->next; ms_item = ms_item->next;
} }
#if 0
int deleted = -7;
char *tuples = NULL;
char *del;
// No longer in the DB
if (old_sharesummary_store->count > 0) {
par = 0;
params[par++] = bigint_to_buf(workmarkers->workinfoidstart, NULL, 0);
params[par++] = bigint_to_buf(workmarkers->workinfoidend, NULL, 0);
PARCHK(par, params);
del = "delete from sharesummary "
"where workinfoid >= $1 and workinfoid <= $2";
res = PQexecParams(conn, del, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (PGOK(rescode)) {
tuples = PQcmdTuples(res);
if (tuples && *tuples)
deleted = atoi(tuples);
}
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Delete", rescode, conn);
reason = "delete failure";
goto rollback;
}
if (deleted != old_sharesummary_store->count) {
LOGERR("%s() processed sharesummaries=%d but deleted=%d",
shortname, old_sharesummary_store->count, deleted);
reason = "delete mismatch";
goto rollback;
}
}
#endif
ok = workmarkers_process(conn, true, true, ok = workmarkers_process(conn, true, true,
workmarkers->markerid, workmarkers->markerid,
workmarkers->poolinstance, workmarkers->poolinstance,
@ -5123,6 +5086,245 @@ unparam:
return ok; return ok;
} }
/* Expire the entire payout, miningpayouts and payments
* If it returns false, nothing was changed
* and a console message will say why */
K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now, bool lock)
{
bool locked = false, conned = false, begun = false, ok = false;
K_TREE_CTX mp_ctx[1], pm_ctx[1];
K_ITEM *po_item = NULL, *mp_item, *pm_item, *next_item;
PAYMENTS *payments = NULL;
MININGPAYOUTS *mp = NULL;
PAYOUTS *payouts = NULL;
ExecStatusType rescode;
PGresult *res;
char *params[8];
int n, par = 0;
char *upd, *tuples = NULL;
int po_upd, mp_upd, pm_upd;
// If not already done before calling
if (lock)
ck_wlock(&process_pplns_lock);
// This will be rare so a full lock is best
K_WLOCK(payouts_free);
K_WLOCK(miningpayouts_free);
K_WLOCK(payments_free);
locked = true;
po_item = find_payoutid(payoutid);
if (!po_item) {
LOGERR("%s(): unknown payoutid %"PRId64, __func__, payoutid);
goto matane;
}
conned = CKPQConn(&conn);
begun = CKPQBegin(conn);
if (!begun)
goto matane;
upd = "update payouts set "EDDB"=$1 where payoutid=$2 and "EDDB"=$3";
par = 0;
params[par++] = tv_to_buf(now, NULL, 0);
params[par++] = bigint_to_buf(payoutid, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 3, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (PGOK(rescode)) {
tuples = PQcmdTuples(res);
if (tuples && *tuples) {
po_upd = atoi(tuples);
if (po_upd != 1) {
LOGERR("%s() updated payouts should be 1"
" but updated=%d",
__func__, po_upd);
goto matane;
}
}
}
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Update payouts", rescode, conn);
goto matane;
}
for (n = 0; n < par; n++)
free(params[n]);
upd = "update miningpayouts set "EDDB"=$1 where payoutid=$2 and "EDDB"=$3";
par = 0;
params[par++] = tv_to_buf(now, NULL, 0);
params[par++] = bigint_to_buf(payoutid, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 3, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (PGOK(rescode)) {
tuples = PQcmdTuples(res);
if (tuples && *tuples)
mp_upd = atoi(tuples);
}
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Update miningpayouts", rescode, conn);
goto matane;
}
for (n = 0; n < par; n++)
free(params[n]);
upd = "update payments set "EDDB"=$1 where payoutid=$2 and "EDDB"=$3";
par = 0;
params[par++] = tv_to_buf(now, NULL, 0);
params[par++] = bigint_to_buf(payoutid, NULL, 0);
params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0);
PARCHKVAL(par, 3, params);
res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE);
rescode = PQresultStatus(res);
if (PGOK(rescode)) {
tuples = PQcmdTuples(res);
if (tuples && *tuples)
pm_upd = atoi(tuples);
}
PQclear(res);
if (!PGOK(rescode)) {
PGLOGERR("Update payments", rescode, conn);
goto matane;
}
for (n = 0; n < par; n++)
free(params[n]);
par = 0;
// Check miningpayouts failure condition
mp_item = first_miningpayouts(payoutid, mp_ctx);
if (!mp_item) {
if (mp_upd != 0) {
LOGERR("%s() updated miningpayouts should be 0 but"
" updated=%d",
__func__, mp_upd);
goto matane;
}
} else {
int count = 0;
DATA_MININGPAYOUTS(mp, mp_item);
while (mp_item && mp->payoutid == payoutid) {
if (CURRENT(&(mp->expirydate)))
count++;
mp_item = next_in_ktree(mp_ctx);
DATA_MININGPAYOUTS_NULL(mp, mp_item);
}
if (count != mp_upd) {
LOGERR("%s() updated miningpayouts should be %d but"
" updated=%d",
__func__, count, mp_upd);
goto matane;
}
}
/* Check payments failure condition
*
* This does a full table search since there is no index
* This should be so rare that adding an index/tree for it
* would be a waste */
pm_item = first_in_ktree(payments_root, pm_ctx);
if (!pm_item) {
if (pm_upd != 0) {
LOGERR("%s() updated payments should be 0 but"
" updated=%d",
__func__, pm_upd);
goto matane;
}
} else {
int count = 0;
DATA_PAYMENTS(payments, pm_item);
while (pm_item) {
if (payments->payoutid == payoutid &&
CURRENT(&(payments->expirydate))) {
count++;
}
pm_item = next_in_ktree(pm_ctx);
DATA_PAYMENTS_NULL(payments, pm_item);
}
if (count != pm_upd) {
LOGERR("%s() updated payments should be %d but"
" updated=%d",
__func__, count, pm_upd);
goto matane;
}
}
// No more possible errors, so update the ram tables
DATA_PAYOUTS(payouts, po_item);
payouts_root = remove_from_ktree(payouts_root, po_item, cmp_payouts);
payouts_id_root = remove_from_ktree(payouts_id_root, po_item, cmp_payouts_id);
copy_tv(&(payouts->expirydate), now);
payouts_root = add_to_ktree(payouts_root, po_item, cmp_payouts);
payouts_id_root = add_to_ktree(payouts_id_root, po_item, cmp_payouts_id);
mp_item = first_miningpayouts(payoutid, mp_ctx);
DATA_MININGPAYOUTS_NULL(mp, mp_item);
while (mp_item && mp->payoutid == payoutid) {
if (CURRENT(&(mp->expirydate))) {
next_item = next_in_ktree(mp_ctx);
miningpayouts_root = remove_from_ktree(miningpayouts_root, mp_item, cmp_miningpayouts);
copy_tv(&(mp->expirydate), now);
miningpayouts_root = add_to_ktree(miningpayouts_root, mp_item, cmp_miningpayouts);
mp_item = next_item;
} else
mp_item = next_in_ktree(mp_ctx);
DATA_MININGPAYOUTS_NULL(mp, mp_item);
}
pm_item = first_in_ktree(payments_root, pm_ctx);
DATA_PAYMENTS_NULL(payments, pm_item);
while (pm_item) {
if (payments->payoutid == payoutid &&
CURRENT(&(payments->expirydate))) {
next_item = next_in_ktree(pm_ctx);
payments_root = remove_from_ktree(payments_root, pm_item, cmp_payments);
copy_tv(&(payments->expirydate), now);
payments_root = add_to_ktree(payments_root, pm_item, cmp_payments);
pm_item = next_item;
} else
pm_item = next_in_ktree(pm_ctx);
DATA_PAYMENTS_NULL(payments, pm_item);
}
ok = true;
matane:
if (begun)
CKPQEnd(conn, ok);
if (locked) {
K_WUNLOCK(payments_free);
K_WUNLOCK(miningpayouts_free);
K_WUNLOCK(payouts_free);
}
CKPQDisco(&conn, conned);
if (lock)
ck_wunlock(&process_pplns_lock);
for (n = 0; n < par; n++)
free(params[n]);
if (ok)
return po_item;
else
return NULL;
}
bool payouts_fill(PGconn *conn) bool payouts_fill(PGconn *conn)
{ {
ExecStatusType rescode; ExecStatusType rescode;

Loading…
Cancel
Save