diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..3c9788e64 --- /dev/null +++ b/.clangd @@ -0,0 +1,3 @@ +CompileFlags: + Remove: [-f*, -m*] + Add: -Wno-unknown-warning-option diff --git a/.gitignore b/.gitignore index 8b27ae7d8..83d83bf55 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,5 @@ managed_components/* .DS_Store Thumbs.db debug.log +.cache +.vscode/settings.json diff --git a/components/asic/asic.c b/components/asic/asic.c index c2b539a40..adbd71c4c 100644 --- a/components/asic/asic.c +++ b/components/asic/asic.c @@ -32,17 +32,17 @@ uint8_t ASIC_init(GlobalState * GLOBAL_STATE) return ESP_OK; } -task_result * ASIC_process_work(GlobalState * GLOBAL_STATE) +bool ASIC_process_work(GlobalState * GLOBAL_STATE, task_result * result) { switch (GLOBAL_STATE->DEVICE_CONFIG.family.asic.id) { case BM1397: - return BM1397_process_work(GLOBAL_STATE); + return BM1397_process_work(GLOBAL_STATE, result); case BM1366: - return BM1366_process_work(GLOBAL_STATE); + return BM1366_process_work(GLOBAL_STATE, result); case BM1368: - return BM1368_process_work(GLOBAL_STATE); + return BM1368_process_work(GLOBAL_STATE, result); case BM1370: - return BM1370_process_work(GLOBAL_STATE); + return BM1370_process_work(GLOBAL_STATE, result); } return NULL; } diff --git a/components/asic/bm1366.c b/components/asic/bm1366.c index be36dec00..037d051f8 100644 --- a/components/asic/bm1366.c +++ b/components/asic/bm1366.c @@ -73,8 +73,6 @@ typedef struct __attribute__((__packed__)) static const char * TAG = "bm1366"; -static task_result result; - static int address_interval; /// @brief @@ -311,26 +309,24 @@ void BM1366_send_work(void * pvParameters, bm_job * next_bm_job) _send_BM1366((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1366_job), BM1366_DEBUG_WORK); } -task_result * BM1366_process_work(void * pvParameters) +bool BM1366_process_work(void * pvParameters, task_result * result) { bm1366_asic_result_t asic_result = {0}; - memset(&result, 0, sizeof(task_result)); - - if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) { - return NULL; + if (receive_work((uint8_t *)&asic_result, sizeof(asic_result), &result->receive_time_us) == ESP_FAIL) { + return false; } if (!asic_result.is_job_response) { - result.register_type = REGISTER_MAP[asic_result.cmd.register_address]; - if (result.register_type == REGISTER_INVALID) { + result->register_type = REGISTER_MAP[asic_result.cmd.register_address]; + if (result->register_type == REGISTER_INVALID) { ESP_LOGW(TAG, "Unknown register read: %02x", asic_result.cmd.register_address); - return NULL; + return false; } - result.asic_nr = asic_result.cmd.asic_address / address_interval; - result.value = ntohl(asic_result.cmd.value); + result->asic_nr = asic_result.cmd.asic_address / address_interval; + result->value = ntohl(asic_result.cmd.value); - return &result; + return true; } uint8_t job_id = asic_result.job.id & 0xf8; @@ -345,17 +341,17 @@ task_result * BM1366_process_work(void * pvParameters) if (GLOBAL_STATE->valid_jobs[job_id] == 0) { ESP_LOGW(TAG, "Invalid job nonce found, 0x%02X", job_id); - return NULL; + return false; } uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits; - result.job_id = job_id; - result.nonce = asic_result.job.nonce; - result.rolled_version = rolled_version; - result.asic_nr = asic_nr; + result->job_id = job_id; + result->nonce = asic_result.job.nonce; + result->rolled_version = rolled_version; + result->asic_nr = asic_nr; - return &result; + return true; } void BM1366_read_registers(void) diff --git a/components/asic/bm1368.c b/components/asic/bm1368.c index 73f08479c..e25d5ea7c 100644 --- a/components/asic/bm1368.c +++ b/components/asic/bm1368.c @@ -74,8 +74,6 @@ typedef struct __attribute__((__packed__)) static const char * TAG = "bm1368"; -static task_result result; - static int address_interval; static void _send_BM1368(uint8_t header, uint8_t * data, uint8_t data_len, bool debug) @@ -254,26 +252,24 @@ void BM1368_send_work(void * pvParameters, bm_job * next_bm_job) _send_BM1368((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1368_job), BM1368_DEBUG_WORK); } -task_result * BM1368_process_work(void * pvParameters) +bool BM1368_process_work(void * pvParameters, task_result * result) { bm1368_asic_result_t asic_result = {0}; - memset(&result, 0, sizeof(task_result)); - - if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) { - return NULL; + if (receive_work((uint8_t *)&asic_result, sizeof(asic_result), &result->receive_time_us) == ESP_FAIL) { + return false; } if (!asic_result.is_job_response) { - result.register_type = REGISTER_MAP[asic_result.cmd.register_address]; - if (result.register_type == REGISTER_INVALID) { + result->register_type = REGISTER_MAP[asic_result.cmd.register_address]; + if (result->register_type == REGISTER_INVALID) { ESP_LOGW(TAG, "Unknown register read: %02x", asic_result.cmd.register_address); - return NULL; + return false; } - result.asic_nr = asic_result.cmd.asic_address / address_interval; - result.value = ntohl(asic_result.cmd.value); + result->asic_nr = asic_result.cmd.asic_address / address_interval; + result->value = ntohl(asic_result.cmd.value); - return &result; + return true; } uint8_t job_id = (asic_result.job.id & 0xf0) >> 1; @@ -288,17 +284,17 @@ task_result * BM1368_process_work(void * pvParameters) if (GLOBAL_STATE->valid_jobs[job_id] == 0) { ESP_LOGW(TAG, "Invalid job nonce found, 0x%02X", job_id); - return NULL; + return false; } uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits; - result.job_id = job_id; - result.nonce = asic_result.job.nonce; - result.rolled_version = rolled_version; - result.asic_nr = asic_nr; + result->job_id = job_id; + result->nonce = asic_result.job.nonce; + result->rolled_version = rolled_version; + result->asic_nr = asic_nr; - return &result; + return true; } void BM1368_read_registers(void) diff --git a/components/asic/bm1370.c b/components/asic/bm1370.c index 732374270..6657f63c6 100644 --- a/components/asic/bm1370.c +++ b/components/asic/bm1370.c @@ -75,8 +75,6 @@ typedef struct __attribute__((__packed__)) static const char * TAG = "bm1370"; -static task_result result; - static int address_interval; /// @brief @@ -331,26 +329,24 @@ void BM1370_send_work(void * pvParameters, bm_job * next_bm_job) _send_BM1370((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(BM1370_job), BM1370_DEBUG_WORK); } -task_result * BM1370_process_work(void * pvParameters) +bool BM1370_process_work(void * pvParameters, task_result * result) { bm1370_asic_result_t asic_result = {0}; - memset(&result, 0, sizeof(task_result)); - - if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) { - return NULL; + if (receive_work((uint8_t *)&asic_result, sizeof(asic_result), &result->receive_time_us) == ESP_FAIL) { + return false; } - + if (!asic_result.is_job_response) { - result.register_type = REGISTER_MAP[asic_result.cmd.register_address]; - if (result.register_type == REGISTER_INVALID) { + result->register_type = REGISTER_MAP[asic_result.cmd.register_address]; + if (result->register_type == REGISTER_INVALID) { ESP_LOGW(TAG, "Unknown register read: %02x", asic_result.cmd.register_address); - return NULL; + return false; } - result.asic_nr = asic_result.cmd.asic_address / address_interval; - result.value = ntohl(asic_result.cmd.value); + result->asic_nr = asic_result.cmd.asic_address / address_interval; + result->value = ntohl(asic_result.cmd.value); - return &result; + return true; } uint8_t job_id = (asic_result.job.id & 0xf0) >> 1; @@ -365,17 +361,17 @@ task_result * BM1370_process_work(void * pvParameters) if (GLOBAL_STATE->valid_jobs[job_id] == 0) { ESP_LOGW(TAG, "Invalid job nonce found, 0x%02X", job_id); - return NULL; + return false; } uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]->version | version_bits; - result.job_id = job_id; - result.nonce = asic_result.job.nonce; - result.rolled_version = rolled_version; - result.asic_nr = asic_nr; + result->job_id = job_id; + result->nonce = asic_result.job.nonce; + result->rolled_version = rolled_version; + result->asic_nr = asic_nr; - return &result; + return true; } void BM1370_read_registers(void) diff --git a/components/asic/bm1397.c b/components/asic/bm1397.c index bcfcebe16..db1e61834 100644 --- a/components/asic/bm1397.c +++ b/components/asic/bm1397.c @@ -77,7 +77,6 @@ typedef struct __attribute__((__packed__)) static const char * TAG = "bm1397"; static uint32_t prev_nonce = 0; -static task_result result; static int address_interval; @@ -294,26 +293,25 @@ void BM1397_send_work(void *pvParameters, bm_job *next_bm_job) _send_BM1397((TYPE_JOB | GROUP_SINGLE | CMD_WRITE), (uint8_t *)&job, sizeof(job_packet), BM1397_DEBUG_WORK); } -task_result *BM1397_process_work(void *pvParameters) +bool BM1397_process_work(void *pvParameters, task_result * result) { - bm1397_asic_result_t asic_result = {0}; + bm1397_asic_result_t asic_result; - memset(&result, 0, sizeof(task_result)); - - if (receive_work((uint8_t *)&asic_result, sizeof(asic_result)) == ESP_FAIL) { - return NULL; + if (receive_work((uint8_t *)&asic_result, sizeof(asic_result), &result->receive_time_us) == ESP_FAIL) { + return false; } if (!asic_result.is_job_response) { - result.register_type = REGISTER_MAP[asic_result.cmd.register_address]; - if (result.register_type == REGISTER_INVALID) { + result->register_type = REGISTER_MAP[asic_result.cmd.register_address]; + if (result->register_type == REGISTER_INVALID) { ESP_LOGW(TAG, "Unknown register read: %02x", asic_result.cmd.register_address); - return NULL; + return false; } - result.asic_nr = asic_result.cmd.asic_address / address_interval; - result.value = ntohl(asic_result.cmd.value); - return &result; + result->asic_nr = asic_result.cmd.asic_address / address_interval; + result->value = ntohl(asic_result.cmd.value); + + return true; } uint8_t nonce_found = 0; @@ -326,7 +324,7 @@ task_result *BM1397_process_work(void *pvParameters) if (GLOBAL_STATE->valid_jobs[rx_job_id] == 0) { ESP_LOGW(TAG, "Invalid job nonce found, id=%d", rx_job_id); - return NULL; + return false; } uint32_t rolled_version = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[rx_job_id]->version; @@ -346,12 +344,12 @@ task_result *BM1397_process_work(void *pvParameters) else if (asic_result.job.nonce == first_nonce) { // stop if we've already seen this nonce - return NULL; + return false; } if (asic_result.job.nonce == prev_nonce) { - return NULL; + return false; } else { @@ -361,17 +359,17 @@ task_result *BM1397_process_work(void *pvParameters) uint32_t nonce_h = ntohl(asic_result.job.nonce); uint8_t asic_nr = (uint8_t)((nonce_h >> 17) & 0xff) / address_interval; - result.job_id = rx_job_id; - result.nonce = asic_result.job.nonce; - result.rolled_version = rolled_version; - result.asic_nr = asic_nr; + result->job_id = rx_job_id; + result->nonce = asic_result.job.nonce; + result->rolled_version = rolled_version; + result->asic_nr = asic_nr; uint8_t core_id = (uint8_t)((nonce_h >> 25) & 0x7f); uint8_t small_core_id = asic_result.job.id & 0x0f; ESP_LOGI(TAG, "Job ID: %02X, Asic nr: %d, Core: %d/%d, Ver: %08" PRIX32, rx_job_id, asic_nr, core_id, small_core_id, rolled_version); - return &result; + return true; } void BM1397_read_registers(void) diff --git a/components/asic/common.c b/components/asic/common.c index f996038a0..b5f3b67dc 100644 --- a/components/asic/common.c +++ b/components/asic/common.c @@ -4,6 +4,7 @@ #include "common.h" #include "serial.h" #include "esp_log.h" +#include "esp_timer.h" #include "crc.h" #define PREAMBLE 0xAA55 @@ -88,10 +89,12 @@ int count_asic_chips(uint16_t asic_count, uint16_t chip_id, int chip_id_response return chip_counter; } -esp_err_t receive_work(uint8_t * buffer, int buffer_size) +esp_err_t receive_work(uint8_t * buffer, int buffer_size, int64_t *result_receive_time_us) { int received = SERIAL_rx(buffer, buffer_size, 10000); + *result_receive_time_us = esp_timer_get_time(); + if (received < 0) { ESP_LOGE(TAG, "UART error in serial RX"); return ESP_FAIL; diff --git a/components/asic/include/asic.h b/components/asic/include/asic.h index b9a454cdd..e9896b66e 100644 --- a/components/asic/include/asic.h +++ b/components/asic/include/asic.h @@ -6,7 +6,7 @@ #include "common.h" uint8_t ASIC_init(GlobalState * GLOBAL_STATE); -task_result * ASIC_process_work(GlobalState * GLOBAL_STATE); +bool ASIC_process_work(GlobalState * GLOBAL_STATE, task_result * result); int ASIC_set_max_baud(GlobalState * GLOBAL_STATE); void ASIC_send_work(GlobalState * GLOBAL_STATE, void * next_job); void ASIC_set_version_mask(GlobalState * GLOBAL_STATE, uint32_t mask); diff --git a/components/asic/include/bm1366.h b/components/asic/include/bm1366.h index 4f37c9746..fb3f70def 100644 --- a/components/asic/include/bm1366.h +++ b/components/asic/include/bm1366.h @@ -27,7 +27,7 @@ void BM1366_set_version_mask(uint32_t version_mask); int BM1366_set_max_baud(void); int BM1366_set_default_baud(void); void BM1366_send_hash_frequency(float frequency); -task_result * BM1366_process_work(void * GLOBAL_STATE); +bool BM1366_process_work(void * GLOBAL_STATE, task_result * result); void BM1366_read_registers(void); #endif /* BM1366_H_ */ diff --git a/components/asic/include/bm1368.h b/components/asic/include/bm1368.h index 1b07cabf1..2a4363314 100644 --- a/components/asic/include/bm1368.h +++ b/components/asic/include/bm1368.h @@ -27,7 +27,7 @@ void BM1368_set_version_mask(uint32_t version_mask); int BM1368_set_max_baud(void); int BM1368_set_default_baud(void); void BM1368_send_hash_frequency(float frequency); -task_result * BM1368_process_work(void * GLOBAL_STATE); +bool BM1368_process_work(void * GLOBAL_STATE, task_result * result); void BM1368_read_registers(void); #endif /* BM1368_H_ */ diff --git a/components/asic/include/bm1370.h b/components/asic/include/bm1370.h index 3b38c9096..8c5943c13 100644 --- a/components/asic/include/bm1370.h +++ b/components/asic/include/bm1370.h @@ -27,7 +27,7 @@ void BM1370_set_version_mask(uint32_t version_mask); int BM1370_set_max_baud(void); int BM1370_set_default_baud(void); void BM1370_send_hash_frequency(float frequency); -task_result * BM1370_process_work(void * GLOBAL_STATE); +bool BM1370_process_work(void * GLOBAL_STATE, task_result * result); void BM1370_read_registers(void); #endif /* BM1370_H_ */ diff --git a/components/asic/include/bm1397.h b/components/asic/include/bm1397.h index 3bfa57bee..208410ba4 100644 --- a/components/asic/include/bm1397.h +++ b/components/asic/include/bm1397.h @@ -29,7 +29,7 @@ void BM1397_set_version_mask(uint32_t version_mask); int BM1397_set_max_baud(void); int BM1397_set_default_baud(void); void BM1397_send_hash_frequency(float frequency); -task_result * BM1397_process_work(void * GLOBAL_STATE); +bool BM1397_process_work(void * GLOBAL_STATE, task_result * result); void BM1397_read_registers(void); #endif /* BM1397_H_ */ diff --git a/components/asic/include/common.h b/components/asic/include/common.h index 61785f85c..7a70613c1 100644 --- a/components/asic/include/common.h +++ b/components/asic/include/common.h @@ -27,6 +27,8 @@ typedef struct register_type_t register_type; uint8_t asic_nr; uint32_t value; + // ---- + int64_t receive_time_us; } task_result; @@ -34,7 +36,7 @@ unsigned char _reverse_bits(unsigned char num); 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); +esp_err_t receive_work(uint8_t * buffer, int buffer_size, int64_t *result_receive_time_us); void get_difficulty_mask(uint16_t difficulty, uint8_t *job_difficulty_mask); #endif /* COMMON_H_ */ diff --git a/components/stratum/include/mining.h b/components/stratum/include/mining.h index 4e8f75524..f5944d72e 100644 --- a/components/stratum/include/mining.h +++ b/components/stratum/include/mining.h @@ -21,6 +21,8 @@ typedef struct uint32_t pool_diff; char *jobid; char *extranonce2; + + const char *user; } bm_job; void free_bm_job(bm_job *job); @@ -30,7 +32,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 uint32_t difficulty, const char * user, 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 f891cf551..94fc7742e 100644 --- a/components/stratum/include/stratum_api.h +++ b/components/stratum/include/stratum_api.h @@ -63,6 +63,7 @@ typedef struct // result bool response_success; char * error_str; + int64_t receive_time_us; } StratumApiV1Message; typedef struct { @@ -79,8 +80,6 @@ int STRATUM_V1_subscribe(int socket, int send_uid, const char * model); void STRATUM_V1_parse(StratumApiV1Message *message, const char *stratum_json); -void STRATUM_V1_stamp_tx(int request_id); - void STRATUM_V1_free_mining_notify(mining_notify *params); int STRATUM_V1_authorize(int socket, int send_uid, const char *username, const char *pass); @@ -93,8 +92,7 @@ int STRATUM_V1_extranonce_subscribe(int socket, int send_uid); int STRATUM_V1_submit_share(int socket, int send_uid, const char *username, const char *job_id, const char *extranonce_2, const uint32_t ntime, const uint32_t nonce, - const uint32_t version_bits); - -double STRATUM_V1_get_response_time_ms(int request_id); + const uint32_t version_bits, + int64_t * result_submit_time_us); -#endif // STRATUM_API_H \ No newline at end of file +#endif // STRATUM_API_H diff --git a/components/stratum/mining.c b/components/stratum/mining.c index 2c80cfae8..42f35d5b7 100644 --- a/components/stratum/mining.c +++ b/components/stratum/mining.c @@ -46,13 +46,14 @@ 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 uint32_t difficulty, const char * user, bm_job *new_job) { new_job->version = params->version; new_job->target = params->target; new_job->ntime = params->ntime; new_job->starting_nonce = 0; new_job->pool_diff = difficulty; + new_job->user = user; reverse_32bit_words(merkle_root, new_job->merkle_root); uint8_t prev_block_hash[32]; diff --git a/components/stratum/stratum_api.c b/components/stratum/stratum_api.c index babdeb260..3b9ad3374 100644 --- a/components/stratum/stratum_api.c +++ b/components/stratum/stratum_api.c @@ -22,56 +22,6 @@ static const char * TAG = "stratum_api"; static char * json_rpc_buffer = NULL; static size_t json_rpc_buffer_size = 0; -static int last_parsed_request_id = -1; - -static RequestTiming request_timings[MAX_REQUEST_IDS]; -static bool initialized = false; - -static void init_request_timings() { - if (!initialized) { - for (int i = 0; i < MAX_REQUEST_IDS; i++) { - request_timings[i].timestamp_us = 0; - request_timings[i].tracking = false; - } - initialized = true; - } -} - -static RequestTiming* get_request_timing(int request_id) { - if (request_id < 0) return NULL; - int index = request_id % MAX_REQUEST_IDS; - return &request_timings[index]; -} - -void STRATUM_V1_stamp_tx(int request_id) -{ - init_request_timings(); - if (request_id >= 1) { - RequestTiming *timing = get_request_timing(request_id); - if (timing) { - timing->timestamp_us = esp_timer_get_time(); - timing->tracking = true; - } - } -} - -double STRATUM_V1_get_response_time_ms(int request_id) -{ - init_request_timings(); - if (request_id < 0) return -1.0; - - RequestTiming *timing = get_request_timing(request_id); - if (!timing || !timing->tracking) { - return -1.0; - } - - double response_time = (esp_timer_get_time() - timing->timestamp_us) / 1000.0; - timing->tracking = false; - return response_time; -} - -static void debug_stratum_tx(const char *); -int _parse_stratum_subscribe_result_message(const char * result_json_str, char ** extranonce, int * extranonce2_len); void STRATUM_V1_initialize_buffer() { @@ -117,9 +67,6 @@ static void realloc_json_buffer(size_t len) char * STRATUM_V1_receive_jsonrpc_line(int sockfd) { - if (json_rpc_buffer == NULL) { - STRATUM_V1_initialize_buffer(); - } char *line, *tok = NULL; char recv_buffer[BUFFER_SIZE]; int nbytes; @@ -164,7 +111,6 @@ void STRATUM_V1_parse(StratumApiV1Message * message, const char * stratum_json) if (id_json != NULL && cJSON_IsNumber(id_json)) { parsed_id = id_json->valueint; } - last_parsed_request_id = parsed_id; message->message_id = parsed_id; cJSON * method_json = cJSON_GetObjectItem(json, "method"); @@ -374,6 +320,21 @@ int _parse_stratum_subscribe_result_message(const char * result_json_str, char * return 0; } +static void debug_stratum_tx(const char * msg, int send_uid) +{ + //remove the trailing newline + char * newline = strchr(msg, '\n'); + if (newline != NULL) { + *newline = '\0'; + } + ESP_LOGI(TAG, "tx: %s", msg); + + //put it back! + if (newline != NULL) { + *newline = '\n'; + } +} + int STRATUM_V1_subscribe(int socket, int send_uid, const char * model) { // Subscribe @@ -381,7 +342,7 @@ int STRATUM_V1_subscribe(int socket, int send_uid, const char * model) const esp_app_desc_t *app_desc = esp_app_get_description(); const char *version = app_desc->version; sprintf(subscribe_msg, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\"bitaxe/%s/%s\"]}\n", send_uid, model, version); - debug_stratum_tx(subscribe_msg); + debug_stratum_tx(subscribe_msg, send_uid); return write(socket, subscribe_msg, strlen(subscribe_msg)); } @@ -390,7 +351,7 @@ int STRATUM_V1_suggest_difficulty(int socket, int send_uid, uint32_t difficulty) { char difficulty_msg[BUFFER_SIZE]; sprintf(difficulty_msg, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%ld]}\n", send_uid, difficulty); - debug_stratum_tx(difficulty_msg); + debug_stratum_tx(difficulty_msg, send_uid); return write(socket, difficulty_msg, strlen(difficulty_msg)); } @@ -399,7 +360,7 @@ int STRATUM_V1_extranonce_subscribe(int socket, int send_uid) { char extranonce_msg[BUFFER_SIZE]; sprintf(extranonce_msg, "{\"id\": %d, \"method\": \"mining.extranonce.subscribe\", \"params\": []}\n", send_uid); - debug_stratum_tx(extranonce_msg); + debug_stratum_tx(extranonce_msg, send_uid); return write(socket, extranonce_msg, strlen(extranonce_msg)); } @@ -409,11 +370,14 @@ int STRATUM_V1_authorize(int socket, int send_uid, const char * username, const char authorize_msg[BUFFER_SIZE]; sprintf(authorize_msg, "{\"id\": %d, \"method\": \"mining.authorize\", \"params\": [\"%s\", \"%s\"]}\n", send_uid, username, pass); - debug_stratum_tx(authorize_msg); + debug_stratum_tx(authorize_msg, send_uid); return write(socket, authorize_msg, strlen(authorize_msg)); } +#define SUBMIT_BUF_SIZE 256 +static char submit_buf[SUBMIT_BUF_SIZE] __attribute__((aligned(4))); + /// @param socket Socket to write to /// @param send_uid Message ID /// @param username The client’s user name. @@ -423,16 +387,21 @@ int STRATUM_V1_authorize(int socket, int send_uid, const char * username, const /// @param nonce The hex-encoded nonce value to use in the block header. /// @param version_bits The hex-encoded version bits set by miner (BIP310). int STRATUM_V1_submit_share(int socket, int send_uid, const char * username, const char * job_id, - const char * extranonce_2, const uint32_t ntime, - const uint32_t nonce, const uint32_t version_bits) + const char * extranonce_2, uint32_t ntime, + uint32_t nonce, uint32_t version_bits, + int64_t * result_submit_time_us) { - char submit_msg[BUFFER_SIZE]; - sprintf(submit_msg, - "{\"id\": %d, \"method\": \"mining.submit\", \"params\": [\"%s\", \"%s\", \"%s\", \"%08lx\", \"%08lx\", \"%08lx\"]}\n", - send_uid, username, job_id, extranonce_2, ntime, nonce, version_bits); - debug_stratum_tx(submit_msg); + int len = snprintf(submit_buf, SUBMIT_BUF_SIZE, + "{\"id\":%d,\"method\":\"mining.submit\",\"params\":[\"%s\",\"%s\",\"%s\",\"%08lx\",\"%08lx\",\"%08lx\"]}\n", + send_uid, username, job_id, extranonce_2, ntime, nonce, version_bits); + + *result_submit_time_us = esp_timer_get_time(); - return write(socket, submit_msg, strlen(submit_msg)); + int result = (len > 0) ? write(socket, submit_buf, len) : -1; + + debug_stratum_tx(submit_buf, send_uid); + + return result; } int STRATUM_V1_configure_version_rolling(int socket, int send_uid, uint32_t * version_mask) @@ -442,23 +411,7 @@ int STRATUM_V1_configure_version_rolling(int socket, int send_uid, uint32_t * ve "{\"id\": %d, \"method\": \"mining.configure\", \"params\": [[\"version-rolling\"], {\"version-rolling.mask\": " "\"ffffffff\"}]}\n", send_uid); - debug_stratum_tx(configure_msg); + debug_stratum_tx(configure_msg, send_uid); return write(socket, configure_msg, strlen(configure_msg)); } - -static void debug_stratum_tx(const char * msg) -{ - STRATUM_V1_stamp_tx(last_parsed_request_id); - //remove the trailing newline - char * newline = strchr(msg, '\n'); - if (newline != NULL) { - *newline = '\0'; - } - ESP_LOGI(TAG, "tx: %s", msg); - - //put it back! - if (newline != NULL) { - *newline = '\n'; - } -} diff --git a/components/stratum/test/test_mining.c b/components/stratum/test/test_mining.c index dbe06f698..07cd108c8 100644 --- a/components/stratum/test/test_mining.c +++ b/components/stratum/test/test_mining.c @@ -94,7 +94,7 @@ TEST_CASE("Validate bm job construction", "[mining]") uint8_t merkle_root[32]; hex2bin("cd1be82132ef0d12053dcece1fa0247fcfdb61d4dbd3eb32ea9ef9b4c604a846", merkle_root, 32); bm_job job = { 0 }; - construct_bm_job(¬ify_message, merkle_root, 0, 1000, &job); + construct_bm_job(¬ify_message, merkle_root, 0, 1000, "user", &job); uint8_t expected_midstate_bin[32]; hex2bin("91DFEA528A9F73683D0D495DD6DD7415E1CA21CB411759E3E05D7D5FF285314D", expected_midstate_bin, 32); @@ -132,7 +132,7 @@ TEST_CASE("Validate version mask incrementing", "[mining]") // char merkle_root[65] // calculate_merkle_root_hash(coinbase_tx, (uint8_t(*)[32])params->merkle_branches, params->n_merkle_branches, merkle_root); // bm_job job = { 0 }; -// construct_bm_job(params, merkle_root, 1000, &job); +// construct_bm_job(params, merkle_root, 1000, "user", &job); // uint8_t expected_midstate_bin[32]; // hex2bin("5FD281AF6A1750EAEE502C04067738BD46C82FC22112FFE797CE7F035D276126", expected_midstate_bin, 32); @@ -180,7 +180,7 @@ TEST_CASE("Test nonce diff checking", "[mining test_nonce][not-on-qemu]") uint8_t merkle_root[32]; hex2bin("6d0359c451434605c52a5a9ce074340be47c2c63840731f9edf1db3f26b1cdd9a9f16f64", merkle_root, 32); bm_job job = { 0 }; - construct_bm_job(¬ify_message, merkle_root, 0, 1000, &job); + construct_bm_job(¬ify_message, merkle_root, 0, 1000, "user", &job); uint32_t nonce = 0x276E8947; double diff = test_nonce_value(&job, nonce, 0); @@ -226,7 +226,7 @@ TEST_CASE("Test nonce diff checking 2", "[mining test_nonce][not-on-qemu]") TEST_ASSERT_EQUAL_STRING("5bdc1968499c3393873edf8e07a1c3a50a97fc3a9d1a376bbf77087dd63778eb", merkle_root); bm_job job = { 0 }; - construct_bm_job(¬ify_message, merkle_root_hash, 0, 1000, &job); + construct_bm_job(¬ify_message, merkle_root_hash, 0, 1000, "user", &job); uint32_t nonce = 0x0a029ed1; double diff = test_nonce_value(&job, nonce, 0); diff --git a/main/global_state.h b/main/global_state.h index 959579ee5..1d929361b 100644 --- a/main/global_state.h +++ b/main/global_state.h @@ -63,7 +63,10 @@ typedef struct uint16_t fallback_pool_difficulty; bool pool_extranonce_subscribe; bool fallback_pool_extranonce_subscribe; - double response_time; + uint32_t share_submit_latency_us; + int last_share_submit_id; + int64_t last_share_submit_time_us; + uint32_t share_response_latency_us; bool use_fallback_stratum; bool is_using_fallback; int pool_addr_family; diff --git a/main/http_server/axe-os/src/app/components/home/home.component.html b/main/http_server/axe-os/src/app/components/home/home.component.html index 8f28cf737..2133afa94 100644 --- a/main/http_server/axe-os/src/app/components/home/home.component.html +++ b/main/http_server/axe-os/src/app/components/home/home.component.html @@ -423,7 +423,7 @@

