pool/stratum/share.cpp

354 lines
9.7 KiB
C++

#include "stratum.h"
//void check_job(YAAMP_JOB *job)
//{
// if(job->coind && job->remote)
// {
// debuglog("error memory\n");
// }
//}
static YAAMP_WORKER *share_find_worker(YAAMP_CLIENT *client, YAAMP_JOB *job, bool valid)
{
for(CLI li = g_list_worker.first; li; li = li->next)
{
YAAMP_WORKER *worker = (YAAMP_WORKER *)li->data;
if(worker->deleted) continue;
if( worker->userid == client->userid &&
worker->workerid == client->workerid &&
worker->valid == valid)
{
if(!job && !worker->coinid && !worker->remoteid)
return worker;
else if(!job)
continue;
else if((job->coind && worker->coinid == job->coind->id) ||
(job->remote && worker->remoteid == job->remote->id))
return worker;
}
}
return NULL;
}
static void share_add_worker(YAAMP_CLIENT *client, YAAMP_JOB *job, bool valid, char *ntime, double share_diff, int error_number)
{
// check_job(job);
g_list_worker.Enter();
YAAMP_WORKER *worker = share_find_worker(client, job, valid);
if(!worker)
{
worker = new YAAMP_WORKER;
memset(worker, 0, sizeof(YAAMP_WORKER));
worker->userid = client->userid;
worker->workerid = client->workerid;
worker->coinid = job? (job->coind? job->coind->id: 0): 0;
worker->remoteid = job? (job->remote? job->remote->id: 0): 0;
worker->valid = valid;
worker->error_number = error_number;
sscanf(ntime, "%x", &worker->ntime);
worker->share_diff = share_diff;
if(g_stratum_reconnect)
worker->extranonce1 = !client->reconnecting && (client->reconnectable || client->extranonce_subscribe);
else
worker->extranonce1 = client->extranonce_subscribe;
g_list_worker.AddTail(worker);
}
if(valid)
{
worker->difficulty += client->difficulty_actual / g_current_algo->diff_multiplier;
client->speed += client->difficulty_actual / g_current_algo->diff_multiplier * 42;
// client->source->speed += client->difficulty_actual / g_current_algo->diff_multiplier * 42;
}
g_list_worker.Leave();
}
/////////////////////////////////////////////////////////////////////////
void share_add(YAAMP_CLIENT *client, YAAMP_JOB *job, bool valid, char *extranonce2, char *ntime, char *nonce, double share_diff, int error_number)
{
// check_job(job);
g_shares_counter++;
share_add_worker(client, job, valid, ntime, share_diff, error_number);
YAAMP_SHARE *share = new YAAMP_SHARE;
memset(share, 0, sizeof(YAAMP_SHARE));
share->jobid = job? job->id: 0;
strcpy(share->extranonce2, extranonce2);
strcpy(share->ntime, ntime);
strcpy(share->nonce, nonce);
strcpy(share->nonce1, client->extranonce1);
g_list_share.AddTail(share);
}
YAAMP_SHARE *share_find(int jobid, char *extranonce2, char *ntime, char *nonce, char *nonce1)
{
g_list_share.Enter();
for(CLI li = g_list_share.first; li; li = li->next)
{
YAAMP_SHARE *share = (YAAMP_SHARE *)li->data;
if(share->deleted) continue;
if( share->jobid == jobid &&
!strcmp(share->extranonce2, extranonce2) && !strcmp(share->ntime, ntime) &&
!strcmp(share->nonce, nonce) && !strcmp(share->nonce1, nonce1))
{
g_list_share.Leave();
return share;
}
}
g_list_share.Leave();
return NULL;
}
void share_write(YAAMP_DB *db)
{
int pid = getpid();
int count = 0;
int now = time(NULL);
char buffer[1024*1024] = "insert into shares (userid, workerid, coinid, jobid, pid, valid, extranonce1, difficulty, share_diff, time, algo, error) values ";
g_list_worker.Enter();
for(CLI li = g_list_worker.first; li; li = li->next)
{
YAAMP_WORKER *worker = (YAAMP_WORKER *)li->data;
if(worker->deleted) continue;
if(!worker->workerid) {
object_delete(worker);
continue;
}
if(count) strcat(buffer, ",");
sprintf(buffer+strlen(buffer), "(%d, %d, %d, %d, %d, %d, %d, %f, %f, %d, '%s', %d)",
worker->userid, worker->workerid, worker->coinid, worker->remoteid, pid,
worker->valid, worker->extranonce1, worker->difficulty, worker->share_diff, now, g_stratum_algo, worker->error_number);
// todo: link max_ttf ?
if((now - worker->ntime) > 15*60 || worker->ntime > now) {
debuglog("ntime warning: value %d (%08x) offset %d secs from uid %d\n", worker->ntime, worker->ntime, (now - worker->ntime), worker->userid);
}
if(++count >= 1000)
{
db_query(db, buffer);
strcpy(buffer, "insert into shares (userid, workerid, coinid, jobid, pid, valid, extranonce1, difficulty, share_diff, time, algo, error) values ");
count = 0;
}
object_delete(worker);
}
g_list_worker.Leave();
if(count) db_query(db, buffer);
}
void share_prune(YAAMP_DB *db)
{
g_list_share.Enter();
for(CLI li = g_list_share.first; li; li = li->next)
{
YAAMP_SHARE *share = (YAAMP_SHARE *)li->data;
if(share->deleted) continue;
YAAMP_JOB *job = (YAAMP_JOB *)object_find(&g_list_job, share->jobid);
if(job) continue;
object_delete(share);
}
g_list_share.Leave();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void block_prune(YAAMP_DB *db)
{
int count = 0;
char buffer[128*1024] = "insert into blocks (height, blockhash, coin_id, userid, workerid, category, difficulty, difficulty_user, time, algo, segwit) values ";
g_list_block.Enter();
for(CLI li = g_list_block.first; li; li = li->next)
{
YAAMP_BLOCK *block = (YAAMP_BLOCK *)li->data;
if(!block->confirmed)
{
int elapsed = 30;
// slow block time...
if(g_stratum_algo && !strcmp(g_stratum_algo, "decred")) elapsed = 60 * 15; // 15mn
if((block->created + elapsed) < time(NULL))
object_delete(block);
continue;
}
if(count) strcat(buffer, ",");
sprintf(buffer+strlen(buffer), "(%d, '%s', %d, %d, %d, 'new', %f, %f, %d, '%s', %d)",
block->height, block->hash, block->coinid, block->userid, block->workerid,
block->difficulty, block->difficulty_user, (int)block->created, g_stratum_algo, block->segwit?1:0);
object_delete(block);
count++;
}
g_list_block.Leave();
if(count) db_query(db, buffer);
}
void block_add(int userid, int workerid, int coinid, int height, double diff, double diff_user, const char *h1, const char *h2, int segwit)
{
YAAMP_BLOCK *block = new YAAMP_BLOCK;
memset(block, 0, sizeof(YAAMP_BLOCK));
block->created = time(NULL);
block->userid = userid;
block->workerid = workerid;
block->coinid = coinid;
block->height = height;
block->difficulty = diff;
block->difficulty_user = diff_user;
block->segwit = segwit;
strcpy(block->hash1, h1);
strcpy(block->hash2, h2);
g_list_block.AddTail(block);
}
// called from blocknotify tool
bool block_confirm(int coinid, const char *blockhash)
{
char hash[192];
if(strlen(blockhash) < 64) return false;
snprintf(hash, 161, "%s", blockhash);
// required for multi algos wallets where pow hash is not the blockhash
g_list_coind.Enter();
for(CLI li = g_list_coind.first; li ; li = li->next)
{
YAAMP_COIND *coind = (YAAMP_COIND *)li->data;
if(coind->id != coinid || coind->deleted) continue;
if(coind->multialgos) {
char params[192];
sprintf(params, "[\"%s\"]", blockhash);
json_value *json = rpc_call(&coind->rpc, "getblock", params);
if(!json) {
debuglog("%s: error getblock, no answer\n", __func__);
break;
}
json_value *json_res = json_get_object(json, "result");
if(!json_res) {
debuglog("%s: error getblock, no result\n", __func__);
break;
}
const char *h1 = json_get_string(json_res, "pow_hash"); // DGB, MYR, J
const char *h2 = json_get_string(json_res, "mined_hash"); // XVG
const char *h3 = json_get_string(json_res, "phash"); // XSH
if (h1) snprintf(hash, 161, "%s", h1);
else if (h2) snprintf(hash, 161, "%s", h2);
else if (h3) snprintf(hash, 161, "%s", h3);
//debuglog("%s: getblock %s -> pow %s\n", __func__, blockhash, hash);
json_value_free(json);
break;
} else if (strcmp(coind->symbol,"ORB") == 0) {
char params[192];
sprintf(params, "[\"%s\"]", blockhash);
json_value *json = rpc_call(&coind->rpc, "getblock", params);
if(!json) {
debuglog("%s: error getblock, no answer\n", __func__);
break;
}
json_value *json_res = json_get_object(json, "result");
if(!json_res) {
debuglog("%s: error getblock, no result\n", __func__);
break;
}
const char *h = json_get_string(json_res, "proofhash");
if (h) snprintf(hash, 161, "%s", h);
json_value_free(json);
break;
}
}
g_list_coind.Leave();
for(CLI li = g_list_block.first; li; li = li->next)
{
YAAMP_BLOCK *block = (YAAMP_BLOCK *)li->data;
if(block->coinid == coinid && !block->deleted)
{
if(strcmp(block->hash1, hash) && strcmp(block->hash2, hash)) continue;
if (!block->confirmed) {
debuglog("*** CONFIRMED %d : %s\n", block->height, block->hash2);
strncpy(block->hash, blockhash, 65);
block->confirmed = true;
}
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////
YAAMP_SUBMIT *submit_add(int remoteid, double difficulty)
{
YAAMP_SUBMIT *submit = new YAAMP_SUBMIT;
memset(submit, 0, sizeof(YAAMP_SUBMIT));
submit->created = time(NULL);
submit->valid = true;
submit->remoteid = remoteid;
submit->difficulty = difficulty / g_current_algo->diff_multiplier;
g_list_submit.AddTail(submit);
return submit;
}
void submit_prune(YAAMP_DB *db)
{
int count = 0;
char buffer[128*1024] = "insert into jobsubmits (jobid, valid, difficulty, time, algo, status) values ";
g_list_submit.Enter();
for(CLI li = g_list_submit.first; li; li = li->next)
{
YAAMP_SUBMIT *submit = (YAAMP_SUBMIT *)li->data;
if(count) strcat(buffer, ",");
sprintf(buffer+strlen(buffer), "(%d, %d, %f, %d, '%s', 0)", submit->remoteid, submit->valid,
submit->difficulty, (int)submit->created, g_stratum_algo);
if(++count >= 1000)
{
db_query(db, buffer);
strcpy(buffer, "insert into jobsubmits (jobid, valid, difficulty, time, algo, status) values ");
count = 0;
}
object_delete(submit);
}
g_list_submit.Leave();
if(count) db_query(db, buffer);
}