mirror of
https://github.com/skot/ESP-Miner.git
synced 2025-04-10 04:49:16 +02:00
stratum_api: cleanup notify parsing
Split parsing into two steps, one for the method and one for the params themselves. Currently it is up to the miner task to grab the parameters in the format it needs.
This commit is contained in:
parent
abf914648f
commit
812e4213c1
@ -10,20 +10,18 @@
|
||||
#define COINBASE2_SIZE 128
|
||||
|
||||
typedef struct {
|
||||
uint32_t job_id;
|
||||
uint8_t prev_block_hash[HASH_SIZE];
|
||||
uint8_t coinbase_1[COINBASE_SIZE];
|
||||
size_t coinbase_1_len;
|
||||
uint8_t coinbase_2[COINBASE2_SIZE];
|
||||
size_t coinbase_2_len;
|
||||
uint8_t merkle_branches[MAX_MERKLE_BRANCHES][HASH_SIZE];
|
||||
char * job_id;
|
||||
char * prev_block_hash;
|
||||
char * coinbase_1;
|
||||
char * coinbase_2;
|
||||
uint8_t * merkle_branches;
|
||||
size_t n_merkle_branches;
|
||||
uint32_t version;
|
||||
uint32_t curtime;
|
||||
uint32_t bits;
|
||||
uint32_t target;
|
||||
uint32_t nonce;
|
||||
} work;
|
||||
} mining_notify;
|
||||
|
||||
typedef enum {
|
||||
STRATUM_UNKNOWN,
|
||||
@ -31,23 +29,17 @@ typedef enum {
|
||||
MINING_SET_DIFFICULTY
|
||||
} stratum_method;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
stratum_method method;
|
||||
char * method_str;
|
||||
union {
|
||||
work notify_work;
|
||||
uint32_t notify_difficulty;
|
||||
};
|
||||
} stratum_message;
|
||||
|
||||
void initialize_stratum_buffer();
|
||||
|
||||
char * receive_jsonrpc_line(int sockfd);
|
||||
|
||||
int subscribe_to_stratum(int socket, char ** extranonce, int * extranonce2_len);
|
||||
|
||||
stratum_message parse_stratum_notify_message(const char * stratum_json);
|
||||
stratum_method parse_stratum_method(const char * stratum_json);
|
||||
|
||||
mining_notify parse_mining_notify_message(const char * stratum_json);
|
||||
|
||||
void free_mining_notify(mining_notify params);
|
||||
|
||||
int parse_stratum_subscribe_result_message(const char * result_json_str,
|
||||
char ** extranonce,
|
||||
|
@ -17,13 +17,13 @@ static int send_uid = 1;
|
||||
|
||||
void initialize_stratum_buffer()
|
||||
{
|
||||
json_rpc_buffer = malloc(BUFFER_SIZE); // Allocate memory dynamically
|
||||
json_rpc_buffer = malloc(BUFFER_SIZE);
|
||||
json_rpc_buffer_size = BUFFER_SIZE;
|
||||
memset(json_rpc_buffer, 0, BUFFER_SIZE);
|
||||
if (json_rpc_buffer == NULL)
|
||||
{
|
||||
printf("Error: Failed to allocate memory for buffer\n");
|
||||
exit(1); // Handle error case
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,7 @@ static void realloc_json_buffer(size_t len)
|
||||
json_rpc_buffer = new_sockbuf;
|
||||
memset(json_rpc_buffer + old, 0, new - old);
|
||||
json_rpc_buffer_size = new;
|
||||
ESP_LOGI(TAG, "Current json rpc buffer size: %d", json_rpc_buffer_size);
|
||||
}
|
||||
|
||||
char * receive_jsonrpc_line(int sockfd)
|
||||
@ -96,58 +97,59 @@ char * receive_jsonrpc_line(int sockfd)
|
||||
return line;
|
||||
}
|
||||
|
||||
work parse_notify_work(cJSON * params) {
|
||||
work new_work;
|
||||
new_work.job_id = (uint32_t) strtoul(cJSON_GetArrayItem(params, 0)->valuestring, NULL, 16);
|
||||
hex2bin(cJSON_GetArrayItem(params, 1)->valuestring, new_work.prev_block_hash, PREV_BLOCK_HASH_SIZE * 2);
|
||||
stratum_method parse_stratum_method(const char * stratum_json)
|
||||
{
|
||||
cJSON * json = cJSON_Parse(stratum_json);
|
||||
cJSON * method_json = cJSON_GetObjectItem(json, "method");
|
||||
stratum_method result = STRATUM_UNKNOWN;
|
||||
if (method_json != NULL && cJSON_IsString(method_json)) {
|
||||
if (strcmp("mining.notify", method_json->valuestring) == 0) {
|
||||
result = MINING_NOTIFY;
|
||||
} else if (strcmp("mining.set_difficulty", method_json->valuestring) == 0) {
|
||||
result = MINING_SET_DIFFICULTY;
|
||||
}
|
||||
}
|
||||
|
||||
char *coinb1 = cJSON_GetArrayItem(params, 2)->valuestring;
|
||||
char *coinb2 = cJSON_GetArrayItem(params, 3)->valuestring;
|
||||
hex2bin(coinb1, new_work.coinbase_1, strlen(coinb1) / 2);
|
||||
new_work.coinbase_1_len = strlen(coinb1) / 2;
|
||||
hex2bin(coinb2, new_work.coinbase_2, strlen(coinb2) / 2);
|
||||
new_work.coinbase_2_len = strlen(coinb2) / 2;
|
||||
cJSON_Delete(json);
|
||||
return result;
|
||||
}
|
||||
|
||||
cJSON *merkle_branch = cJSON_GetArrayItem(params, 4);
|
||||
mining_notify parse_mining_notify_message(const char * stratum_json)
|
||||
{
|
||||
cJSON * json = cJSON_Parse(stratum_json);
|
||||
cJSON * method = cJSON_GetObjectItem(json, "method");
|
||||
if (method != NULL && cJSON_IsString(method)) {
|
||||
assert(strcmp("mining.notify", method->valuestring) == 0);
|
||||
}
|
||||
|
||||
mining_notify new_work;
|
||||
cJSON * params = cJSON_GetObjectItem(json, "params");
|
||||
new_work.job_id = strdup(cJSON_GetArrayItem(params, 0)->valuestring);
|
||||
new_work.prev_block_hash = strdup(cJSON_GetArrayItem(params, 1)->valuestring);
|
||||
new_work.coinbase_1 = strdup(cJSON_GetArrayItem(params, 2)->valuestring);
|
||||
new_work.coinbase_2 = strdup(cJSON_GetArrayItem(params, 3)->valuestring);
|
||||
|
||||
cJSON * merkle_branch = cJSON_GetArrayItem(params, 4);
|
||||
new_work.n_merkle_branches = cJSON_GetArraySize(merkle_branch);
|
||||
if (new_work.n_merkle_branches > MAX_MERKLE_BRANCHES) {
|
||||
printf("Too many Merkle branches.\n");
|
||||
abort();
|
||||
}
|
||||
new_work.merkle_branches = malloc(HASH_SIZE * new_work.n_merkle_branches);
|
||||
for (size_t i = 0; i < new_work.n_merkle_branches; i++) {
|
||||
hex2bin(cJSON_GetArrayItem(merkle_branch, i)->valuestring, new_work.merkle_branches[i], PREV_BLOCK_HASH_SIZE * 2);
|
||||
}
|
||||
|
||||
return new_work;
|
||||
}
|
||||
|
||||
stratum_message parse_stratum_notify_message(const char * stratum_json)
|
||||
{
|
||||
stratum_message output;
|
||||
output.method = STRATUM_UNKNOWN;
|
||||
cJSON *json = cJSON_Parse(stratum_json);
|
||||
|
||||
cJSON *id = cJSON_GetObjectItem(json, "id");
|
||||
cJSON *method = cJSON_GetObjectItem(json, "method");
|
||||
|
||||
if (id != NULL && cJSON_IsNumber(id)) {
|
||||
output.id = id->valueint;
|
||||
}
|
||||
|
||||
if (method != NULL && cJSON_IsString(method)) {
|
||||
output.method_str = strdup(method->valuestring);
|
||||
if (strcmp("mining.notify", method->valuestring) == 0) {
|
||||
output.method = MINING_NOTIFY;
|
||||
output.notify_work = parse_notify_work(cJSON_GetObjectItem(json, "params"));
|
||||
} else if (strcmp("mining.set_difficulty", method->valuestring) == 0) {
|
||||
output.method = MINING_SET_DIFFICULTY;
|
||||
} else {
|
||||
output.method = STRATUM_UNKNOWN;
|
||||
}
|
||||
hex2bin(cJSON_GetArrayItem(merkle_branch, i)->valuestring, new_work.merkle_branches + HASH_SIZE * i, HASH_SIZE * 2);
|
||||
}
|
||||
|
||||
cJSON_Delete(json);
|
||||
return output;
|
||||
return new_work;
|
||||
}
|
||||
|
||||
void free_mining_notify(mining_notify params)
|
||||
{
|
||||
free(params.prev_block_hash);
|
||||
free(params.coinbase_1);
|
||||
free(params.coinbase_2);
|
||||
free(params.merkle_branches);
|
||||
}
|
||||
|
||||
int parse_stratum_subscribe_result_message(const char * result_json_str,
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "unity.h"
|
||||
#include "stratum_api.h"
|
||||
|
||||
TEST_CASE("Check can parse json", "[mining.notify]")
|
||||
TEST_CASE("Parse stratum method", "[mining.notify]")
|
||||
{
|
||||
const char * json_string = "{\"id\":null,\"method\":\"mining.notify\",\"params\":"
|
||||
"[\"1b4c3d9041\","
|
||||
@ -10,8 +10,24 @@ TEST_CASE("Check can parse json", "[mining.notify]")
|
||||
"\"41903d4c1b2f736c7573682f0000000003ca890d27000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3a4cb4cb2ddfc37c41baf5ef6b6b4899e3253a8f1dfc7e5dd68a5b5b27005014ef0000000000000000266a24aa21a9ed5caa249f1af9fbf71c986fea8e076ca34ae3514fb2f86400561b28c7b15949bf00000000\","
|
||||
"[\"ae23055e00f0f697cc3640124812d96d4fe8bdfa03484c1c638ce5a1c0e9aa81\",\"980fb87cb61021dd7afd314fcb0dabd096f3d56a7377f6f320684652e7410a21\",\"a52e9868343c55ce405be8971ff340f562ae9ab6353f07140d01666180e19b52\",\"7435bdfa004e603953b2ed39f118803934d9cf17b06d979ceb682f2251bafac2\",\"2a91f061a22d27cb8f44eea79938fb241ebeb359891aa907f05ffde7ed44e52e\",\"302401f80eb5e958155135e25200bb8ea181ad2d05e804a531c7314d86403cdc\",\"318ecb6161eb9b4cfd802bd730e2d36c167ddf102e70aa7b4158e2870dd47392\",\"1114332a9858e0cf84b2425bb1e59eaabf91dd102d114aa443d57fc1b3beb0c9\",\"f43f38095c810613ed795a44d9fab02ff25269706f454885db9be05cdf9c06e1\",\"3e2fc26b27fddc39668b59099cd9635761bb72ed92404204e12bdff08b16fb75\",\"463c19427286342120039a83218fa87ce45448e246895abac11fff0036076758\",\"03d287f655813e540ddb9c4e7aeb922478662b0f5d8e9d0cbd564b20146bab76\"],"
|
||||
"\"20000004\",\"1705c739\",\"64495522\",false]}";
|
||||
stratum_message message = parse_stratum_notify_message(json_string);
|
||||
TEST_ASSERT_EQUAL(MINING_NOTIFY, message.method);
|
||||
stratum_method method = parse_stratum_method(json_string);
|
||||
TEST_ASSERT_EQUAL(MINING_NOTIFY, method);
|
||||
}
|
||||
|
||||
TEST_CASE("Parse stratum notify params", "[mining.notify]")
|
||||
{
|
||||
const char * json_string = "{\"id\":null,\"method\":\"mining.notify\",\"params\":"
|
||||
"[\"1d2e0c4d3d\","
|
||||
"\"ef4b9a48c7986466de4adc002f7337a6e121bc43000376ea0000000000000000\","
|
||||
"\"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03a5020cfabe6d6d379ae882651f6469f2ed6b8b40a4f9a4b41fd838a3ad6de8cba775f4e8f1d3080100000000000000\","
|
||||
"\"41903d4c1b2f736c7573682f0000000003ca890d27000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3a4cb4cb2ddfc37c41baf5ef6b6b4899e3253a8f1dfc7e5dd68a5b5b27005014ef0000000000000000266a24aa21a9ed5caa249f1af9fbf71c986fea8e076ca34ae3514fb2f86400561b28c7b15949bf00000000\","
|
||||
"[\"ae23055e00f0f697cc3640124812d96d4fe8bdfa03484c1c638ce5a1c0e9aa81\",\"980fb87cb61021dd7afd314fcb0dabd096f3d56a7377f6f320684652e7410a21\",\"a52e9868343c55ce405be8971ff340f562ae9ab6353f07140d01666180e19b52\",\"7435bdfa004e603953b2ed39f118803934d9cf17b06d979ceb682f2251bafac2\",\"2a91f061a22d27cb8f44eea79938fb241ebeb359891aa907f05ffde7ed44e52e\",\"302401f80eb5e958155135e25200bb8ea181ad2d05e804a531c7314d86403cdc\",\"318ecb6161eb9b4cfd802bd730e2d36c167ddf102e70aa7b4158e2870dd47392\",\"1114332a9858e0cf84b2425bb1e59eaabf91dd102d114aa443d57fc1b3beb0c9\",\"f43f38095c810613ed795a44d9fab02ff25269706f454885db9be05cdf9c06e1\",\"3e2fc26b27fddc39668b59099cd9635761bb72ed92404204e12bdff08b16fb75\",\"463c19427286342120039a83218fa87ce45448e246895abac11fff0036076758\",\"03d287f655813e540ddb9c4e7aeb922478662b0f5d8e9d0cbd564b20146bab76\"],"
|
||||
"\"20000004\",\"1705c739\",\"64495522\",false]}";
|
||||
mining_notify params = parse_mining_notify_message(json_string);
|
||||
TEST_ASSERT_EQUAL_STRING("1d2e0c4d3d", params.job_id);
|
||||
TEST_ASSERT_EQUAL_STRING("ef4b9a48c7986466de4adc002f7337a6e121bc43000376ea0000000000000000", params.prev_block_hash);
|
||||
TEST_ASSERT_EQUAL_STRING("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4b03a5020cfabe6d6d379ae882651f6469f2ed6b8b40a4f9a4b41fd838a3ad6de8cba775f4e8f1d3080100000000000000", params.coinbase_1);
|
||||
TEST_ASSERT_EQUAL_STRING("41903d4c1b2f736c7573682f0000000003ca890d27000000001976a9147c154ed1dc59609e3d26abb2df2ea3d587cd8c4188ac00000000000000002c6a4c2952534b424c4f434b3a4cb4cb2ddfc37c41baf5ef6b6b4899e3253a8f1dfc7e5dd68a5b5b27005014ef0000000000000000266a24aa21a9ed5caa249f1af9fbf71c986fea8e076ca34ae3514fb2f86400561b28c7b15949bf00000000", params.coinbase_2);
|
||||
}
|
||||
|
||||
TEST_CASE("Test mining.subcribe result parsing", "[mining.subscribe]")
|
||||
|
57
main/miner.c
57
main/miner.c
@ -14,6 +14,7 @@
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "stratum_api.h"
|
||||
#include "mining.h"
|
||||
#include "work_queue.h"
|
||||
|
||||
#include "system.h"
|
||||
@ -39,15 +40,39 @@ TaskHandle_t serialTaskHandle = NULL;
|
||||
|
||||
static work_queue g_queue;
|
||||
|
||||
static char * extranonce_str = NULL;
|
||||
static int extranonce_2_len = 0;
|
||||
|
||||
static void mining_task(void *pvParameters)
|
||||
{
|
||||
int termination_flag = 0;
|
||||
while(true) {
|
||||
work next_work = queue_dequeue(&g_queue, &termination_flag);
|
||||
uint32_t free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "miner heap free size: %u bytes", free_heap_size);
|
||||
char * next_notify_json_str = queue_dequeue(&g_queue, &termination_flag);
|
||||
ESP_LOGI(TAG, "New Work Dequeued");
|
||||
// TODO: dequeue work from work_queue
|
||||
ESP_LOGI(TAG, "Notify json: %s", next_notify_json_str);
|
||||
|
||||
mining_notify params = parse_mining_notify_message(next_notify_json_str);
|
||||
|
||||
char * coinbase_tx = construct_coinbase_tx(params.coinbase_1, params.coinbase_2,
|
||||
extranonce_str, extranonce_2_len);
|
||||
ESP_LOGI(TAG, "Coinbase tx: %s", coinbase_tx);
|
||||
|
||||
char * merkle_root = calculate_merkle_root_hash(coinbase_tx,
|
||||
(uint8_t(*)[32]) params.merkle_branches,
|
||||
params.n_merkle_branches);
|
||||
ESP_LOGI(TAG, "Merkle root: %s", merkle_root);
|
||||
|
||||
free_mining_notify(params);
|
||||
free(coinbase_tx);
|
||||
free(merkle_root);
|
||||
vPortFree(next_notify_json_str);
|
||||
|
||||
|
||||
free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "miner heap free size: %u bytes", free_heap_size);
|
||||
|
||||
// TODO: Construct the coinbase transaction and compute the merkle root
|
||||
// TODO: Prepare the block header and start mining
|
||||
|
||||
// TODO: Increment the nonce
|
||||
@ -108,26 +133,24 @@ static void admin_task(void *pvParameters)
|
||||
|
||||
auth_to_stratum(sock, STRATUM_USERNAME);
|
||||
|
||||
char * extranonce_str;
|
||||
int extranonce_2_len;
|
||||
|
||||
subscribe_to_stratum(sock, &extranonce_str, &extranonce_2_len);
|
||||
ESP_LOGI(TAG, "Extranonce: %s", extranonce_str);
|
||||
ESP_LOGI(TAG, "Extranonce 2 length: %d", extranonce_2_len);
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *line = receive_jsonrpc_line(sock);
|
||||
// Error occurred during receiving
|
||||
ESP_LOGI(TAG, "Json: %s", line);
|
||||
stratum_message parsed_message = parse_stratum_notify_message(line);
|
||||
if (parsed_message.method == STRATUM_UNKNOWN) {
|
||||
ESP_LOGI(TAG, "UNKNOWN MESSAGE");
|
||||
uint32_t free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "before receive heap free size: %u bytes", free_heap_size);
|
||||
char * line = receive_jsonrpc_line(sock);
|
||||
free_heap_size = esp_get_free_heap_size();
|
||||
ESP_LOGI(TAG, "after receive heap free size: %u bytes", free_heap_size);
|
||||
|
||||
stratum_method method = parse_stratum_method(line);
|
||||
if (method == MINING_NOTIFY) {
|
||||
queue_enqueue(&g_queue, line);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "method: %s", parsed_message.method_str);
|
||||
if (parsed_message.method == MINING_NOTIFY) {
|
||||
queue_enqueue(&g_queue, parsed_message.notify_work);
|
||||
}
|
||||
vPortFree(line);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
if (sock != -1)
|
||||
|
@ -9,7 +9,7 @@ void queue_init(work_queue *queue) {
|
||||
pthread_cond_init(&queue->not_full, NULL);
|
||||
}
|
||||
|
||||
void queue_enqueue(work_queue *queue, work new_work) {
|
||||
void queue_enqueue(work_queue *queue, char * new_work) {
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
|
||||
while (queue->count == QUEUE_SIZE) {
|
||||
@ -24,19 +24,18 @@ void queue_enqueue(work_queue *queue, work new_work) {
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
work queue_dequeue(work_queue *queue, int *termination_flag) {
|
||||
char * queue_dequeue(work_queue *queue, int *termination_flag) {
|
||||
pthread_mutex_lock(&queue->lock);
|
||||
|
||||
while (queue->count == 0) {
|
||||
if (*termination_flag) {
|
||||
pthread_mutex_unlock(&queue->lock);
|
||||
work empty_work = { 0 };
|
||||
return empty_work;
|
||||
return NULL;
|
||||
}
|
||||
pthread_cond_wait(&queue->not_empty, &queue->lock);
|
||||
}
|
||||
|
||||
work next_work = queue->buffer[queue->head];
|
||||
char * next_work = queue->buffer[queue->head];
|
||||
queue->head = (queue->head + 1) % QUEUE_SIZE;
|
||||
queue->count--;
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
#include <pthread.h>
|
||||
#include "stratum_api.h"
|
||||
|
||||
#define QUEUE_SIZE 10
|
||||
#define QUEUE_SIZE 3
|
||||
|
||||
typedef struct {
|
||||
work buffer[QUEUE_SIZE];
|
||||
char * buffer[QUEUE_SIZE];
|
||||
int head;
|
||||
int tail;
|
||||
int count;
|
||||
@ -17,7 +17,7 @@ typedef struct {
|
||||
} work_queue;
|
||||
|
||||
void queue_init(work_queue *queue);
|
||||
void queue_enqueue(work_queue *queue, work new_work);
|
||||
work queue_dequeue(work_queue *queue, int *termination_flag);
|
||||
void queue_enqueue(work_queue *queue, char * new_work);
|
||||
char * queue_dequeue(work_queue *queue, int *termination_flag);
|
||||
|
||||
#endif // WORK_QUEUE_H
|
Loading…
x
Reference in New Issue
Block a user