/>
- {{ info.responseTime }} ms + {{ info.responseTime | number:'1.1-1' }} ms
diff --git a/main/http_server/http_server.c b/main/http_server/http_server.c index 94c7aea9a..7333cd0e2 100644 --- a/main/http_server/http_server.c +++ b/main/http_server/http_server.c @@ -879,7 +879,8 @@ static esp_err_t GET_system_info(httpd_req_t * req) cJSON_AddStringToObject(root, "fallbackStratumUser", fallbackStratumUser); cJSON_AddNumberToObject(root, "fallbackStratumSuggestedDifficulty", nvs_config_get_u16(NVS_CONFIG_FALLBACK_STRATUM_DIFFICULTY)); cJSON_AddNumberToObject(root, "fallbackStratumExtranonceSubscribe", nvs_config_get_bool(NVS_CONFIG_FALLBACK_STRATUM_EXTRANONCE_SUBSCRIBE)); - cJSON_AddNumberToObject(root, "responseTime", GLOBAL_STATE->SYSTEM_MODULE.response_time); + cJSON_AddNumberToObject(root, "responseTime", GLOBAL_STATE->SYSTEM_MODULE.share_response_latency_us / 1000.0); + cJSON_AddNumberToObject(root, "shareSubmitLatency", GLOBAL_STATE->SYSTEM_MODULE.share_submit_latency_us / 1000.0); cJSON_AddStringToObject(root, "version", esp_app_get_description()->version); cJSON_AddStringToObject(root, "axeOSVersion", axeOSVersion); diff --git a/main/self_test/self_test.c b/main/self_test/self_test.c index 724eb35a3..43ba77619 100644 --- a/main/self_test/self_test.c +++ b/main/self_test/self_test.c @@ -396,7 +396,7 @@ bool self_test(void * pvParameters) calculate_merkle_root_hash(coinbase_tx_hash, merkles, num_merkles, merkle_root); bm_job job = {0}; - construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000, &job); + construct_bm_job(¬ify_message, merkle_root, 0x1fffe000, 1000000, "user", &job); ESP_LOGI(TAG, "Sending work"); @@ -409,16 +409,20 @@ bool self_test(void * pvParameters) float hashrate = 0; uint32_t hashtest_ms = 5000; + task_result result; + while (duration_ms < hashtest_ms) { - task_result * asic_result = ASIC_process_work(GLOBAL_STATE); - if (asic_result != NULL) { + + memset(&result, 0, sizeof(result)); + + if (ASIC_process_work(GLOBAL_STATE, &result)) { // check the nonce difficulty - double nonce_diff = test_nonce_value(&job, asic_result->nonce, asic_result->rolled_version); + double nonce_diff = test_nonce_value(&job, result.nonce, result.rolled_version); counter += DIFFICULTY; duration_ms = (esp_timer_get_time() / 1000) - start_ms; hashrate = hashCounterToGhs(duration_ms, counter); - ESP_LOGI(TAG, "Nonce %lu Nonce difficulty %.32f.", asic_result->nonce, nonce_diff); + ESP_LOGI(TAG, "Nonce %lu Nonce difficulty %.32f.", result.nonce, nonce_diff); ESP_LOGI(TAG, "%f Gh/s , duration %dms", hashrate, duration_ms); } } diff --git a/main/tasks/asic_result_task.c b/main/tasks/asic_result_task.c index 17ef449c9..ee10288fe 100644 --- a/main/tasks/asic_result_task.c +++ b/main/tasks/asic_result_task.c @@ -17,6 +17,8 @@ void ASIC_result_task(void *pvParameters) { GlobalState *GLOBAL_STATE = (GlobalState *)pvParameters; + task_result result; + while (1) { // Check if ASIC is initialized before trying to process work @@ -24,21 +26,19 @@ void ASIC_result_task(void *pvParameters) vTaskDelay(100 / portTICK_PERIOD_MS); continue; } - - //task_result *asic_result = (*GLOBAL_STATE->ASIC_functions.receive_result_fn)(GLOBAL_STATE); - task_result *asic_result = ASIC_process_work(GLOBAL_STATE); - if (asic_result == NULL) - { + memset(&result, 0, sizeof(result)); + + if (!ASIC_process_work(GLOBAL_STATE, &result)) { continue; } - if (asic_result->register_type != REGISTER_INVALID) { - hashrate_monitor_register_read(GLOBAL_STATE, asic_result->register_type, asic_result->asic_nr, asic_result->value); + if (result.register_type != REGISTER_INVALID) { + hashrate_monitor_register_read(GLOBAL_STATE, result.register_type, result.asic_nr, result.value); continue; } - uint8_t job_id = asic_result->job_id; + uint8_t job_id = result.job_id; if (GLOBAL_STATE->valid_jobs[job_id] == 0) { @@ -47,31 +47,45 @@ void ASIC_result_task(void *pvParameters) } bm_job *active_job = GLOBAL_STATE->ASIC_TASK_MODULE.active_jobs[job_id]; - // check the nonce difficulty - 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); + // Calculate the actual difficulty of this nonce + double nonce_diff = test_nonce_value(active_job, result.nonce, result.rolled_version); + + // Only submit shares that meet or exceed the pool difficulty + if (nonce_diff >= active_job->pool_diff) { + // Store share ID for response latency tracking + GLOBAL_STATE->SYSTEM_MODULE.last_share_submit_id = GLOBAL_STATE->send_uid; + + int64_t result_submit_time_us; - if (nonce_diff >= active_job->pool_diff) - { - char * user = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_user : GLOBAL_STATE->SYSTEM_MODULE.pool_user; int ret = STRATUM_V1_submit_share( GLOBAL_STATE->sock, GLOBAL_STATE->send_uid++, - user, + active_job->user, active_job->jobid, active_job->extranonce2, active_job->ntime, - asic_result->nonce, - asic_result->rolled_version ^ active_job->version); + result.nonce, + result.rolled_version ^ active_job->version, + &result_submit_time_us); + + // Store submit time in global state for response latency tracking + GLOBAL_STATE->SYSTEM_MODULE.last_share_submit_time_us = result_submit_time_us; + + // Calculate and store submit latency using the same timestamps + uint32_t share_submit_latency_us = result_submit_time_us - result.receive_time_us; + GLOBAL_STATE->SYSTEM_MODULE.share_submit_latency_us = share_submit_latency_us; + ESP_LOGI(TAG, "Share submit latency: %u µs", share_submit_latency_us); if (ret < 0) { ESP_LOGI(TAG, "Unable to write share to socket. Closing connection. Ret: %d (errno %d: %s)", ret, errno, strerror(errno)); stratum_close_connection(GLOBAL_STATE); } } + //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, result.asic_nr, result.rolled_version, result.nonce, nonce_diff, active_job->pool_diff); + SYSTEM_notify_found_nonce(GLOBAL_STATE, nonce_diff, job_id); } } diff --git a/main/tasks/create_jobs_task.c b/main/tasks/create_jobs_task.c index 299925ff0..a9d7e5832 100644 --- a/main/tasks/create_jobs_task.c +++ b/main/tasks/create_jobs_task.c @@ -100,7 +100,9 @@ static void generate_work(GlobalState *GLOBAL_STATE, mining_notify *notification return; } - construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty, queued_next_job); + const char * user = GLOBAL_STATE->SYSTEM_MODULE.is_using_fallback ? GLOBAL_STATE->SYSTEM_MODULE.fallback_pool_user : GLOBAL_STATE->SYSTEM_MODULE.pool_user; + + construct_bm_job(notification, merkle_root, GLOBAL_STATE->version_mask, difficulty, user, queued_next_job); queued_next_job->extranonce2 = strdup(extranonce_2_str); queued_next_job->jobid = strdup(notification->job_id); diff --git a/main/tasks/stratum_task.c b/main/tasks/stratum_task.c index 10ca3297d..6a0bf8acf 100644 --- a/main/tasks/stratum_task.c +++ b/main/tasks/stratum_task.c @@ -461,13 +461,15 @@ void stratum_task(void * pvParameters) int authorize_message_id = GLOBAL_STATE->send_uid++; //mining.authorize - ID: 3 STRATUM_V1_authorize(GLOBAL_STATE->sock, authorize_message_id, username, password); - STRATUM_V1_stamp_tx(authorize_message_id); // Everything is set up, lets make sure we don't abandon work unnecessarily. GLOBAL_STATE->abandon_work = 0; while (1) { char * line = STRATUM_V1_receive_jsonrpc_line(GLOBAL_STATE->sock); + + stratum_api_v1_message.receive_time_us = esp_timer_get_time(); + if (!line) { ESP_LOGE(TAG, "Failed to receive JSON-RPC line, reconnecting..."); retry_attempts++; @@ -475,12 +477,6 @@ void stratum_task(void * pvParameters) break; } - double response_time_ms = STRATUM_V1_get_response_time_ms(stratum_api_v1_message.message_id); - if (response_time_ms >= 0) { - ESP_LOGI(TAG, "Stratum response time: %.2f ms", response_time_ms); - GLOBAL_STATE->SYSTEM_MODULE.response_time = response_time_ms; - } - STRATUM_V1_parse(&stratum_api_v1_message, line); free(line); @@ -524,6 +520,19 @@ void stratum_task(void * pvParameters) stratum_close_connection(GLOBAL_STATE); break; } else if (stratum_api_v1_message.method == STRATUM_RESULT) { + int last_share_id = GLOBAL_STATE->SYSTEM_MODULE.last_share_submit_id; + int64_t last_share_time_us = GLOBAL_STATE->SYSTEM_MODULE.last_share_submit_time_us; + + if (stratum_api_v1_message.message_id == last_share_id && + last_share_id == GLOBAL_STATE->SYSTEM_MODULE.last_share_submit_id && + last_share_time_us > 0) { + + uint32_t share_response_latency_us = stratum_api_v1_message.receive_time_us - last_share_time_us; + GLOBAL_STATE->SYSTEM_MODULE.share_response_latency_us = share_response_latency_us; + + ESP_LOGI(TAG, "Stratum response time: %u µs (%.2f ms)", share_response_latency_us, share_response_latency_us / 1000.0); + } + if (stratum_api_v1_message.response_success) { ESP_LOGI(TAG, "message result accepted"); SYSTEM_notify_accepted_share(GLOBAL_STATE);