diff --git a/src/ckdb.c b/src/ckdb.c index 4cccaf8c..7f219aef 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -420,6 +420,7 @@ K_STORE *miningpayouts_store; // PAYOUTS K_TREE *payouts_root; K_TREE *payouts_id_root; +K_TREE *payouts_wid_root; K_LIST *payouts_free; K_STORE *payouts_store; cklock_t process_pplns_lock; @@ -1086,6 +1087,7 @@ static void alloc_storage() payouts_store = k_new_store(payouts_free); payouts_root = new_ktree(); payouts_id_root = new_ktree(); + payouts_wid_root = new_ktree(); auths_free = k_new_list("Auths", sizeof(AUTHS), ALLOC_AUTHS, LIMIT_AUTHS, true); @@ -1304,6 +1306,7 @@ static void dealloc_storage() FREE_ALL(poolstats); FREE_ALL(auths); + FREE_TREE(payouts_wid); FREE_TREE(payouts_id); FREE_TREE(payouts); FREE_STORE_DATA(payouts); diff --git a/src/ckdb.h b/src/ckdb.h index 8ab5cf26..6ae1bdd4 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -55,7 +55,7 @@ #define DB_VLOCK "1" #define DB_VERSION "1.0.2" -#define CKDB_VERSION DB_VERSION"-1.229" +#define CKDB_VERSION DB_VERSION"-1.230" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -1600,6 +1600,7 @@ typedef struct payouts { extern K_TREE *payouts_root; extern K_TREE *payouts_id_root; +extern K_TREE *payouts_wid_root; extern K_LIST *payouts_free; extern K_STORE *payouts_store; extern cklock_t process_pplns_lock; @@ -2318,9 +2319,11 @@ extern K_TREE *upd_add_mu(K_TREE *mu_root, K_STORE *mu_store, int64_t userid, double diffacc); extern cmp_t cmp_payouts(K_ITEM *a, K_ITEM *b); extern cmp_t cmp_payouts_id(K_ITEM *a, K_ITEM *b); +extern cmp_t cmp_payouts_wid(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_payouts(int32_t height, char *blockhash); extern K_ITEM *find_last_payouts(); extern K_ITEM *find_payoutid(int64_t payoutid); +extern K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx); extern double payout_stats(PAYOUTS *payouts, char *statname); extern bool process_pplns(int32_t height, char *blockhash, tv_t *now); extern cmp_t cmp_auths(K_ITEM *a, K_ITEM *b); @@ -2354,6 +2357,7 @@ extern bool workmarkers_generate(PGconn *conn, char *err, size_t siz, char *by, char *code, char *inet, tv_t *cd, K_TREE *trf_root, bool none_error); extern bool reward_shifts(PAYOUTS *payouts, bool lock, int delta); +extern bool shift_rewards(K_ITEM *wm_item); extern cmp_t cmp_marks(K_ITEM *a, K_ITEM *b); extern K_ITEM *find_marks(int64_t workinfoid); extern const char *marks_marktype(char *marktype); diff --git a/src/ckdb_cmd.c b/src/ckdb_cmd.c index ed5e9786..11c9bac1 100644 --- a/src/ckdb_cmd.c +++ b/src/ckdb_cmd.c @@ -5541,7 +5541,7 @@ static char *cmd_stats(__maybe_unused PGconn *conn, char *cmd, char *id, USEINFO(marks, 1, 1); USEINFO(blocks, 1, 1); USEINFO(miningpayouts, 1, 1); - USEINFO(payouts, 1, 2); + USEINFO(payouts, 1, 3); USEINFO(auths, 1, 1); USEINFO(poolstats, 1, 1); USEINFO(userstats, 2, 1); diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 7942a790..0700f727 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -3141,6 +3141,22 @@ cmp_t cmp_payouts_id(K_ITEM *a, K_ITEM *b) return c; } +/* order by workinfoidend asc,expirydate asc + * This must use workinfoidend, not workinfoidstart, since a change + * in the payout PPLNS N could have 2 payouts with the same start, + * but currently there is only one payout per block + * i.e. workinfoidend can only have one payout */ +cmp_t cmp_payouts_wid(K_ITEM *a, K_ITEM *b) +{ + PAYOUTS *pa, *pb; + DATA_PAYOUTS(pa, a); + DATA_PAYOUTS(pb, b); + cmp_t c = CMP_BIGINT(pa->workinfoidend, pb->workinfoidend); + if (c == 0) + c = CMP_TV(pa->expirydate, pb->expirydate); + return c; +} + K_ITEM *find_payouts(int32_t height, char *blockhash) { PAYOUTS payouts; @@ -3189,6 +3205,25 @@ K_ITEM *find_payoutid(int64_t payoutid) return find_in_ktree(payouts_id_root, &look, cmp_payouts_id, ctx); } +// First payouts workinfoidend equal or before workinfoidend +K_ITEM *find_payouts_wid(int64_t workinfoidend, K_TREE_CTX *ctx) +{ + PAYOUTS payouts; + K_TREE_CTX ctx0[1]; + K_ITEM look; + + if (ctx == NULL) + ctx = ctx0; + + payouts.workinfoidend = workinfoidend+1; + payouts.expirydate.tv_sec = 0; + payouts.expirydate.tv_usec = 0; + + INIT_PAYOUTS(&look); + look.data = (void *)(&payouts); + return find_before_in_ktree(payouts_wid_root, &look, cmp_payouts_wid, ctx); +} + /* Values from payout stats, returns -1 if statname isn't found * If code needs a value then it probably really should be a new payouts field * rather than stored in the stats passed to the pplns2 web page @@ -4635,6 +4670,35 @@ bool reward_shifts(PAYOUTS *payouts, bool lock, int delta) return did_one; } +// (re)calculate rewards for a shift +bool shift_rewards(K_ITEM *wm_item) +{ + PAYOUTS *payouts = NULL; + K_TREE_CTX ctx[1]; + WORKMARKERS *wm; + K_ITEM *p_item; + int rewards = 0; + + DATA_WORKMARKERS(wm, wm_item); + + // Deadlock risk since calling code should have workmarkers locked + K_WLOCK(payouts_free); + p_item = find_payouts_wid(wm->workinfoidend, ctx); + DATA_PAYOUTS_NULL(payouts, p_item); + // a workmarker should not cross a payout boundary + while (p_item && payouts->workinfoidstart <= wm->workinfoidstart && + wm->workinfoidend <= payouts->workinfoidend) { + if (CURRENT(&(payouts->expirydate))) + rewards++; + p_item = prev_in_ktree(ctx); + DATA_PAYOUTS_NULL(payouts, p_item); + } + K_WUNLOCK(payouts_free); + + wm->rewards = rewards; + return (rewards > 0); +} + // order by expirydate asc,workinfoid asc // TODO: add poolinstance cmp_t cmp_marks(K_ITEM *a, K_ITEM *b) diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index b4fd8eee..e6552ed2 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -5119,12 +5119,15 @@ void payouts_add_ram(bool ok, K_ITEM *p_item, K_ITEM *old_p_item, tv_t *cd) DATA_PAYOUTS(oldp, old_p_item); payouts_root = remove_from_ktree(payouts_root, old_p_item, cmp_payouts); payouts_id_root = remove_from_ktree(payouts_id_root, old_p_item, cmp_payouts_id); + payouts_wid_root = remove_from_ktree(payouts_wid_root, old_p_item, cmp_payouts_wid); copy_tv(&(oldp->expirydate), cd); payouts_root = add_to_ktree(payouts_root, old_p_item, cmp_payouts); payouts_id_root = add_to_ktree(payouts_id_root, old_p_item, cmp_payouts_id); + payouts_wid_root = add_to_ktree(payouts_wid_root, old_p_item, cmp_payouts_wid); } payouts_root = add_to_ktree(payouts_root, p_item, cmp_payouts); payouts_id_root = add_to_ktree(payouts_id_root, p_item, cmp_payouts_id); + payouts_wid_root = add_to_ktree(payouts_wid_root, p_item, cmp_payouts_wid); k_add_head(payouts_store, p_item); } K_WUNLOCK(payouts_free); @@ -5431,9 +5434,11 @@ K_ITEM *payouts_full_expire(PGconn *conn, int64_t payoutid, tv_t *now, bool lock 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); + payouts_wid_root = remove_from_ktree(payouts_wid_root, po_item, cmp_payouts_wid); 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); + payouts_wid_root = add_to_ktree(payouts_wid_root, po_item, cmp_payouts_wid); mp_item = first_miningpayouts(payoutid, mp_ctx); DATA_MININGPAYOUTS_NULL(mp, mp_item); @@ -5643,6 +5648,7 @@ bool payouts_fill(PGconn *conn) payouts_root = add_to_ktree(payouts_root, item, cmp_payouts); payouts_id_root = add_to_ktree(payouts_id_root, item, cmp_payouts_id); + payouts_wid_root = add_to_ktree(payouts_wid_root, item, cmp_payouts_wid); k_add_head(payouts_store, item); if (CURRENT(&(row->expirydate)) && PAYGENERATED(row->status)) @@ -6726,6 +6732,8 @@ unparam: cmp_workmarkers_workinfoid); } if (wm_item) { + shift_rewards(wm_item); + workmarkers_root = add_to_ktree(workmarkers_root, wm_item, cmp_workmarkers);