diff --git a/main.c b/main.c index e5fefb72..15969495 100644 --- a/main.c +++ b/main.c @@ -265,6 +265,10 @@ static unsigned int total_go, total_ro; static struct pool *pools[MAX_POOLS]; static struct pool *currentpool = NULL; + +static float opt_donation = 0.0; +static struct pool donationpool; + static int total_pools; static enum pool_strategy pool_strategy = POOL_FAILOVER; static int opt_rotate_period; @@ -961,6 +965,18 @@ static char *set_int_1_to_10(const char *arg, int *i) return set_int_range(arg, i, 1, 10); } +static char *set_float_0_to_99(const char *arg, float *f) +{ + char *err = opt_set_floatval(arg, f); + if (err) + return err; + + if (*f < 0.0 || *f > 99.9) + return "Value out of range"; + + return NULL; +} + static char *set_devices(const char *arg, int *i) { char *err = opt_set_intval(arg, i); @@ -1458,6 +1474,11 @@ static struct opt_table opt_config_table[] = { OPT_WITHOUT_ARG("--disable-gpu|-G", opt_set_bool, &opt_nogpu, "Disable GPU mining even if suitable devices exist"), +#endif + OPT_WITH_ARG("--donation", + set_float_0_to_99, &opt_show_floatval, &opt_donation, + "Set donation percentage to cgminer author (0.0 - 99.9)"), +#ifdef HAVE_OPENCL OPT_WITHOUT_ARG("--enable-cpu|-C", opt_set_bool, &opt_usecpu, "Enable CPU mining with GPU mining (default: no CPU mining if suitable GPUs exist)"), @@ -2085,6 +2106,11 @@ bool regeneratehash(const struct work *work) return false; } +static bool donor(struct pool *pool) +{ + return (pool == &donationpool); +} + static bool submit_upstream_work(const struct work *work) { char *hexstr = NULL; @@ -2130,11 +2156,14 @@ static bool submit_upstream_work(const struct work *work) if (!pool_tset(pool, &pool->submit_fail)) { total_ro++; pool->remotefail_occasions++; - applog(LOG_WARNING, "Pool %d communication failure, caching submissions", pool->pool_no); + if (!donor(pool)) + applog(LOG_WARNING, "Pool %d communication failure, caching submissions", pool->pool_no); } goto out; - } else if (pool_tclear(pool, &pool->submit_fail)) - applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); + } else if (pool_tclear(pool, &pool->submit_fail)) { + if (!donor(pool)) + applog(LOG_WARNING, "Pool %d communication resumed, submitting work", pool->pool_no); + } res = json_object_get(val, "result"); @@ -2156,7 +2185,10 @@ static bool submit_upstream_work(const struct work *work) if (opt_debug) applog(LOG_DEBUG, "PROOF OF WORK RESULT: true (yay!!!)"); if (!QUIET) { - if (total_pools > 1) + if (donor(work->pool)) + applog(LOG_NOTICE, "Accepted %s %sPU %d thread %d donate", + hashshow, cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, thr_id); + else if (total_pools > 1) applog(LOG_NOTICE, "Accepted %s %sPU %d thread %d pool %d", hashshow, cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, thr_id, work->pool->pool_no); else @@ -2175,7 +2207,10 @@ static bool submit_upstream_work(const struct work *work) if (opt_debug) applog(LOG_DEBUG, "PROOF OF WORK RESULT: false (booooo)"); if (!QUIET) { - if (total_pools > 1) + if (donor(work->pool)) + applog(LOG_NOTICE, "Rejected %s %sPU %d thread %d donate", + hashshow, cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, thr_id); + else if (total_pools > 1) applog(LOG_NOTICE, "Rejected %s %sPU %d thread %d pool %d", hashshow, cgpu->is_gpu? "G" : "C", cgpu->cpu_gpu, thr_id, work->pool->pool_no); else @@ -2214,6 +2249,10 @@ static inline struct pool *select_pool(bool lagging) static int rotating_pool = 0; struct pool *pool, *cp; + if (total_getworks && opt_donation > 0.0 && !donationpool.idle && + (float)donationpool.getwork_requested / (float)total_getworks < opt_donation / 100) + return &donationpool; + cp = current_pool(); if (pool_strategy != POOL_LOADBALANCE && !lagging) @@ -3601,7 +3640,8 @@ static bool pool_active(struct pool *pool, bool pinging) static void pool_died(struct pool *pool) { if (!pool_tset(pool, &pool->idle)) { - applog(LOG_WARNING, "Pool %d %s not responding!", pool->pool_no, pool->rpc_url); + if (!donor(pool)) + applog(LOG_WARNING, "Pool %d %s not responding!", pool->pool_no, pool->rpc_url); gettimeofday(&pool->tv_idle, NULL); switch_pools(NULL); } @@ -3619,7 +3659,8 @@ static inline int cp_prio(void) static void pool_resus(struct pool *pool) { - applog(LOG_WARNING, "Pool %d %s recovered", pool->pool_no, pool->rpc_url); + if (!donor(pool)) + applog(LOG_WARNING, "Pool %d %s recovered", pool->pool_no, pool->rpc_url); if (pool->prio < cp_prio() && pool_strategy == POOL_FAILOVER) switch_pools(NULL); } @@ -3708,7 +3749,7 @@ static inline bool should_roll(struct work *work) static inline bool can_roll(struct work *work) { return (work->pool && !stale_work(work) && work->rolltime && - work->rolls < 11 && !work->clone); + work->rolls < 11 && !work->clone && !donor(work->pool)); } static void roll_work(struct work *work) @@ -4791,6 +4832,14 @@ static void *watchdog_thread(void *userdata) } } + if (opt_donation > 0.0) { + if (donationpool.idle && now.tv_sec - donationpool.tv_idle.tv_sec > 60) { + gettimeofday(&donationpool.tv_idle, NULL); + if (pool_active(&donationpool, true) && pool_tclear(&donationpool, &donationpool.idle)) + pool_resus(&donationpool); + } + } + if (pool_strategy == POOL_ROTATE && now.tv_sec - rotate_tv.tv_sec > 60 * opt_rotate_period) { gettimeofday(&rotate_tv, NULL); switch_pools(NULL); @@ -4956,6 +5005,9 @@ static void print_summary(void) } } + if (opt_donation > 0.0) + applog(LOG_WARNING, "Donated share submissions: %d\n", donationpool.accepted + donationpool.rejected); + applog(LOG_WARNING, "Summary of per device statistics:\n"); for (i = 0; i < mining_threads; i++) { if (active_device(i)) @@ -5516,6 +5568,17 @@ int main (int argc, char *argv[]) quit(0, "No servers could be used! Exiting."); } + if (opt_donation > 0.0) { + if (!get_dondata(&donationpool.rpc_url, &donationpool.rpc_userpass)) + opt_donation = 0.0; + else { + donationpool.enabled = true; + donationpool.pool_no = MAX_POOLS; + if (!pool_active(&donationpool, false)) + donationpool.idle = true; + } + } + /* If we want longpoll, enable it for the chosen default pool, or, if * the pool does not support longpoll, find the first one that does * and use its longpoll support */ diff --git a/miner.h b/miner.h index 52e4993f..472e39ac 100644 --- a/miner.h +++ b/miner.h @@ -494,5 +494,6 @@ extern void tq_thaw(struct thread_q *tq); extern bool successful_connect; extern enum cl_kernel chosen_kernel; extern void adl(void); +extern bool get_dondata(char **url, char **userpass); #endif /* __MINER_H__ */ diff --git a/util.c b/util.c index 6a53d948..2417be7d 100644 --- a/util.c +++ b/util.c @@ -682,3 +682,53 @@ void thr_info_cancel(struct thr_info *thr) if (pthread_cancel(thr->pth)) pthread_join(thr->pth, NULL); } + +bool get_dondata(char **url, char **userpass) +{ + struct data_buffer all_data = { }; + char curl_err_str[CURL_ERROR_SIZE]; + CURL *curl = curl_easy_init(); + int rc; + + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(curl, CURLOPT_ENCODING, ""); + curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); + curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, all_data_cb); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &all_data); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_err_str); + curl_easy_setopt(curl, CURLOPT_URL, "http://vds.kolivas.org/url"); + rc = curl_easy_perform(curl); + if (rc) { + applog(LOG_INFO, "HTTP request failed: %s", curl_err_str); + goto err_out; + } + if (!all_data.buf) + goto err_out; + *url = strtok(all_data.buf, "\n"); + all_data.buf = NULL; + databuf_free(&all_data); + + curl_easy_setopt(curl, CURLOPT_URL, "http://vds.kolivas.org/userpass"); + rc = curl_easy_perform(curl); + if (rc) { + applog(LOG_INFO, "HTTP request failed: %s", curl_err_str); + goto err_out; + } + if (!all_data.buf) + goto err_out; + *userpass = strtok(all_data.buf, "\n"); + all_data.buf = NULL; + databuf_free(&all_data); + + applog(LOG_INFO, "Donation URL: %s Userpass: %s", *url, *userpass); + curl_easy_cleanup(curl); + return true; + +err_out: + databuf_free(&all_data); + *url = NULL; + *userpass = NULL; + curl_easy_cleanup(curl); + return false; +}