Browse Source

multipool: Squashed commit (v2)

commit a9d3c1ffdb71d2a4985749acba3d424161154ab4
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 05:39:24 2015 +0200

    multipool: last changes before squashed merge

    and fix net diff on wallets.. was longpoll specific

commit a63f0024f3f1fb52d2c4369518bf87c33a9e16ae
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 05:02:27 2015 +0200

    update api sample for the protocol 1.5

commit adda14b22edde6485932be56550166478f6f00dd
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 04:43:25 2015 +0200

    stats: store pool number in scanlog

commit e1a0274b01c29409ce16f9096b9985a35cf78ba7
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Thu May 21 03:36:15 2015 +0200

    api: switchpool and new pool stats variables (API v1.5)

    add accepted/rej by pool, wait time on conditional, net diff and rate

    also add scantime per pool config option and do some pool cleanup..

commit 1a30450ad2a5e068983531b9d2a96629b970c1e8
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 06:39:09 2015 +0200

    prevent concurrent pool switching

    and limit condtionnal wait messages to the first thread/device

commit e3922c7a331a3ad2730bc83082fcd6b2547542f5
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 05:39:45 2015 +0200

    add some pool rotate options, like pool time-limit

    update sample pools.conf for time rotation

commit 312bd905412d49fd5a9f9e7ff2bc72b23edf38ed
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 04:31:19 2015 +0200

    do not try to restart threads from threads

    Start inconditionally the stratum and longpoll threads,
    these threads are just waiting a tq_push() if unused...

    so add some checks to know if vars are set for the right pool

commit d4a9428fefdd9e9d70c3c8231f10961e7cd41760
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Wed May 20 01:06:31 2015 +0200

    pools: add name and removed attributes

    also increase max defined pools to 8

    to be tested on windows..

commit d840d683ecb2cc4767f0a0612b8359c52d4bad29
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Tue May 19 22:33:11 2015 +0200

    parse json config file pools array

commit d6c29b1f7f6b786c56e1f0cb8a90305f06cc7aec
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Tue May 19 03:29:30 2015 +0200

    multi-pools: prepare storage/switch of credentials

    for the moment:
    - allow the storage of multiple -o params (and user/pass)
    - allow a failover pool on connection failed
    - switch to the next pool with the "seturl" api remote command
    - longpoll to stratum switch (reverse to check...)

    todo: mix stratum/getwork, new api commands, json config...

commit 2d6b3fddf6631d7df1ac6ca74eee91c33a3c09ee
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Fri May 22 08:26:40 2015 +0200

    multipool: increase stability, but not 100% perfect

    several problems fixed:
    - submit to the pool set in work (source pool)
    - longpoll curl timeout could be too high and could lock the switch
    - mutexes cant be copied on windows (stratum global var to fully remove later)

    I linked the -T timeout option to curl and tried to remove all fixed timeout values

commit 6fd935c369cf33949dab98c8b09b2ca8cab3e7ea
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Fri May 22 11:23:07 2015 +0200

    stratum: remove last rpc_ vars in stratum thread

commit ee9c821525be303282e5dab512ffd2ae81ad524f
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Sat May 23 03:53:50 2015 +0200

    stratum: do not alloc empty merkle tree

commit 69852a2874bd18c4ed1daa9180a10d12976424dc
Author: Tanguy Pruvot <tanguy.pruvot@gmail.com>
Date:   Sat May 23 04:25:12 2015 +0200

    stratum: properly free jobs on disconnect

Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
master
Tanguy Pruvot 9 years ago
parent
commit
bbd2c704f9
  1. 103
      api.cpp
  2. 12
      api/index.php
  3. 824
      ccminer.cpp
  4. 8
      hashlog.cpp
  5. 76
      miner.h
  6. 27
      pools.conf
  7. 2
      stats.cpp
  8. 124
      util.cpp

103
api.cpp

