diff --git a/components/asic/asic_common.c b/components/asic/asic_common.c index 7379b70a0..3f485616a 100644 --- a/components/asic/asic_common.c +++ b/components/asic/asic_common.c @@ -1,5 +1,6 @@ #include #include +#include #include "asic_common.h" #include "serial.h" @@ -24,18 +25,6 @@ unsigned char _reverse_bits(unsigned char num) return reversed; } -int _largest_power_of_two(int num) -{ - int power = 0; - - while (num > 1) { - num = num >> 1; - power++; - } - - return 1 << power; -} - int count_asic_chips(uint16_t asic_count, uint16_t chip_id, int chip_id_response_length) { uint8_t buffer[11] = {0}; @@ -127,12 +116,22 @@ esp_err_t receive_work(uint8_t * buffer, int buffer_size) return ESP_OK; } -void get_difficulty_mask(uint16_t difficulty, uint8_t *job_difficulty_mask) +void get_difficulty_mask(double difficulty, uint8_t *job_difficulty_mask) { // The mask must be a power of 2 so there are no holes // Correct: {0b00000000, 0b00000000, 0b11111111, 0b11111111} // Incorrect: {0b00000000, 0b00000000, 0b11100111, 0b11111111} - difficulty = _largest_power_of_two(difficulty) - 1; + + // Round up to ensure we don't make difficulty harder than requested, then convert to int + uint32_t diff_int = (uint32_t)ceil(difficulty); + + // Calculate largest power of 2 <= diff_int (inline of former _largest_power_of_two) + int power = 0; + while (diff_int > 1) { + diff_int = diff_int >> 1; + power++; + } + uint32_t mask = (1 << power) - 1; job_difficulty_mask[0] = 0x00; job_difficulty_mask[1] = 0x14; // TICKET_MASK @@ -140,8 +139,8 @@ void get_difficulty_mask(uint16_t difficulty, uint8_t *job_difficulty_mask) // convert difficulty into char array // Ex: 256 = {0b00000000, 0b00000000, 0b00000000, 0b11111111}, {0x00, 0x00, 0x00, 0xff} // Ex: 512 = {0b00000000, 0b00000000, 0b00000001, 0b11111111}, {0x00, 0x00, 0x01, 0xff} - job_difficulty_mask[2] = _reverse_bits((difficulty >> 24) & 0xFF); - job_difficulty_mask[3] = _reverse_bits((difficulty >> 16) & 0xFF); - job_difficulty_mask[4] = _reverse_bits((difficulty >> 8) & 0xFF); - job_difficulty_mask[5] = _reverse_bits( difficulty & 0xFF); + job_difficulty_mask[2] = _reverse_bits((mask >> 24) & 0xFF); + job_difficulty_mask[3] = _reverse_bits((mask >> 16) & 0xFF); + job_difficulty_mask[4] = _reverse_bits((mask >> 8) & 0xFF); + job_difficulty_mask[5] = _reverse_bits( mask & 0xFF); } diff --git a/components/asic/include/asic_common.h b/components/asic/include/asic_common.h index 05034f2e2..44687798b 100644 --- a/components/asic/include/asic_common.h +++ b/components/asic/include/asic_common.h @@ -36,6 +36,6 @@ int _largest_power_of_two(int num); int count_asic_chips(uint16_t asic_count, uint16_t chip_id, int chip_id_response_length); esp_err_t receive_work(uint8_t * buffer, int buffer_size); -void get_difficulty_mask(uint16_t difficulty, uint8_t *job_difficulty_mask); +void get_difficulty_mask(double difficulty, uint8_t *job_difficulty_mask); #endif /* ASIC_COMMON_H_ */ diff --git a/components/stratum/include/mining.h b/components/stratum/include/mining.h index 4e8f75524..d07543c17 100644 --- a/components/stratum/include/mining.h +++ b/components/stratum/include/mining.h @@ -18,7 +18,7 @@ typedef struct uint8_t midstate1[32]; uint8_t midstate2[32]; uint8_t midstate3[32]; - uint32_t pool_diff; + double pool_diff; char *jobid; char *extranonce2; } bm_job; @@ -30,7 +30,7 @@ void calculate_coinbase_tx_hash(const char *coinbase_1, const char *coinbase_2, void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_t merkle_branches[][32], const int num_merkle_branches, uint8_t dest[32]); -void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty, bm_job* new_job); +void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const double difficulty, bm_job* new_job); double test_nonce_value(const bm_job *job, const uint32_t nonce, const uint32_t rolled_version); diff --git a/components/stratum/include/stratum_api.h b/components/stratum/include/stratum_api.h index da8065829..585087411 100644 --- a/components/stratum/include/stratum_api.h +++ b/components/stratum/include/stratum_api.h @@ -65,7 +65,7 @@ typedef struct // mining.notify mining_notify *mining_notification; // mining.set_difficulty - uint32_t new_difficulty; + double new_difficulty; // mining.set_version_mask uint32_t version_mask; // result diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 1e43e39d4..e09fcd234 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -46,7 +46,7 @@ void calculate_merkle_root_hash(const uint8_t coinbase_tx_hash[32], const uint8_ } // take a mining_notify struct with ascii hex strings and convert it to a bm_job struct -void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const uint32_t difficulty, bm_job *new_job) +void construct_bm_job(mining_notify *params, const uint8_t merkle_root[32], const uint32_t version_mask, const double difficulty, bm_job *new_job) { new_job->version = params->version; new_job->target = params->target; diff --git a/components/stratum/stratum_api.c b/components/stratum/stratum_api.c index 1d6896d4a..42e2f1d13 100644 --- a/components/stratum/stratum_api.c +++ b/components/stratum/stratum_api.c @@ -388,7 +388,7 @@ void STRATUM_V1_parse(StratumApiV1Message * message, const char * stratum_json) message->mining_notification = new_work; } else if (message->method == MINING_SET_DIFFICULTY) { cJSON * params = cJSON_GetObjectItem(json, "params"); - uint32_t difficulty = cJSON_GetArrayItem(params, 0)->valueint; + double difficulty = cJSON_GetArrayItem(params, 0)->valuedouble; message->new_difficulty = difficulty; } else if (message->method == MINING_SET_VERSION_MASK) { cJSON * params = cJSON_GetObjectItem(json, "params"); diff --git a/components/stratum/test/test_stratum_json.c b/components/stratum/test/test_stratum_json.c index 9b759012e..bf9220f21 100644 --- a/components/stratum/test/test_stratum_json.c +++ b/components/stratum/test/test_stratum_json.c @@ -65,7 +65,16 @@ TEST_CASE("Parse stratum set_difficulty params", "[mining.set_difficulty]") StratumApiV1Message stratum_api_v1_message = {}; STRATUM_V1_parse(&stratum_api_v1_message, json_string); TEST_ASSERT_EQUAL(MINING_SET_DIFFICULTY, stratum_api_v1_message.method); - TEST_ASSERT_EQUAL(1638, stratum_api_v1_message.new_difficulty); + TEST_ASSERT_EQUAL_DOUBLE(1638.0, stratum_api_v1_message.new_difficulty); +} + +TEST_CASE("Parse stratum set_difficulty params with fractional", "[mining.set_difficulty]") +{ + const char *json_string = "{\"id\":null,\"method\":\"mining.set_difficulty\",\"params\":[100.5]}"; + StratumApiV1Message stratum_api_v1_message = {}; + STRATUM_V1_parse(&stratum_api_v1_message, json_string); + TEST_ASSERT_EQUAL(MINING_SET_DIFFICULTY, stratum_api_v1_message.method); + TEST_ASSERT_EQUAL_DOUBLE(100.5, stratum_api_v1_message.new_difficulty); } TEST_CASE("Parse stratum notify params", "[mining.notify]") diff --git a/main/global_state.h b/main/global_state.h index 19c90d25a..ef2a22b3e 100644 --- a/main/global_state.h +++ b/main/global_state.h @@ -132,7 +132,7 @@ typedef struct uint8_t * valid_jobs; pthread_mutex_t valid_jobs_lock; - uint32_t pool_difficulty; + double pool_difficulty; bool new_set_mining_difficulty_msg; uint32_t version_mask; bool new_stratum_version_rolling_msg; diff --git a/main/tasks/asic_result_task.c b/main/tasks/asic_result_task.c index 5e097180e..e1ce0a40f 100644 --- a/main/tasks/asic_result_task.c +++ b/main/tasks/asic_result_task.c @@ -51,7 +51,7 @@ void ASIC_result_task(void *pvParameters) double nonce_diff = test_nonce_value(active_job, asic_result->nonce, asic_result->rolled_version); //log the ASIC response - ESP_LOGI(TAG, "ID: %s, ASIC nr: %d, ver: %08" PRIX32 " Nonce %08" PRIX32 " diff %.1f of %ld.", active_job->jobid, asic_result->asic_nr, asic_result->rolled_version, asic_result->nonce, nonce_diff, active_job->pool_diff); + ESP_LOGI(TAG, "ID: %s, ASIC nr: %d, ver: %08" PRIX32 " Nonce %08" PRIX32 " diff %.1f of %.2f.", active_job->jobid, asic_result->asic_nr, asic_result->rolled_version, asic_result->nonce, nonce_diff, active_job->pool_diff); if (nonce_diff >= active_job->pool_diff) { diff --git a/main/tasks/create_jobs_task.c b/main/tasks/create_jobs_task.c index d258138cd..c2d30ac32 100644 --- a/main/tasks/create_jobs_task.c +++ b/main/tasks/create_jobs_task.c @@ -15,7 +15,7 @@ static const char *TAG = "create_jobs_task"; -static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification, uint64_t extranonce_2, uint32_t difficulty); +static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification, uint64_t extranonce_2, double difficulty); void create_jobs_task(void *pvParameters) { @@ -29,7 +29,7 @@ void create_jobs_task(void *pvParameters) GLOBAL_STATE->valid_jobs[i] = 0; } - uint32_t difficulty = GLOBAL_STATE->pool_difficulty; + double difficulty = GLOBAL_STATE->pool_difficulty; mining_notify *current_mining_notification = NULL; uint64_t extranonce_2 = 0; int timeout_ms = ASIC_get_asic_job_frequency_ms(GLOBAL_STATE); @@ -52,7 +52,7 @@ void create_jobs_task(void *pvParameters) current_mining_notification = new_mining_notification; if (GLOBAL_STATE->new_set_mining_difficulty_msg) { - ESP_LOGI(TAG, "New pool difficulty %lu", GLOBAL_STATE->pool_difficulty); + ESP_LOGI(TAG, "New pool difficulty %.2f", GLOBAL_STATE->pool_difficulty); difficulty = GLOBAL_STATE->pool_difficulty; GLOBAL_STATE->new_set_mining_difficulty_msg = false; } @@ -82,7 +82,7 @@ void create_jobs_task(void *pvParameters) } } -static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification, uint64_t extranonce_2, uint32_t difficulty) +static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification, uint64_t extranonce_2, double difficulty) { char extranonce_2_str[GLOBAL_STATE->extranonce_2_len * 2 + 1]; extranonce_2_generate(extranonce_2, GLOBAL_STATE->extranonce_2_len, extranonce_2_str); diff --git a/main/tasks/stratum_task.c b/main/tasks/stratum_task.c index 18e31625c..05b036730 100644 --- a/main/tasks/stratum_task.c +++ b/main/tasks/stratum_task.c @@ -426,10 +426,6 @@ void stratum_task(void * pvParameters) primary_stratum_cert = GLOBAL_STATE->SYSTEM_MODULE.pool_cert; char * stratum_url = GLOBAL_STATE->SYSTEM_MODULE.pool_url; uint16_t port = GLOBAL_STATE->SYSTEM_MODULE.pool_port; - bool extranonce_subscribe = GLOBAL_STATE->SYSTEM_MODULE.pool_extranonce_subscribe; - uint16_t difficulty = GLOBAL_STATE->SYSTEM_MODULE.pool_difficulty; - tls_mode tls = GLOBAL_STATE->SYSTEM_MODULE.pool_tls; - char * cert = GLOBAL_STATE->SYSTEM_MODULE.pool_cert; STRATUM_V1_initialize_buffer(); int retry_attempts = 0; @@ -472,8 +468,6 @@ void stratum_task(void * pvParameters) stratum_url = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_url : GLOBAL_STATE->SYSTEM_MODULE.pool_url; port = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_port : GLOBAL_STATE->SYSTEM_MODULE.pool_port; - extranonce_subscribe = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_extranonce_subscribe : GLOBAL_STATE->SYSTEM_MODULE.pool_extranonce_subscribe; - difficulty = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_difficulty : GLOBAL_STATE->SYSTEM_MODULE.pool_difficulty; stratum_connection_info_t conn_info; if (resolve_stratum_address(stratum_url, port, &conn_info) != ESP_OK) { @@ -485,8 +479,8 @@ void stratum_task(void * pvParameters) ESP_LOGI(TAG, "Connecting to: stratum+tcp://%s:%d (%s)", stratum_url, port, conn_info.host_ip); - tls = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_tls : GLOBAL_STATE->SYSTEM_MODULE.pool_tls; - cert = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_cert : GLOBAL_STATE->SYSTEM_MODULE.pool_cert; + tls_mode tls = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_tls : GLOBAL_STATE->SYSTEM_MODULE.pool_tls; + char * cert = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_cert : GLOBAL_STATE->SYSTEM_MODULE.pool_cert; retry_critical_attempts = 0; GLOBAL_STATE->transport = STRATUM_V1_transport_init(tls, cert); @@ -576,7 +570,7 @@ void stratum_task(void * pvParameters) queue_enqueue(&GLOBAL_STATE->stratum_queue, stratum_api_v1_message.mining_notification); decode_mining_notification(GLOBAL_STATE, stratum_api_v1_message.mining_notification); } else if (stratum_api_v1_message.method == MINING_SET_DIFFICULTY) { - ESP_LOGI(TAG, "Set pool difficulty: %ld", stratum_api_v1_message.new_difficulty); + ESP_LOGI(TAG, "Set pool difficulty: %.2f", stratum_api_v1_message.new_difficulty); GLOBAL_STATE->pool_difficulty = stratum_api_v1_message.new_difficulty; GLOBAL_STATE->new_set_mining_difficulty_msg = true; } else if (stratum_api_v1_message.method == MINING_SET_VERSION_MASK || @@ -616,9 +610,11 @@ void stratum_task(void * pvParameters) retry_attempts = 0; if (stratum_api_v1_message.response_success) { ESP_LOGI(TAG, "setup message accepted"); + uint16_t difficulty = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_difficulty : GLOBAL_STATE->SYSTEM_MODULE.pool_difficulty; if (stratum_api_v1_message.message_id == authorize_message_id && difficulty > 0) { STRATUM_V1_suggest_difficulty(GLOBAL_STATE->transport, GLOBAL_STATE->send_uid++, difficulty); } + bool extranonce_subscribe = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_extranonce_subscribe : GLOBAL_STATE->SYSTEM_MODULE.pool_extranonce_subscribe; if (extranonce_subscribe) { STRATUM_V1_extranonce_subscribe(GLOBAL_STATE->transport, GLOBAL_STATE->send_uid++); }