2023-03-20 01:10:44 +01:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include <ArduinoJson.h>
|
|
|
|
#include <WiFi.h>
|
2023-04-17 02:07:18 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
|
2023-04-07 00:43:20 +02:00
|
|
|
#include "media/Free_Fonts.h"
|
|
|
|
#include "media/images.h"
|
2023-03-20 01:10:44 +01:00
|
|
|
#include "mbedtls/md.h"
|
2023-05-01 22:26:01 +02:00
|
|
|
#include "mbedtls/sha256.h"
|
2023-03-20 01:10:44 +01:00
|
|
|
#include "OpenFontRender.h"
|
|
|
|
#include "mining.h"
|
|
|
|
|
2023-04-17 02:07:18 +02:00
|
|
|
#define TARGET_BUFFER_SIZE 64
|
2023-05-07 13:21:00 +02:00
|
|
|
#define BUFFER_JSON_DOC 4096
|
2023-04-17 02:07:18 +02:00
|
|
|
|
|
|
|
unsigned long templates = 0;
|
|
|
|
unsigned long hashes= 0;
|
|
|
|
unsigned long Mhashes = 0;
|
2023-05-07 13:21:00 +02:00
|
|
|
unsigned long totalKHashes = 0;
|
|
|
|
unsigned long mStart = millis();
|
2023-04-15 23:56:13 +02:00
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
int halfshares; // increase if blockhash has 16 bits of zeroes
|
|
|
|
int shares; // increase if blockhash has 32 bits of zeroes
|
|
|
|
int valids; // increased if blockhash <= target
|
2023-05-01 22:26:01 +02:00
|
|
|
bool enableGlobalHash = false;
|
2023-03-20 01:10:44 +01:00
|
|
|
|
|
|
|
// Variables to hold data from custom textboxes
|
|
|
|
extern char poolString[80];
|
|
|
|
extern int portNumber;
|
|
|
|
extern char btcString[80];
|
|
|
|
|
|
|
|
extern OpenFontRender render;
|
|
|
|
extern TFT_eSprite background;
|
|
|
|
|
2023-05-03 21:11:59 +02:00
|
|
|
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
bool checkValid(unsigned char* hash, unsigned char* target) {
|
|
|
|
bool valid = true;
|
|
|
|
for(uint8_t i=31; i>=0; i--) {
|
|
|
|
if(hash[i] > target[i]) {
|
|
|
|
valid = false;
|
|
|
|
break;
|
|
|
|
} else if (hash[i] < target[i]) {
|
|
|
|
valid = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-05-03 21:11:59 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-03-20 01:10:44 +01:00
|
|
|
if (valid) {
|
|
|
|
Serial.print("\tvalid : ");
|
|
|
|
for (size_t i = 0; i < 32; i++)
|
|
|
|
Serial.printf("%02x ", hash[i]);
|
|
|
|
Serial.println();
|
|
|
|
}
|
2023-04-17 15:04:42 +02:00
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
return valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t hex(char ch) {
|
|
|
|
uint8_t r = (ch > 57) ? (ch - 55) : (ch - 48);
|
|
|
|
return r & 0x0F;
|
|
|
|
}
|
|
|
|
|
|
|
|
int to_byte_array(const char *in, size_t in_size, uint8_t *out) {
|
|
|
|
int count = 0;
|
|
|
|
if (in_size % 2) {
|
|
|
|
while (*in && out) {
|
|
|
|
*out = hex(*in++);
|
|
|
|
if (!*in)
|
|
|
|
return count;
|
|
|
|
*out = (*out << 4) | hex(*in++);
|
|
|
|
*out++;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
} else {
|
|
|
|
while (*in && out) {
|
|
|
|
*out++ = (hex(*in++) << 4) | hex(*in++);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
}
|
2023-05-01 22:26:01 +02:00
|
|
|
|
2023-05-04 17:05:24 +02:00
|
|
|
bool verifyPayload (String* line){
|
|
|
|
if(line->length() == 0) return false;
|
|
|
|
line->trim();
|
|
|
|
if(line->isEmpty()) return false;
|
2023-05-01 22:26:01 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
unsigned long getNextId(unsigned long id) {
|
|
|
|
if (id == ULONG_MAX) {
|
|
|
|
id = 1;
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
return ++id;
|
|
|
|
}
|
|
|
|
|
|
|
|
void getNextExtranonce2(int extranonce2_size, char *extranonce2) {
|
|
|
|
|
|
|
|
unsigned long extranonce2_number = strtoul(extranonce2, NULL, 10);
|
|
|
|
extranonce2_number++;
|
|
|
|
|
|
|
|
memset(extranonce2, '0', 2 * extranonce2_size);
|
|
|
|
if (extranonce2_number > long(pow(10, 2 * extranonce2_size))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char next_extranounce2[2 * extranonce2_size + 1];
|
|
|
|
memset(extranonce2, '0', 2 * extranonce2_size);
|
|
|
|
ultoa(extranonce2_number, next_extranounce2, 10);
|
|
|
|
memcpy(extranonce2 + (2 * extranonce2_size) - long(log10(extranonce2_number)) - 1 , next_extranounce2, strlen(next_extranounce2));
|
|
|
|
extranonce2[2 * extranonce2_size] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool verifyPayload (String* line){
|
|
|
|
if(line->length() == 0) return false;
|
|
|
|
line->trim();
|
|
|
|
if(line->isEmpty()) return false;
|
2023-05-01 22:26:01 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
bool checkError(const StaticJsonDocument<BUFFER_JSON_DOC> doc) {
|
|
|
|
if (doc["error"].size() == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Serial.printf("ERROR: %d | reason: %s \n", (const int) doc["error"][0], (const char*) doc["error"][1]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
void runWorker(void *name) {
|
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
// TEST: https://bitcoin.stackexchange.com/questions/22929/full-example-data-for-scrypt-stratum-client
|
2023-04-17 02:07:18 +02:00
|
|
|
|
|
|
|
Serial.println("");
|
|
|
|
Serial.printf("\n[WORKER] Started. Running %s on core %d\n", (char *)name, xPortGetCoreID());
|
2023-05-07 13:21:00 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_MEMORY
|
2023-05-01 22:26:01 +02:00
|
|
|
Serial.printf("### [Total Heap / Free heap]: %d / %d \n", ESP.getHeapSize(), ESP.getFreeHeap());
|
2023-05-07 13:21:00 +02:00
|
|
|
#endif
|
2023-04-17 02:07:18 +02:00
|
|
|
|
|
|
|
// connect to pool
|
|
|
|
WiFiClient client;
|
2023-05-07 13:21:00 +02:00
|
|
|
IPAddress serverIP; //Temporally save poolIPaddres
|
|
|
|
bool isMinerSuscribed = false;
|
2023-04-17 02:07:18 +02:00
|
|
|
bool continueSecuence = false;
|
2023-05-07 13:21:00 +02:00
|
|
|
String line, extranonce1, extranonce2 = String("0");
|
|
|
|
unsigned long id = 0, extranonce_number = 0;
|
2023-04-17 02:07:18 +02:00
|
|
|
unsigned int extranonce2_size;
|
|
|
|
|
|
|
|
while(true) {
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
if(WiFi.status() != WL_CONNECTED){
|
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
continue;
|
|
|
|
}
|
2023-03-20 01:10:44 +01:00
|
|
|
|
|
|
|
// get template
|
2023-05-07 13:21:00 +02:00
|
|
|
StaticJsonDocument<BUFFER_JSON_DOC> doc;
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
char payload[BUFFER_JSON_DOC] = {0};
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
if (!client.connected()) {
|
|
|
|
isMinerSuscribed = false;
|
|
|
|
Serial.println("Client not connected, trying to connect...");
|
|
|
|
if (!client.connect(serverIP, portNumber)) {
|
|
|
|
Serial.println("Imposible to connect to : " + String(poolString));
|
|
|
|
WiFi.hostByName(poolString, serverIP);
|
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// STEP 1: Pool server connection (SUBSCRIBE)
|
|
|
|
// Docs:
|
|
|
|
// - https://cs.braiins.com/stratum-v1/docs
|
|
|
|
// - https://github.com/aeternity/protocol/blob/master/STRATUM.md#mining-subscribe
|
|
|
|
if(!isMinerSuscribed){
|
|
|
|
id = getNextId(id);
|
|
|
|
sprintf(payload, "{\"id\": %u, \"method\": \"mining.subscribe\", \"params\": [\"NerdMinerV2\"]}\n", id);
|
|
|
|
Serial.printf("[WORKER] %s ==> Mining subscribe\n", (char *)name);
|
|
|
|
Serial.print(" Sending : "); Serial.println(payload);
|
|
|
|
client.print(payload);
|
|
|
|
line = client.readStringUntil('\n');
|
|
|
|
if(!verifyPayload(&line)) continue;
|
|
|
|
Serial.print(" Receiving: "); Serial.println(line);
|
|
|
|
deserializeJson(doc, line);
|
|
|
|
if (checkError(doc)) {
|
|
|
|
Serial.printf("[WORKER] %s >>>>>>>>> Work aborted\n", (char *)name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
String sub_details = String((const char*) doc["result"][0][0][1]);
|
|
|
|
extranonce1 = String((const char*) doc["result"][1]);
|
|
|
|
int extranonce2_size = doc["result"][2];
|
|
|
|
|
|
|
|
// DIFFICULTY
|
|
|
|
line = client.readStringUntil('\n');
|
|
|
|
Serial.print(" Receiving: "); Serial.println(line);
|
|
|
|
Serial.print(" sub_details: "); Serial.println(sub_details);
|
|
|
|
Serial.print(" extranonce1: "); Serial.println(extranonce1);
|
|
|
|
Serial.print(" extranonce2_size: "); Serial.println(extranonce2_size);
|
|
|
|
|
|
|
|
if((extranonce1.length() == 0) || line.length() == 0) {
|
|
|
|
Serial.printf("[WORKER] %s >>>>>>>>> Work aborted\n", (char *)name);
|
|
|
|
Serial.printf("extranonce1 length: %u | line2 length: %u \n", extranonce1.length(), line.length());
|
|
|
|
client.stop();
|
|
|
|
doc.clear();
|
|
|
|
doc.garbageCollect();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
isMinerSuscribed=true;
|
2023-04-17 02:07:18 +02:00
|
|
|
}
|
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
// STEP 2: Pool authorize work (Block Info)
|
|
|
|
id = getNextId(id);
|
|
|
|
sprintf(payload, "{\"params\": [\"%s\", \"x\"], \"id\": %u, \"method\": \"mining.authorize\"}\n",
|
|
|
|
btcString,
|
|
|
|
id);
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.printf("[WORKER] %s ==> Autorize work\n", (char *)name);
|
|
|
|
Serial.print(" Sending : "); Serial.println(payload);
|
2023-05-07 13:21:00 +02:00
|
|
|
client.print(payload);
|
2023-04-17 02:07:18 +02:00
|
|
|
line = client.readStringUntil('\n');
|
2023-05-07 13:21:00 +02:00
|
|
|
if(!verifyPayload(&line)) continue;
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.print(" Receiving: "); Serial.println(line);
|
2023-05-03 21:11:59 +02:00
|
|
|
Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n'));
|
|
|
|
Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n'));
|
2023-05-07 13:21:00 +02:00
|
|
|
// client.stop();
|
|
|
|
|
2023-05-03 21:11:59 +02:00
|
|
|
deserializeJson(doc, line);
|
|
|
|
String job_id = String((const char*) doc["params"][0]);
|
|
|
|
String prevhash = String((const char*) doc["params"][1]);
|
|
|
|
String coinb1 = String((const char*) doc["params"][2]);
|
|
|
|
String coinb2 = String((const char*) doc["params"][3]);
|
|
|
|
JsonArray merkle_branch = doc["params"][4];
|
|
|
|
String version = String((const char*) doc["params"][5]);
|
|
|
|
String nbits = String((const char*) doc["params"][6]);
|
|
|
|
String ntime = String((const char*) doc["params"][7]);
|
|
|
|
bool clean_jobs = doc["params"][8]; //bool
|
|
|
|
|
2023-04-15 23:56:13 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.print(" job_id: "); Serial.println(job_id);
|
|
|
|
Serial.print(" prevhash: "); Serial.println(prevhash);
|
|
|
|
Serial.print(" coinb1: "); Serial.println(coinb1);
|
|
|
|
Serial.print(" coinb2: "); Serial.println(coinb2);
|
|
|
|
Serial.print(" merkle_branch size: "); Serial.println(merkle_branch.size());
|
|
|
|
Serial.print(" version: "); Serial.println(version);
|
|
|
|
Serial.print(" nbits: "); Serial.println(nbits);
|
|
|
|
Serial.print(" ntime: "); Serial.println(ntime);
|
|
|
|
Serial.print(" clean_jobs: "); Serial.println(clean_jobs);
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-04-17 23:24:42 +02:00
|
|
|
//Check if parameters where correctly received
|
2023-05-07 13:21:00 +02:00
|
|
|
if (checkError(doc)) {
|
|
|
|
Serial.printf("[WORKER] %s >>>>>>>>> Work aborted\n", (char *)name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-04-17 02:07:18 +02:00
|
|
|
templates++;
|
2023-03-20 01:10:44 +01:00
|
|
|
|
|
|
|
// calculate target - target = (nbits[2:]+'00'*(int(nbits[:2],16) - 3)).zfill(64)
|
2023-04-17 02:07:18 +02:00
|
|
|
|
|
|
|
char target[TARGET_BUFFER_SIZE+1];
|
|
|
|
memset(target, '0', TARGET_BUFFER_SIZE);
|
2023-03-20 01:10:44 +01:00
|
|
|
int zeros = (int) strtol(nbits.substring(0, 2).c_str(), 0, 16) - 3;
|
2023-04-17 02:07:18 +02:00
|
|
|
memcpy(target + zeros - 2, nbits.substring(2).c_str(), nbits.length() - 2);
|
2023-05-07 13:21:00 +02:00
|
|
|
target[TARGET_BUFFER_SIZE] = 0;
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.print(" target: "); Serial.println(target);
|
2023-03-20 01:10:44 +01:00
|
|
|
// bytearray target
|
|
|
|
uint8_t bytearray_target[32];
|
2023-04-17 02:07:18 +02:00
|
|
|
size_t size_target = to_byte_array(target, 32, bytearray_target);
|
|
|
|
// uint8_t buf;
|
|
|
|
// for (size_t j = 0; j < 16; j++) {
|
|
|
|
// buf = bytearray_target[j];
|
|
|
|
// bytearray_target[j] = bytearray_target[size_target - 1 - j];
|
|
|
|
// bytearray_target[size_target - 1 - j] = buf;
|
|
|
|
// }
|
|
|
|
for (size_t j = 0; j < 8; j++) {
|
|
|
|
bytearray_target[j] ^= bytearray_target[size_target - 1 - j];
|
|
|
|
bytearray_target[size_target - 1 - j] ^= bytearray_target[j];
|
|
|
|
bytearray_target[j] ^= bytearray_target[size_target - 1 - j];
|
2023-03-20 01:10:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// get extranonce2 - extranonce2 = hex(random.randint(0,2**32-1))[2:].zfill(2*extranonce2_size)
|
2023-05-07 13:21:00 +02:00
|
|
|
char extranonce2_char[2 * extranonce2_size+1];
|
|
|
|
extranonce2.toCharArray(extranonce2_char, 2 * extranonce2_size + 1);
|
|
|
|
getNextExtranonce2(extranonce2_size, extranonce2_char);
|
|
|
|
//extranonce2 = String(extranonce2_char);
|
|
|
|
extranonce2 = "00000002";
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
//get coinbase - coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
|
|
|
|
String coinbase = coinb1 + extranonce1 + extranonce2 + coinb2;
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print(" coinbase: "); Serial.println(coinbase);
|
2023-03-20 01:10:44 +01:00
|
|
|
size_t str_len = coinbase.length()/2;
|
|
|
|
uint8_t bytearray[str_len];
|
|
|
|
|
|
|
|
size_t res = to_byte_array(coinbase.c_str(), str_len*2, bytearray);
|
|
|
|
|
2023-04-15 23:56:13 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.print(" extranonce2: "); Serial.println(extranonce2);
|
|
|
|
Serial.print(" coinbase: "); Serial.println(coinbase);
|
|
|
|
Serial.print(" coinbase bytes - size: "); Serial.println(res);
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < res; i++)
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.printf("%02x", bytearray[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("---");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_context ctx;
|
|
|
|
mbedtls_sha256_init(&ctx);
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
byte interResult[32]; // 256 bit
|
|
|
|
byte shaResult[32]; // 256 bit
|
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_starts_ret(&ctx,0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, bytearray, str_len);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, interResult);
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_starts_ret(&ctx,0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, interResult, 32);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, shaResult);
|
|
|
|
mbedtls_sha256_free(&ctx);
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-04-15 23:56:13 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.print(" coinbase double sha: ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < 32; i++)
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.printf("%02x", shaResult[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
|
|
|
|
byte merkle_result[32];
|
|
|
|
// copy coinbase hash
|
2023-04-17 02:07:18 +02:00
|
|
|
memcpy(merkle_result, shaResult, sizeof(shaResult));
|
2023-03-20 01:10:44 +01:00
|
|
|
|
|
|
|
byte merkle_concatenated[32 * 2];
|
2023-05-07 13:21:00 +02:00
|
|
|
for (size_t k=0; k < merkle_branch.size(); k++) {
|
2023-03-20 01:10:44 +01:00
|
|
|
const char* merkle_element = (const char*) merkle_branch[k];
|
|
|
|
uint8_t bytearray[32];
|
|
|
|
size_t res = to_byte_array(merkle_element, 64, bytearray);
|
|
|
|
|
2023-04-17 15:04:42 +02:00
|
|
|
#ifdef DEBUG_MINING
|
|
|
|
Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element);
|
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < 32; i++) {
|
|
|
|
merkle_concatenated[i] = merkle_result[i];
|
|
|
|
merkle_concatenated[32 + i] = bytearray[i];
|
|
|
|
}
|
2023-04-15 23:56:13 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element);
|
|
|
|
Serial.print(" merkle concatenated: ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < 64; i++)
|
|
|
|
Serial.printf("%02x", merkle_concatenated[i]);
|
|
|
|
Serial.println("");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_context ctx;
|
|
|
|
mbedtls_sha256_init(&ctx);
|
|
|
|
mbedtls_sha256_starts_ret(&ctx,0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, merkle_concatenated, 64);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, interResult);
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_starts_ret(&ctx,0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, interResult, 32);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, merkle_result);
|
|
|
|
mbedtls_sha256_free(&ctx);
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-04-15 23:56:13 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.print(" merkle sha : ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < 32; i++)
|
|
|
|
Serial.printf("%02x", merkle_result[i]);
|
|
|
|
Serial.println("");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
}
|
|
|
|
// merkle root from merkle_result
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.print(" merkle sha : ");
|
2023-04-17 02:07:18 +02:00
|
|
|
char merkle_root[65];
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
Serial.printf("%02x", merkle_result[i]);
|
|
|
|
snprintf(&merkle_root[i*2], 3, "%02x", merkle_result[i]);
|
|
|
|
}
|
|
|
|
merkle_root[65] = 0;
|
|
|
|
Serial.println("");
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
// calculate blockheader
|
2023-05-07 13:21:00 +02:00
|
|
|
// j.block_header = ''.join([j.version, j.prevhash, merkle_root, j.ntime, j.nbits])
|
|
|
|
String blockheader = version + prevhash + String(merkle_root) + ntime + nbits + "00000000";
|
2023-03-20 01:10:44 +01:00
|
|
|
str_len = blockheader.length()/2;
|
|
|
|
uint8_t bytearray_blockheader[str_len];
|
|
|
|
res = to_byte_array(blockheader.c_str(), str_len*2, bytearray_blockheader);
|
2023-04-15 23:56:13 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.println(" blockheader bytes "); Serial.print(str_len); Serial.print(" -> ");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
// reverse version
|
|
|
|
uint8_t buff;
|
|
|
|
size_t bsize, boffset;
|
|
|
|
boffset = 0;
|
|
|
|
bsize = 4;
|
|
|
|
for (size_t j = boffset; j < boffset + (bsize/2); j++) {
|
|
|
|
buff = bytearray_blockheader[j];
|
|
|
|
bytearray_blockheader[j] = bytearray_blockheader[2 * boffset + bsize - 1 - j];
|
|
|
|
bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff;
|
|
|
|
}
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
// reverse merkle
|
|
|
|
boffset = 36;
|
|
|
|
bsize = 32;
|
|
|
|
for (size_t j = boffset; j < boffset + (bsize/2); j++) {
|
|
|
|
buff = bytearray_blockheader[j];
|
|
|
|
bytearray_blockheader[j] = bytearray_blockheader[2 * boffset + bsize - 1 - j];
|
|
|
|
bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff;
|
|
|
|
}
|
|
|
|
// reverse difficulty
|
|
|
|
boffset = 72;
|
|
|
|
bsize = 4;
|
|
|
|
for (size_t j = boffset; j < boffset + (bsize/2); j++) {
|
|
|
|
buff = bytearray_blockheader[j];
|
|
|
|
bytearray_blockheader[j] = bytearray_blockheader[2 * boffset + bsize - 1 - j];
|
|
|
|
bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff;
|
|
|
|
}
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-04-17 15:04:42 +02:00
|
|
|
|
2023-04-15 23:56:13 +02:00
|
|
|
#ifdef DEBUG_MINING
|
2023-04-17 02:07:18 +02:00
|
|
|
Serial.print(" >>> bytearray_blockheader : ");
|
|
|
|
for (size_t i = 0; i < 4; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("version ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 0; i < 4; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("prev hash ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 4; i < 4+32; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("merkle root ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 36; i < 36+32; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("nbits ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 68; i < 68+4; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("difficulty ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 72; i < 72+4; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.print("nonce ");
|
2023-03-20 01:10:44 +01:00
|
|
|
for (size_t i = 76; i < 76+4; i++)
|
2023-04-17 15:04:42 +02:00
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
2023-03-20 01:10:44 +01:00
|
|
|
Serial.println("");
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.println("bytearray_blockheader: ");
|
|
|
|
for (size_t i = 0; i < str_len; i++) {
|
|
|
|
Serial.printf("%02x", bytearray_blockheader[i]);
|
|
|
|
}
|
|
|
|
Serial.println("");
|
2023-04-15 23:56:13 +02:00
|
|
|
#endif
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_context midstate[32];
|
|
|
|
unsigned char hash[32];
|
|
|
|
|
|
|
|
//Calcular midstate
|
|
|
|
mbedtls_sha256_init(midstate);
|
|
|
|
mbedtls_sha256_starts_ret(midstate, 0);
|
|
|
|
mbedtls_sha256_update_ret(midstate, bytearray_blockheader, 64);
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
// search a valid nonce
|
2023-05-01 22:26:01 +02:00
|
|
|
enableGlobalHash = true;
|
2023-05-07 13:21:00 +02:00
|
|
|
|
|
|
|
unsigned long nonce = TARGET_NONCE - MAX_NONCE;
|
2023-03-20 01:10:44 +01:00
|
|
|
uint32_t startT = micros();
|
2023-05-01 22:26:01 +02:00
|
|
|
unsigned char *header64 = bytearray_blockheader + 64;
|
2023-04-15 23:56:13 +02:00
|
|
|
Serial.println(">>> STARTING TO HASH NONCES");
|
2023-03-20 01:10:44 +01:00
|
|
|
while(true) {
|
2023-05-01 22:26:01 +02:00
|
|
|
memcpy(bytearray_blockheader + 77, &nonce, 3);
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
//Con midstate
|
|
|
|
// Primer SHA-256
|
|
|
|
mbedtls_sha256_clone(&ctx, midstate); //Clonamos el contexto anterior para continuar el SHA desde allí
|
|
|
|
mbedtls_sha256_update_ret(&ctx, header64, 16);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, hash);
|
|
|
|
|
|
|
|
// Segundo SHA-256
|
|
|
|
mbedtls_sha256_starts_ret(&ctx, 0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, hash, 32);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, hash);
|
|
|
|
/*for (size_t i = 0; i < 32; i++)
|
|
|
|
Serial.printf("%02x", hash[i]);
|
|
|
|
Serial.println(""); */
|
2023-04-17 15:04:42 +02:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
hashes++;
|
2023-05-07 13:21:00 +02:00
|
|
|
if (nonce++> TARGET_NONCE) break; //exit
|
2023-05-01 22:26:01 +02:00
|
|
|
|
|
|
|
// check if 16bit share
|
2023-05-07 13:21:00 +02:00
|
|
|
if(hash[31] !=0 || hash[30] !=0) continue;
|
2023-05-01 22:26:01 +02:00
|
|
|
halfshares++;
|
|
|
|
// check if 32bit share
|
2023-05-07 13:21:00 +02:00
|
|
|
if(hash[29] !=0 || hash[28] !=0) continue;
|
2023-05-01 22:26:01 +02:00
|
|
|
shares++;
|
|
|
|
|
|
|
|
// check if valid header
|
|
|
|
if(checkValid(hash, bytearray_target)){
|
2023-05-07 13:21:00 +02:00
|
|
|
Serial.printf("[WORKER] %s CONGRATULATIONS! Valid completed with nonce: %d | 0x%x\n", (char *)name, nonce, nonce);
|
|
|
|
valids++;
|
|
|
|
Serial.printf("[WORKER] %s Submiting work valid!\n", (char *)name);
|
|
|
|
while (!client.connected()) {
|
|
|
|
client.connect(poolString, portNumber);
|
|
|
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
|
|
}
|
|
|
|
// STEP 3: Submit mining job
|
|
|
|
id = getNextId(id);
|
|
|
|
sprintf(payload, "{\"params\": [\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"], \"id\": %u, \"method\": \"mining.submit\"}",
|
|
|
|
btcString,
|
|
|
|
job_id,
|
|
|
|
extranonce2,
|
|
|
|
ntime,
|
|
|
|
String(nonce, HEX),
|
|
|
|
id
|
|
|
|
);
|
|
|
|
Serial.print(" Sending : "); Serial.println(payload);
|
|
|
|
client.print(payload);
|
|
|
|
Serial.print(" Receiving: "); Serial.println(client.readString());
|
|
|
|
client.stop();
|
|
|
|
// exit
|
|
|
|
nonce = MAX_NONCE;
|
|
|
|
break;
|
2023-05-01 22:26:01 +02:00
|
|
|
}
|
2023-03-20 01:10:44 +01:00
|
|
|
} // exit if found a valid result or nonce > MAX_NONCE
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
mbedtls_sha256_free(&ctx);
|
|
|
|
mbedtls_sha256_free(midstate);
|
|
|
|
enableGlobalHash = false;
|
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
// TODO Pending doub
|
2023-05-01 22:26:01 +02:00
|
|
|
if(hashes>=MAX_NONCE) { Mhashes=Mhashes+MAX_NONCE/1000000; hashes=hashes-MAX_NONCE;}
|
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
uint32_t duration = micros() - startT;
|
|
|
|
}
|
2023-05-01 22:26:01 +02:00
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////THREAD CALLS///////////////////
|
2023-05-03 21:11:59 +02:00
|
|
|
|
2023-05-01 22:26:01 +02:00
|
|
|
//Testeamos hashrate final usando hilo principal
|
|
|
|
//this is currently on test
|
|
|
|
|
2023-05-03 21:11:59 +02:00
|
|
|
void runMiner(void){
|
2023-05-01 22:26:01 +02:00
|
|
|
uint32_t nonce=0;
|
|
|
|
unsigned char bytearray_blockheader[80];
|
|
|
|
|
|
|
|
if(!enableGlobalHash) return;
|
|
|
|
|
|
|
|
mbedtls_sha256_context midstate[32], ctx;
|
|
|
|
unsigned char hash[32];
|
|
|
|
|
|
|
|
//Calcular midstate
|
|
|
|
mbedtls_sha256_init(midstate);
|
|
|
|
mbedtls_sha256_starts_ret(midstate, 0);
|
|
|
|
mbedtls_sha256_update_ret(midstate, bytearray_blockheader, 64);
|
|
|
|
|
|
|
|
//Iteraciones
|
|
|
|
unsigned char *header64 = bytearray_blockheader + 64;
|
|
|
|
|
2023-05-03 21:11:59 +02:00
|
|
|
for(nonce = 0; nonce < 10000; nonce++){
|
2023-05-01 22:26:01 +02:00
|
|
|
memcpy(bytearray_blockheader + 77, &nonce, 3);
|
|
|
|
mbedtls_sha256_clone(&ctx, midstate); //Clonamos el contexto anterior para continuar el SHA desde allí
|
|
|
|
mbedtls_sha256_update_ret(&ctx, header64, 16);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, hash);
|
|
|
|
|
|
|
|
// Segundo SHA-256
|
|
|
|
mbedtls_sha256_starts_ret(&ctx, 0);
|
|
|
|
mbedtls_sha256_update_ret(&ctx, hash, 32);
|
|
|
|
mbedtls_sha256_finish_ret(&ctx, hash);
|
|
|
|
|
|
|
|
hashes++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mbedtls_sha256_free(&ctx);
|
|
|
|
mbedtls_sha256_free(midstate);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-05-03 21:11:59 +02:00
|
|
|
void runMonitor(void *name){
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
// Serial.println("[MONITOR] started");
|
2023-03-20 01:10:44 +01:00
|
|
|
|
2023-05-07 13:21:00 +02:00
|
|
|
|
|
|
|
//while(1){
|
2023-03-20 01:10:44 +01:00
|
|
|
background.pushImage(0, 0, MinerWidth, MinerHeight, MinerScreen);
|
|
|
|
|
|
|
|
unsigned long mElapsed = millis()-mStart;
|
2023-05-07 13:21:00 +02:00
|
|
|
unsigned long totalKHashes = (Mhashes*1000) + hashes/1000 - totalKHashes;
|
2023-04-17 02:07:18 +02:00
|
|
|
//Serial.println("[runMonitor Task] -> Printing results on screen ");
|
2023-05-07 13:21:00 +02:00
|
|
|
|
|
|
|
// Serial.printf(">>> Completed %d share(s), %d Khashes, avg. hashrate %.3f KH/s\n",
|
|
|
|
// shares, totalKHashes, (1.0*(totalKHashes*1000))/mElapsed);
|
2023-04-17 02:07:18 +02:00
|
|
|
|
2023-03-20 01:10:44 +01:00
|
|
|
//Hashrate
|
|
|
|
render.setFontSize(70);
|
|
|
|
render.setCursor(19, 118);
|
|
|
|
render.setFontColor(TFT_BLACK);
|
|
|
|
char tmp[10] = {0};
|
2023-04-17 02:07:18 +02:00
|
|
|
sprintf(tmp, "%.2f", (1.0*(totalKHashes*1000))/mElapsed);
|
2023-03-20 01:10:44 +01:00
|
|
|
render.rdrawString(tmp, 118, 114, TFT_BLACK);
|
|
|
|
//Total hashes
|
|
|
|
render.setFontSize(36);
|
2023-04-17 02:07:18 +02:00
|
|
|
render.rdrawString(String(Mhashes).c_str(), 268, 138, TFT_BLACK);
|
2023-03-20 01:10:44 +01:00
|
|
|
//Block templates
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.drawString(String(templates).c_str(), 186, 17, 0xDEDB);
|
|
|
|
//16Bit shares
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.drawString(String(halfshares).c_str(), 186, 45, 0xDEDB);
|
|
|
|
//32Bit shares
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.drawString(String(shares).c_str(), 186, 73, 0xDEDB);
|
|
|
|
//Hores
|
|
|
|
unsigned long secElapsed=mElapsed/1000;
|
|
|
|
int hr = secElapsed/3600; //Number of seconds in an hour
|
|
|
|
int mins = (secElapsed-(hr*3600))/60; //Remove the number of hours and calculate the minutes.
|
|
|
|
int sec = secElapsed-(hr*3600)-(mins*60);
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.rdrawString(String(hr).c_str(), 208, 99, 0xDEDB);
|
|
|
|
//Minutss
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.rdrawString(String(mins).c_str(), 253, 99, 0xDEDB);
|
|
|
|
//Segons
|
|
|
|
render.setFontSize(36);
|
|
|
|
render.rdrawString(String(sec).c_str(), 298, 99, 0xDEDB);
|
|
|
|
//Valid Blocks
|
|
|
|
render.setFontSize(48);
|
|
|
|
render.drawString(String(valids).c_str(), 281, 55, 0xDEDB);
|
|
|
|
|
|
|
|
//Push prepared background to screen
|
|
|
|
background.pushSprite(0,0);
|
|
|
|
|
|
|
|
// Pause the task for 5000ms
|
2023-05-07 13:21:00 +02:00
|
|
|
// vTaskDelay(5000 / portTICK_PERIOD_MS);
|
|
|
|
//}
|
2023-03-20 01:10:44 +01:00
|
|
|
}
|