@ -8,7 +8,7 @@
* Software Foundation; either version 2 of the License, or (at your option) * Software Foundation; either version 2 of the License, or (at your option)
* any later version. See COPYING for more details. * any later version. See COPYING for more details.
*/ */
#define APIVERSION "1.4" #define APIVERSION "1.5"
#ifdef WIN32 #ifdef WIN32
# define _WINSOCK_DEPRECATED_NO_WARNINGS # define _WINSOCK_DEPRECATED_NO_WARNINGS
@ -92,13 +92,12 @@ static int bye = 0;
extern char *opt_api_allow; extern char *opt_api_allow;
extern int opt_api_listen; /* port */ extern int opt_api_listen; /* port */
extern int opt_api_remote; extern int opt_api_remote;
extern uint32_t accepted_count;
extern uint32_t rejected_count; // current stratum...
extern int num_cpus;
extern struct stratum_ctx stratum; extern struct stratum_ctx stratum;
extern char* rpc_user;
// sysinfos.cpp // sysinfos.cpp
extern int num_cpus;
extern float cpu_temp(int); extern float cpu_temp(int);
extern uint32_t cpu_clock(int); extern uint32_t cpu_clock(int);
// cuda.cpp // cuda.cpp
@ -111,6 +110,8 @@ char driver_version[32] = { 0 };
static void gpustatus(int thr_id) static void gpustatus(int thr_id)
{ {
struct pool_infos *p = &pools[cur_pooln];
if (thr_id >= 0 && thr_id < opt_n_threads) { if (thr_id >= 0 && thr_id < opt_n_threads) {
struct cgpu_info *cgpu = &thr_info[thr_id].gpu; struct cgpu_info *cgpu = &thr_info[thr_id].gpu;
int gpuid = cgpu->gpu_id; int gpuid = cgpu->gpu_id;
@ -127,8 +128,8 @@ static void gpustatus(int thr_id)
cuda_gpu_clocks(cgpu); cuda_gpu_clocks(cgpu);
// todo: per gpu // todo: per gpu
cgpu->accepted = accepted_count; cgpu->accepted = p->accepted_count;
cgpu->rejected = rejected_count; cgpu->rejected = p->rejected_count;
cgpu->khashes = stats_get_speed(thr_id, 0.0) / 1000.0; cgpu->khashes = stats_get_speed(thr_id, 0.0) / 1000.0;
@ -165,19 +166,27 @@ static char *getsummary(char *params)
{ {
char algo[64]; *algo = '\0'; char algo[64]; *algo = '\0';
time_t ts = time(NULL); time_t ts = time(NULL);
double uptime = difftime(ts, startup); double accps, uptime = difftime(ts, startup);
double accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0); uint32_t wait_time = 0, accepted_count = 0, rejected_count = 0;
for (int p = 0; p < num_pools; p++) {
wait_time += pools[cur_pooln].wait_time;
accepted_count += pools[cur_pooln].accepted_count;
rejected_count += pools[cur_pooln].rejected_count;
}
accps = (60.0 * accepted_count) / (uptime ? uptime : 1.0);
get_currentalgo(algo, sizeof(algo)); get_currentalgo(algo, sizeof(algo));
*buffer = '\0'; *buffer = '\0';
sprintf(buffer, "NAME=%s;VER=%s;API=%s;" sprintf(buffer, "NAME=%s;VER=%s;API=%s;"
"ALGO=%s;GPUS=%d;KHS=%.2f;ACC=%d;REJ=%d;" "ALGO=%s;GPUS=%d;KHS=%.2f;ACC=%d;REJ=%d;"
"ACCMN=%.3f;DIFF=%.6f;UPTIME=%.0f;TS=%u|", "ACCMN=%.3f;DIFF=%.6f;NETKHS=%.2f;"
"POOLS=%u;WAIT=%u;UPTIME=%.0f;TS=%u|",
PACKAGE_NAME, PACKAGE_VERSION, APIVERSION, PACKAGE_NAME, PACKAGE_VERSION, APIVERSION,
algo, active_gpus, (double)global_hashrate / 1000.0, algo, active_gpus, (double)global_hashrate / 1000.,
accepted_count, rejected_count, accepted_count, rejected_count,
accps, net_diff > 0. ? net_diff : stratum_diff, uptime, (uint32_t) ts); accps, net_diff > 0. ? net_diff : stratum_diff, (double)net_hashrate / 1000.,
num_pools, wait_time, uptime, (uint32_t) ts);
return buffer; return buffer;
} }
@ -186,31 +195,30 @@ static char *getsummary(char *params)
*/ */
static char *getpoolnfo(char *params) static char *getpoolnfo(char *params)
{ {
char *p = buffer; char *s = buffer;
char jobid[128] = { 0 }; char jobid[128] = { 0 };
char nonce[128] = { 0 }; char nonce[128] = { 0 };
*p = '\0'; struct pool_infos *p = &pools[cur_pooln];
if (!stratum.url) { *s = '\0';
sprintf(p, "|");
return p;
}
if (stratum.job.job_id) if (stratum.job.job_id)
strncpy(jobid, stratum.job.job_id, sizeof(stratum.job.job_id)); strncpy(jobid, stratum.job.job_id, sizeof(stratum.job.job_id));
if (stratum.job.xnonce2) { if (stratum.job.xnonce2) {
/* used temporary to be sure all is ok */ /* used temporary to be sure all is ok */
cbin2hex(nonce, (const char*) stratum.job.xnonce2, stratum.xnonce2_size); sprintf(nonce, "0x");
cbin2hex(&nonce[2], (const char*) stratum.job.xnonce2, stratum.xnonce2_size);
} }
snprintf(p, MYBUFSIZ, "URL=%s;USER=%s;H=%u;JOB=%s;DIFF=%.6f;N2SZ=%d;N2=0x%s;PING=%u;DISCO=%u;UPTIME=%u|", snprintf(s, MYBUFSIZ, "URL=%s;USER=%s;ACC=%d;REJ=%d;H=%u;JOB=%s;DIFF=%.6f;"
stratum.url, rpc_user ? rpc_user : "", "N2SZ=%d;N2=%s;PING=%u;DISCO=%u;WAIT=%u;UPTIME=%u|",
stratum.job.height, jobid, stratum.job.diff, p->url, p->type & POOL_STRATUM ? p->user : "",
p->accepted_count, p->rejected_count,
stratum.job.height, jobid, stratum_diff,
(int) stratum.xnonce2_size, nonce, stratum.answer_msec, (int) stratum.xnonce2_size, nonce, stratum.answer_msec,
stratum.disconnects, (uint32_t) (time(NULL) - stratum.tm_connected)); p->disconnects, p->wait_time, p->work_time);
return p; return s;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -342,9 +350,9 @@ static char *getscanlog(char *params)
*buffer = '\0'; *buffer = '\0';
for (int i = 0; i < records; i++) { for (int i = 0; i < records; i++) {
time_t ts = data[i].tm_upd; time_t ts = data[i].tm_upd;
p += sprintf(p, "H=%u;JOB=%u;N=%u;FROM=0x%x;SCANTO=0x%x;" p += sprintf(p, "H=%u;P=%u;JOB=%u;N=%u;FROM=0x%x;SCANTO=0x%x;"
"COUNT=0x%x;FOUND=%u;TS=%u|", "COUNT=0x%x;FOUND=%u;TS=%u|",
data[i].height, data[i].njobid, data[i].nonce, data[i].scanned_from, data[i].scanned_to, data[i].height, data[i].npool, data[i].njobid, data[i].nonce, data[i].scanned_from, data[i].scanned_to,
(data[i].scanned_to - data[i].scanned_from), data[i].tm_sent ? 1 : 0, (uint32_t)ts); (data[i].scanned_to - data[i].scanned_from), data[i].tm_sent ? 1 : 0, (uint32_t)ts);
} }
return buffer; return buffer;
@ -380,19 +388,47 @@ static bool check_remote_access(void)
return (opt_api_remote > 0); return (opt_api_remote > 0);
} }
/**
* Set pool by index (pools array in json config)
* switchpool|1|
*/
static char *remote_switchpool(char *params)
{
bool ret = false;
*buffer = '\0';
if (!check_remote_access())
return buffer;
if (!params || strlen(params) == 0) {
// rotate pool test
ret = pool_switch_next();
} else {
int n = atoi(params);
if (n == cur_pooln)
ret = true;
else if (n < num_pools)
ret = pool_switch(n);
}
sprintf(buffer, "%s|", ret ? "ok" : "fail");
return buffer;
}
/** /**
* Change pool url (see --url parameter) * Change pool url (see --url parameter)
* seturl|stratum+tcp://Danila.1:X@pool.ipominer.com:3335| * seturl|stratum+tcp://<user>:<pass>@mine.xpool.ca:1131|
*/ */
extern bool stratum_need_reset;
static char *remote_seturl(char *params) static char *remote_seturl(char *params)
{ {
bool ret;
*buffer = '\0'; *buffer = '\0';
if (!check_remote_access()) if (!check_remote_access())
return buffer; return buffer;
parse_arg('o', params); if (!params || strlen(params) == 0) {
stratum_need_reset = true; // rotate pool test
sprintf(buffer, "%s", "ok|"); ret = pool_switch_next();
} else {
ret = pool_switch_url(params);
}
sprintf(buffer, "%s|", ret ? "ok" : "fail");
return buffer; return buffer;
} }
@ -425,7 +461,8 @@ struct CMDS {
{ "scanlog", getscanlog }, { "scanlog", getscanlog },
/* remote functions */ /* remote functions */
{ "seturl", remote_seturl }, { "seturl", remote_seturl }, /* prefer switchpool, deprecated */
{ "switchpool", remote_switchpool },
{ "quit", remote_quit }, { "quit", remote_quit },
/* keep it the last */ /* keep it the last */

12
api/index.php

@ -1,5 +1,5 @@
<?php <?php
/* ccminer API sample UI */ /* ccminer API sample UI (API 1.5) */
$host = 'http://localhost/api/'; // 'http://'.$_SERVER['SERVER_NAME'].'/api/'; $host = 'http://localhost/api/'; // 'http://'.$_SERVER['SERVER_NAME'].'/api/';
$configs = array( $configs = array(
@ -27,7 +27,7 @@ function getdataFromPeers()
function ignoreField($key) function ignoreField($key)
{ {
$ignored = array( $ignored = array(
'API','VER','GPU','BUS', 'API','VER','GPU','BUS','POOLS',
'CARD','GPUS','CPU','TS', 'CARD','GPUS','CPU','TS',
); );
return in_array($key, $ignored); return in_array($key, $ignored);
@ -47,13 +47,17 @@ function translateField($key)
$intl['ACCMN'] = 'Accepted / mn'; $intl['ACCMN'] = 'Accepted / mn';
$intl['REJ'] = 'Rejected'; $intl['REJ'] = 'Rejected';
$intl['DIFF'] = 'Difficulty'; $intl['DIFF'] = 'Difficulty';
$intl['NETKHS'] = 'Net Rate';
$intl['UPTIME'] = 'Miner up time'; $intl['UPTIME'] = 'Miner up time';
$intl['TS'] = 'Last update'; $intl['TS'] = 'Last update';
$intl['THR'] = 'Throughput'; $intl['THR'] = 'Throughput';
$intl['WAIT'] = 'Wait time';
$intl['H'] = 'Bloc height'; $intl['H'] = 'Bloc height';
$intl['I'] = 'Intensity'; $intl['I'] = 'Intensity';
$intl['HWF'] = 'Failures'; $intl['HWF'] = 'Failures';
$intl['POOLS'] = 'Pools';
$intl['TEMP'] = 'T°c'; $intl['TEMP'] = 'T°c';
$intl['FAN'] = 'Fan %'; $intl['FAN'] = 'Fan %';
@ -76,6 +80,7 @@ function translateValue($key,$val,$data=array())
{ {
switch ($key) { switch ($key) {
case 'UPTIME': case 'UPTIME':
case 'WAIT':
$min = floor(intval($val) / 60); $min = floor(intval($val) / 60);
$sec = intval($val) % 60; $sec = intval($val) % 60;
$val = "${min}mn${sec}s"; $val = "${min}mn${sec}s";
@ -95,6 +100,7 @@ function translateValue($key,$val,$data=array())
$val = strftime("%H:%M:%S", (int) $val); $val = strftime("%H:%M:%S", (int) $val);
break; break;
case 'KHS': case 'KHS':
case 'NETKHS':
$val = '<span class="bold">'.$val.'</span> kH/s'; $val = '<span class="bold">'.$val.'</span> kH/s';
break; break;
case 'NAME': case 'NAME':
@ -246,7 +252,7 @@ span.elipsis { display: inline-block; max-width: 130px; overflow: hidden; }
</div> </div>
<div id="footer"> <div id="footer">
<p>&copy; 2014 <a href="http://github.com/tpruvot/ccminer">tpruvot@github</a></p> <p>&copy; 2014-2015 <a href="http://github.com/tpruvot/ccminer">tpruvot@github</a></p>
</div> </div>
</body> </body>

824
ccminer.cpp

File diff suppressed because it is too large Load Diff

8
hashlog.cpp

@ -18,13 +18,17 @@
/* from miner.h /* from miner.h
struct hashlog_data { struct hashlog_data {
uint32_t tm_sent; uint8_t npool;
uint8_t pool_type;
uint32_t height; uint32_t height;
uint32_t njobid;
uint32_t nonce;
uint32_t scanned_from; uint32_t scanned_from;
uint32_t scanned_to; uint32_t scanned_to;
uint32_t last_from; uint32_t last_from;
uint32_t tm_add; uint32_t tm_add;
uint32_t tm_upd; uint32_t tm_upd;
uint32_t tm_sent;
}; };
*/ */
@ -75,6 +79,8 @@ void hashlog_remember_submit(struct work* work, uint32_t nonce)
data.height = work->height; data.height = work->height;
data.njobid = (uint32_t) njobid; data.njobid = (uint32_t) njobid;
data.tm_add = data.tm_upd = data.tm_sent = (uint32_t) time(NULL); data.tm_add = data.tm_upd = data.tm_sent = (uint32_t) time(NULL);
data.npool = (uint8_t) cur_pooln;
data.pool_type = pools[cur_pooln].type;
tlastshares[key] = data; tlastshares[key] = data;
} }

76
miner.h

@ -423,16 +423,25 @@ struct stats_data {
uint32_t tm_stat; uint32_t tm_stat;
uint32_t hashcount; uint32_t hashcount;
uint32_t height; uint32_t height;
double difficulty; double difficulty;
double hashrate; double hashrate;
uint8_t thr_id; uint8_t thr_id;
uint8_t gpu_id; uint8_t gpu_id;
uint8_t hashfound; uint8_t hashfound;
uint8_t ignored; uint8_t ignored;
uint8_t npool;
uint8_t pool_type;
uint16_t align;
}; };
struct hashlog_data { struct hashlog_data {
uint32_t tm_sent; uint8_t npool;
uint8_t pool_type;
uint16_t align;
uint32_t height; uint32_t height;
uint32_t njobid; uint32_t njobid;
uint32_t nonce; uint32_t nonce;
@ -441,6 +450,7 @@ struct hashlog_data {
uint32_t last_from; uint32_t last_from;
uint32_t tm_add; uint32_t tm_add;
uint32_t tm_upd; uint32_t tm_upd;
uint32_t tm_sent;
}; };
/* end of api */ /* end of api */
@ -529,8 +539,6 @@ extern uint32_t gpus_intensity[MAX_GPUS];
extern void format_hashrate(double hashrate, char *output); extern void format_hashrate(double hashrate, char *output);
extern void applog(int prio, const char *fmt, ...); extern void applog(int prio, const char *fmt, ...);
void get_defconfig_path(char *out, size_t bufsize, char *argv0); void get_defconfig_path(char *out, size_t bufsize, char *argv0);
extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
const char *rpc_req, bool, bool, int *);
extern void cbin2hex(char *out, const char *in, size_t len); extern void cbin2hex(char *out, const char *in, size_t len);
extern char *bin2hex(const unsigned char *in, size_t len); extern char *bin2hex(const unsigned char *in, size_t len);
extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@ -567,7 +575,6 @@ struct stratum_ctx {
curl_socket_t sock; curl_socket_t sock;
size_t sockbuf_size; size_t sockbuf_size;
char *sockbuf; char *sockbuf;
pthread_mutex_t sock_lock;
double next_diff; double next_diff;
@ -576,11 +583,10 @@ struct stratum_ctx {
unsigned char *xnonce1; unsigned char *xnonce1;
size_t xnonce2_size; size_t xnonce2_size;
struct stratum_job job; struct stratum_job job;
pthread_mutex_t work_lock;
struct timeval tv_submit; struct timeval tv_submit;
uint32_t answer_msec; uint32_t answer_msec;
uint32_t disconnects; int pooln;
time_t tm_connected; time_t tm_connected;
int srvtime_diff; int srvtime_diff;
@ -602,11 +608,68 @@ struct work {
double difficulty; double difficulty;
uint32_t height; uint32_t height;
uint8_t pooln;
uint32_t scanned_from; uint32_t scanned_from;
uint32_t scanned_to; uint32_t scanned_to;
}; };
#define MAX_POOLS 8
struct pool_infos {
uint8_t id;
#define POOL_UNUSED 0
#define POOL_GETWORK 1
#define POOL_STRATUM 2
#define POOL_LONGPOLL 4
uint8_t type;
#define POOL_ST_DEFINED 1
#define POOL_ST_VALID 2
#define POOL_ST_DISABLED 4
#define POOL_ST_REMOVED 8
uint16_t status;
char name[64];
// credentials
char url[256];
char short_url[64];
char user[64];
char pass[64];
// config options
double max_diff;
double max_rate;
int time_limit;
int scantime;
// connection
struct stratum_ctx stratum;
uint8_t allow_gbt;
uint8_t allow_mininginfo;
uint16_t check_dups; // 16_t for align
int retries;
int fail_pause;
int timeout;
// stats
uint32_t work_time;
uint32_t wait_time;
uint32_t accepted_count;
uint32_t rejected_count;
uint32_t disconnects;
};
extern struct pool_infos pools[MAX_POOLS];
extern int num_pools;
extern volatile int cur_pooln;
int pool_get_first_valid(int startfrom);
void pool_set_creds(int pooln);
void pool_set_attr(int pooln, const char* key, char* arg);
bool pool_switch_url(char *params);
bool pool_switch(int pooln);
bool pool_switch_next(void);
json_t * json_rpc_call_pool(CURL *curl, struct pool_infos*,
const char *req, bool lp_scan, bool lp, int *err);
json_t * json_rpc_longpoll(CURL *curl, char *lp_url, struct pool_infos*,
const char *req, int *err);
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout); bool stratum_socket_full(struct stratum_ctx *sctx, int timeout);
bool stratum_send_line(struct stratum_ctx *sctx, char *s); bool stratum_send_line(struct stratum_ctx *sctx, char *s);
char *stratum_recv_line(struct stratum_ctx *sctx); char *stratum_recv_line(struct stratum_ctx *sctx);
@ -615,6 +678,7 @@ void stratum_disconnect(struct stratum_ctx *sctx);
bool stratum_subscribe(struct stratum_ctx *sctx); bool stratum_subscribe(struct stratum_ctx *sctx);
bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass); bool stratum_authorize(struct stratum_ctx *sctx, const char *user, const char *pass);
bool stratum_handle_method(struct stratum_ctx *sctx, const char *s); bool stratum_handle_method(struct stratum_ctx *sctx, const char *s);
void stratum_free_job(struct stratum_ctx *sctx);
void hashlog_remember_submit(struct work* work, uint32_t nonce); void hashlog_remember_submit(struct work* work, uint32_t nonce);
void hashlog_remember_scan_range(struct work* work); void hashlog_remember_scan_range(struct work* work);

27
pools.conf

@ -0,0 +1,27 @@
{
"_note": "Sample rotation of 2 pools",
"pools":[{
"name": "Longpoll sample",
"url": "http://ziftr.suprnova.cc:9991",
"user": "tpruvot.win",
"pass": "x",
"max-diff": 0.0,
"time-limit": 180,
"disabled": false
},
{
"name": "Stratum sample",
"url": "stratum+tcp://zrc-stratum.suprnova.cc:2257",
"user": "tpruvot.elite",
"pass": "x",
"time-limit": 300
}],
"algo" : "zr5",
"api-bind" : "0.0.0.0",
"api-remote" : true,
"no-gbt": true
}

2
stats.cpp

@ -41,6 +41,8 @@ void stats_remember_speed(int thr_id, uint32_t hashcount, double hashrate, uint8
data.thr_id = (uint8_t) thr_id; data.thr_id = (uint8_t) thr_id;
data.tm_stat = (uint32_t) time(NULL); data.tm_stat = (uint32_t) time(NULL);
data.height = height; data.height = height;
data.npool = (uint8_t) cur_pooln;
data.pool_type = pools[cur_pooln].type;
data.hashcount = hashcount; data.hashcount = hashcount;
data.hashfound = found; data.hashfound = found;
data.hashrate = hashrate; data.hashrate = hashrate;

124
util.cpp

@ -36,6 +36,9 @@
#include "miner.h" #include "miner.h"
#include "elist.h" #include "elist.h"
extern pthread_mutex_t stratum_sock_lock;
extern pthread_mutex_t stratum_work_lock;
bool opt_tracegpu = false; bool opt_tracegpu = false;
struct data_buffer { struct data_buffer {
@ -385,9 +388,12 @@ static int sockopt_keepalive_cb(void *userdata, curl_socket_t fd,
} }
#endif #endif
json_t *json_rpc_call(CURL *curl, const char *url, /* For getwork (longpoll or wallet) - not stratum pools!
* DO NOT USE DIRECTLY
*/
static json_t *json_rpc_call(CURL *curl, const char *url,
const char *userpass, const char *rpc_req, const char *userpass, const char *rpc_req,
bool longpoll_scan, bool longpoll, int *curl_err) bool longpoll_scan, bool longpoll, bool keepalive, int *curl_err)
{ {
json_t *val, *err_val, *res_val; json_t *val, *err_val, *res_val;
int rc; int rc;
@ -395,10 +401,10 @@ json_t *json_rpc_call(CURL *curl, const char *url,
struct upload_buffer upload_data; struct upload_buffer upload_data;
json_error_t err; json_error_t err;
struct curl_slist *headers = NULL; struct curl_slist *headers = NULL;
char* httpdata; char *httpdata;
char len_hdr[64], hashrate_hdr[64]; char len_hdr[64], hashrate_hdr[64];
char curl_err_str[CURL_ERROR_SIZE] = { 0 }; char curl_err_str[CURL_ERROR_SIZE] = { 0 };
long timeout = longpoll ? opt_timeout : 30; long timeout = longpoll ? opt_timeout*2 : opt_timeout;
struct header_info hi = { 0 }; struct header_info hi = { 0 };
bool lp_scanning = longpoll_scan && !have_longpoll; bool lp_scanning = longpoll_scan && !have_longpoll;
@ -435,7 +441,7 @@ json_t *json_rpc_call(CURL *curl, const char *url,
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
} }
#if LIBCURL_VERSION_NUM >= 0x070f06 #if LIBCURL_VERSION_NUM >= 0x070f06
if (longpoll) if (keepalive)
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb); curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
#endif #endif
curl_easy_setopt(curl, CURLOPT_POST, 1); curl_easy_setopt(curl, CURLOPT_POST, 1);
@ -486,7 +492,8 @@ json_t *json_rpc_call(CURL *curl, const char *url,
} }
if (!all_data.buf || !all_data.len) { if (!all_data.buf || !all_data.len) {
applog(LOG_ERR, "Empty data received in json_rpc_call."); if (!have_longpoll) // seems normal on longpoll timeout
applog(LOG_ERR, "Empty data received in json_rpc_call.");
goto err_out; goto err_out;
} }
@ -571,6 +578,31 @@ err_out:
return NULL; return NULL;
} }
/* getwork calls with pool pointer (wallet/longpoll pools) */
json_t *json_rpc_call_pool(CURL *curl, struct pool_infos *pool, const char *req,
bool longpoll_scan, bool longpoll, int *curl_err)
{
char userpass[256];
// todo, malloc and store that in pool array
snprintf(userpass, sizeof(userpass), "%s%c%s", pool->user,
strlen(pool->pass)?':':'\0', pool->pass);
return json_rpc_call(curl, pool->url, userpass, req, longpoll_scan, false, false, curl_err);
}
/* called only from longpoll thread */
json_t *json_rpc_longpoll(CURL *curl, char *lp_url, struct pool_infos *pool, const char *req, int *curl_err)
{
char userpass[256];
snprintf(userpass, sizeof(userpass), "%s%c%s", pool->user,
strlen(pool->pass)?':':'\0', pool->pass);
// on pool rotate by time-limit, this keepalive can be a problem
bool keepalive = pool->time_limit == 0 || pool->time_limit > opt_timeout*4;
return json_rpc_call(curl, lp_url, userpass, req, want_longpoll, have_longpoll, keepalive, curl_err);
}
/** /**
* Unlike malloc, calloc set the memory to zero * Unlike malloc, calloc set the memory to zero
*/ */
@ -774,9 +806,9 @@ bool stratum_send_line(struct stratum_ctx *sctx, char *s)
if (opt_protocol) if (opt_protocol)
applog(LOG_DEBUG, "> %s", s); applog(LOG_DEBUG, "> %s", s);
pthread_mutex_lock(&sctx->sock_lock); pthread_mutex_lock(&stratum_sock_lock);
ret = send_line(sctx->sock, s); ret = send_line(sctx->sock, s);
pthread_mutex_unlock(&sctx->sock_lock); pthread_mutex_unlock(&stratum_sock_lock);
return ret; return ret;
} }
@ -797,6 +829,7 @@ static bool socket_full(curl_socket_t sock, int timeout)
bool stratum_socket_full(struct stratum_ctx *sctx, int timeout) bool stratum_socket_full(struct stratum_ctx *sctx, int timeout)
{ {
if (!sctx->sockbuf) return false;
return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout); return strlen(sctx->sockbuf) || socket_full(sctx->sock, timeout);
} }
@ -821,10 +854,13 @@ char *stratum_recv_line(struct stratum_ctx *sctx)
ssize_t len, buflen; ssize_t len, buflen;
char *tok, *sret = NULL; char *tok, *sret = NULL;
if (!sctx->sockbuf)
return NULL;
if (!strstr(sctx->sockbuf, "\n")) { if (!strstr(sctx->sockbuf, "\n")) {
bool ret = true; bool ret = true;
time_t rstart = time(NULL); time_t rstart = time(NULL);
if (!socket_full(sctx->sock, 60)) { if (!socket_full(sctx->sock, opt_timeout)) {
applog(LOG_ERR, "stratum_recv_line timed out"); applog(LOG_ERR, "stratum_recv_line timed out");
goto out; goto out;
} }
@ -845,7 +881,7 @@ char *stratum_recv_line(struct stratum_ctx *sctx)
} }
} else } else
stratum_buffer_append(sctx, s); stratum_buffer_append(sctx, s);
} while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n")); } while (time(NULL) - rstart < opt_timeout && !strstr(sctx->sockbuf, "\n"));
if (!ret) { if (!ret) {
applog(LOG_ERR, "stratum_recv_line failed"); applog(LOG_ERR, "stratum_recv_line failed");
@ -888,13 +924,13 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
CURL *curl; CURL *curl;
int rc; int rc;
pthread_mutex_lock(&sctx->sock_lock); pthread_mutex_lock(&stratum_sock_lock);
if (sctx->curl) if (sctx->curl)
curl_easy_cleanup(sctx->curl); curl_easy_cleanup(sctx->curl);
sctx->curl = curl_easy_init(); sctx->curl = curl_easy_init();
if (!sctx->curl) { if (!sctx->curl) {
applog(LOG_ERR, "CURL initialization failed"); applog(LOG_ERR, "CURL initialization failed");
pthread_mutex_unlock(&sctx->sock_lock); pthread_mutex_unlock(&stratum_sock_lock);
return false; return false;
} }
curl = sctx->curl; curl = sctx->curl;
@ -903,21 +939,21 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
sctx->sockbuf_size = RBUFSIZE; sctx->sockbuf_size = RBUFSIZE;
} }
sctx->sockbuf[0] = '\0'; sctx->sockbuf[0] = '\0';
pthread_mutex_unlock(&sctx->sock_lock); pthread_mutex_unlock(&stratum_sock_lock);
if (url != sctx->url) { if (url != sctx->url) {
free(sctx->url); free(sctx->url);
sctx->url = strdup(url); sctx->url = strdup(url);
} }
free(sctx->curl_url); free(sctx->curl_url);
sctx->curl_url = (char*)malloc(strlen(url)); sctx->curl_url = (char*)malloc(strlen(url)+1);
sprintf(sctx->curl_url, "http%s", strstr(url, "://")); sprintf(sctx->curl_url, "http%s", strstr(url, "://"));
if (opt_protocol) if (opt_protocol)
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url); curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30); curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, opt_timeout);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str); curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
@ -957,16 +993,41 @@ bool stratum_connect(struct stratum_ctx *sctx, const char *url)
return true; return true;
} }
void stratum_free_job(struct stratum_ctx *sctx)
{
pthread_mutex_lock(&stratum_work_lock);
if (sctx->job.job_id) {
free(sctx->job.job_id);
}
if (sctx->job.merkle_count) {
for (int i = 0; i < sctx->job.merkle_count; i++) {
free(sctx->job.merkle[i]);
sctx->job.merkle[i] = NULL;
}
free(sctx->job.merkle);
}
free(sctx->job.coinbase);
// note: xnonce2 is not allocated
memset(&(sctx->job.job_id), 0, sizeof(struct stratum_job));
pthread_mutex_unlock(&stratum_work_lock);
}
void stratum_disconnect(struct stratum_ctx *sctx) void stratum_disconnect(struct stratum_ctx *sctx)
{ {
pthread_mutex_lock(&sctx->sock_lock); pthread_mutex_lock(&stratum_sock_lock);
if (sctx->curl) { if (sctx->curl) {
sctx->disconnects++; pools[sctx->pooln].disconnects++;
curl_easy_cleanup(sctx->curl); curl_easy_cleanup(sctx->curl);
sctx->curl = NULL; sctx->curl = NULL;
sctx->sockbuf[0] = '\0'; if (sctx->sockbuf)
sctx->sockbuf[0] = '\0';
// free(sctx->sockbuf);
// sctx->sockbuf = NULL;
}
if (sctx->job.job_id) {
stratum_free_job(sctx);
} }
pthread_mutex_unlock(&sctx->sock_lock); pthread_mutex_unlock(&stratum_sock_lock);
} }
static const char *get_stratum_session_id(json_t *val) static const char *get_stratum_session_id(json_t *val)
@ -1012,19 +1073,19 @@ static bool stratum_parse_extranonce(struct stratum_ctx *sctx, json_t *params, i
goto out; goto out;
} }
pthread_mutex_lock(&sctx->work_lock); pthread_mutex_lock(&stratum_work_lock);
if (sctx->xnonce1) if (sctx->xnonce1)
free(sctx->xnonce1); free(sctx->xnonce1);
sctx->xnonce1_size = strlen(xnonce1) / 2; sctx->xnonce1_size = strlen(xnonce1) / 2;
sctx->xnonce1 = (uchar*) calloc(1, sctx->xnonce1_size); sctx->xnonce1 = (uchar*) calloc(1, sctx->xnonce1_size);
if (unlikely(!sctx->xnonce1)) { if (unlikely(!sctx->xnonce1)) {
applog(LOG_ERR, "Failed to alloc xnonce1"); applog(LOG_ERR, "Failed to alloc xnonce1");
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&stratum_work_lock);
goto out; goto out;
} }
hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size); hex2bin(sctx->xnonce1, xnonce1, sctx->xnonce1_size);
sctx->xnonce2_size = xn2_size; sctx->xnonce2_size = xn2_size;
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&stratum_work_lock);
if (pndx == 0 && opt_debug) /* pool dynamic change */ if (pndx == 0 && opt_debug) /* pool dynamic change */
applog(LOG_DEBUG, "Stratum set nonce %s with extranonce2 size=%d", applog(LOG_DEBUG, "Stratum set nonce %s with extranonce2 size=%d",
@ -1103,12 +1164,12 @@ start:
if (opt_debug && sid) if (opt_debug && sid)
applog(LOG_DEBUG, "Stratum session id: %s", sid); applog(LOG_DEBUG, "Stratum session id: %s", sid);
pthread_mutex_lock(&sctx->work_lock); pthread_mutex_lock(&stratum_work_lock);
if (sctx->session_id) if (sctx->session_id)
free(sctx->session_id); free(sctx->session_id);
sctx->session_id = sid ? strdup(sid) : NULL; sctx->session_id = sid ? strdup(sid) : NULL;
sctx->next_diff = 1.0; sctx->next_diff = 1.0;
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&stratum_work_lock);
out: out:
free(s); free(s);
@ -1253,8 +1314,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
bool clean, ret = false; bool clean, ret = false;
int merkle_count, i; int merkle_count, i;
json_t *merkle_arr; json_t *merkle_arr;
uchar **merkle; uchar **merkle = NULL;
uchar(*merkle_tree)[32] = NULL; // uchar(*merkle_tree)[32] = { 0 };
int ntime; int ntime;
job_id = json_string_value(json_array_get(params, 0)); job_id = json_string_value(json_array_get(params, 0));
@ -1287,7 +1348,8 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
applog(LOG_DEBUG, "stratum time is at least %ds in the future", ntime); applog(LOG_DEBUG, "stratum time is at least %ds in the future", ntime);
} }
merkle = (uchar**) malloc(merkle_count * sizeof(char *)); if (merkle_count)
merkle = (uchar**) malloc(merkle_count * sizeof(char *));
for (i = 0; i < merkle_count; i++) { for (i = 0; i < merkle_count; i++) {
const char *s = json_string_value(json_array_get(merkle_arr, i)); const char *s = json_string_value(json_array_get(merkle_arr, i));
if (!s || strlen(s) != 64) { if (!s || strlen(s) != 64) {
@ -1301,7 +1363,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
hex2bin(merkle[i], s, 32); hex2bin(merkle[i], s, 32);
} }
pthread_mutex_lock(&sctx->work_lock); pthread_mutex_lock(&stratum_work_lock);
coinb1_size = strlen(coinb1) / 2; coinb1_size = strlen(coinb1) / 2;
coinb2_size = strlen(coinb2) / 2; coinb2_size = strlen(coinb2) / 2;
@ -1341,7 +1403,7 @@ static bool stratum_notify(struct stratum_ctx *sctx, json_t *params)
sctx->job.diff = sctx->next_diff; sctx->job.diff = sctx->next_diff;
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&stratum_work_lock);
ret = true; ret = true;
@ -1358,9 +1420,9 @@ static bool stratum_set_difficulty(struct stratum_ctx *sctx, json_t *params)
if (diff <= 0.0) if (diff <= 0.0)
return false; return false;
pthread_mutex_lock(&sctx->work_lock); pthread_mutex_lock(&stratum_work_lock);
sctx->next_diff = diff; sctx->next_diff = diff;
pthread_mutex_unlock(&sctx->work_lock); pthread_mutex_unlock(&stratum_work_lock);
/* store for api stats */ /* store for api stats */
if (diff != stratum_diff) { if (diff != stratum_diff) {

Loading…
Cancel
Save