diff --git a/src/stratifier.c b/src/stratifier.c index 2502de9f..6c6d57df 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -228,6 +228,7 @@ static user_instance_t *user_instances; /* Combined data from workers with the same workername */ struct worker_instance { + user_instance_t *instance; char *workername; worker_instance_t *next; @@ -284,6 +285,8 @@ struct stratum_instance { ckpool_t *ckp; time_t last_txns; /* Last time this worker requested txn hashes */ + + int64_t suggest_diff; /* Stratum client suggested diff */ }; /* Stratum_instances hashlist is stored by id, whereas disconnected_instances @@ -1516,6 +1519,7 @@ static user_instance_t *generate_user(ckpool_t *ckp, stratum_instance_t *client, if (!client->worker_instance) { client->worker_instance = ckzalloc(sizeof(worker_instance_t)); client->worker_instance->workername = strdup(workername); + client->worker_instance->instance = instance; DL_APPEND(instance->worker_instances, client->worker_instance); } DL_APPEND(instance->instances, client); @@ -1818,12 +1822,23 @@ static void add_submit(ckpool_t *ckp, stratum_instance_t *client, int diff, bool if (drr > 0.15 && drr < 0.4) return; - /* Round away from zero to avoid bouncing around diffs at the lower - * end of the scale. */ - optimal = lround(dsps * 3.33); + /* Allow slightly lower diffs when users choose their own mindiff */ + if (worker->mindiff || client->suggest_diff) { + if (drr < 0.5) + return; + optimal = lround(dsps * 2.4); + } else + optimal = lround(dsps * 3.33); + /* Clamp to mindiff ~ network_diff */ if (optimal < ckp->mindiff) optimal = ckp->mindiff; + /* Client suggest diff overrides worker mindiff */ + if (client->suggest_diff) { + if (optimal < client->suggest_diff) + optimal = client->suggest_diff; + } else if (optimal < worker->mindiff) + optimal = worker->mindiff; if (optimal > network_diff) optimal = network_diff; if (client->diff == optimal) @@ -2311,6 +2326,66 @@ static json_params_t *create_json_params(const int64_t client_id, const json_t * return jp; } +#if 0 +static void set_worker_mindiff(ckpool_t *ckp, worker_instance_t *worker, int64_t mindiff) +{ + stratum_instance_t *client; + user_instance_t *instance; + + if (mindiff < 1) + return LOGINFO("Worker %s requested invalid diff %ld", worker->workername, mindiff); + if (mindiff < ckp->mindiff) + mindiff = ckp->mindiff; + if (mindiff == worker->mindiff) + return; + worker->mindiff = mindiff; + instance = worker->instance; + + /* Iterate over all the workers from this user to find any with the + * matching worker that are currently live and send them a new diff + * if we can. Otherwise it will only act as a clamp on next share + * submission. */ + ck_rlock(&instance_lock); + DL_FOREACH(instance->instances, client) { + if (client->worker_instance != worker) + continue; + /* Per connection suggest diff overrides worker mindiff ugh */ + if (mindiff < client->suggest_diff) + continue; + if (mindiff == client->diff) + continue; + /* If we're going down in diff, do not allow the next diff to + * be drastically lower than the current diff */ + if (mindiff < client->diff * 2 / 3) + client->diff = client->diff * 2 / 3; + else + client->diff = mindiff; + stratum_send_diff(client); + } + ck_runlock(&instance_lock); +} +#endif + +static void suggest_diff(stratum_instance_t *client, const char *method) +{ + int64_t sdiff; + + if (unlikely(!client->authorised)) + return LOGWARNING("Attempted to suggest diff on unauthorised client %ld", client->id); + if (sscanf(method, "mining.suggest_difficulty(%ld", &sdiff) != 1) + return LOGINFO("Failed to parse suggest_difficulty for client %ld", client->id); + if (sdiff == client->suggest_diff) + return; + client->suggest_diff = sdiff; + if (client->diff == sdiff) + return; + if (sdiff < client->diff * 2 / 3) + client->diff = client->diff * 2 / 3; + else + client->diff = sdiff; + stratum_send_diff(client); +} + static void parse_method(const int64_t client_id, json_t *id_val, json_t *method_val, json_t *params_val, char *address) { @@ -2389,6 +2464,11 @@ static void parse_method(const int64_t client_id, json_t *id_val, json_t *method return; } + if (cmdmatch(method, "mining.suggest")) { + suggest_diff(client, method); + return; + } + /* Covers both get_transactions and get_txnhashes */ if (cmdmatch(method, "mining.get")) { json_params_t *jp = create_json_params(client_id, method_val, id_val, address);