diff --git a/src/NerdMinerV2.ino.cpp b/src/NerdMinerV2.ino.cpp index 82d3425..9ccd5a7 100644 --- a/src/NerdMinerV2.ino.cpp +++ b/src/NerdMinerV2.ino.cpp @@ -20,6 +20,8 @@ //3 seconds WDT #define WDT_TIMEOUT 3 +//120 seconds WDT for miner task +#define WDT_MINER_TIMEOUT 120 OneButton button1(PIN_BUTTON_1); OneButton button2(PIN_BUTTON_2); @@ -56,6 +58,7 @@ void setup() Serial.setTimeout(0); delay(100); + esp_task_wdt_init(WDT_MINER_TIMEOUT, true); // Idle task that would reset WDT never runs, because core 0 gets fully utilized disableCore0WDT(); //disableCore1WDT(); @@ -137,8 +140,11 @@ void setup() // Start mining tasks //BaseType_t res = xTaskCreate(runWorker, name, 35000, (void*)name, 1, NULL); - xTaskCreate(runMiner, "Miner0", 15000, NULL, 1, NULL); - xTaskCreate(runMiner, "Miner1", 15000, NULL, 1, NULL); + TaskHandle_t minerTask1, minerTask2 = NULL; + xTaskCreate(runMiner, "Miner0", 15000, (void*)0, 1, &minerTask1); + xTaskCreate(runMiner, "Miner1", 15000, (void*)1, 1, &minerTask2); + esp_task_wdt_add(minerTask1); + esp_task_wdt_add(minerTask2); /******** MONITOR SETUP *****/ setup_monitor(); @@ -164,4 +170,4 @@ void loop() { wifiManagerProcess(); // avoid delays() in loop when non-blocking and other long running code vTaskDelay(50 / portTICK_PERIOD_MS); -} \ No newline at end of file +} diff --git a/src/mining.cpp b/src/mining.cpp index f272b95..dc4e5db 100644 --- a/src/mining.cpp +++ b/src/mining.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include // Graphics and font library for ILI9341 driver chip #include #include "media/Free_Fonts.h" @@ -110,12 +111,14 @@ void runStratumWorker(void *name) { // connect to pool - float currentPoolDifficulty = atof(DEFAULT_DIFFICULTY); + double currentPoolDifficulty = DEFAULT_DIFFICULTY; while(true) { if(WiFi.status() != WL_CONNECTED){ - vTaskDelay(1000 / portTICK_PERIOD_MS); + // WiFi is disconnected, so reconnect now + WiFi.reconnect(); + vTaskDelay(5000 / portTICK_PERIOD_MS); continue; } @@ -210,12 +213,12 @@ void runStratumWorker(void *name) { //This works only with one thread, TODO -> Class or miner_data for each thread -#include "shaTests/jadeSHA256.h" -#include "shaTests/customSHA256.h" -#include "mbedtls/sha256.h" -void runMiner(void * name){ - unsigned long nonce; - unsigned long max_nonce; +//#include "shaTests/jadeSHA256.h" +//#include "shaTests/customSHA256.h" +//#include "mbedtls/sha256.h" +void runMiner(void * task_id) { + + unsigned int miner_id = (uint32_t)task_id; while(1){ @@ -226,16 +229,10 @@ void runMiner(void * name){ } vTaskDelay(10 / portTICK_PERIOD_MS); //Small delay to join both mining threads - if(mMiner.newJob) { + if(mMiner.newJob) mMiner.newJob = false; //Clear newJob flag - nonce = 0; - max_nonce = MAX_NONCE; - } - else if(mMiner.newJob2){ + else if(mMiner.newJob2) mMiner.newJob2 = false; //Clear newJob flag - nonce = TARGET_NONCE - MAX_NONCE; - max_nonce = TARGET_NONCE; - } mMiner.inRun = true; //Set inRun flag //Prepare Premining data @@ -258,11 +255,23 @@ void runMiner(void * name){ Serial.println(""); */ // search a valid nonce + unsigned long nonce = TARGET_NONCE - MAX_NONCE; + // split up odd/even nonces between miner tasks + nonce += miner_id; uint32_t startT = micros(); - unsigned char *header64 = mMiner.bytearray_blockheader + 64; + unsigned char *header64; + // each miner thread needs to track its own blockheader template + memcpy(mMiner.bytearray_blockheader2, &mMiner.bytearray_blockheader, 80); + if (miner_id == 0) + header64 = mMiner.bytearray_blockheader + 64; + else + header64 = mMiner.bytearray_blockheader2 + 64; Serial.println(">>> STARTING TO HASH NONCES"); while(true) { - memcpy(mMiner.bytearray_blockheader + 76, &nonce, 4); + if (miner_id == 0) + memcpy(mMiner.bytearray_blockheader + 76, &nonce, 4); + else + memcpy(mMiner.bytearray_blockheader2 + 76, &nonce, 4); //Con midstate // Primer SHA-256 @@ -283,11 +292,15 @@ void runMiner(void * name){ Serial.println(""); */ hashes++; - if (nonce++> max_nonce) break; //exit + if (nonce > TARGET_NONCE) break; //exit if(!mMiner.inRun) { Serial.println ("MINER WORK ABORTED >> waiting new job"); break;} // check if 16bit share - if(hash[31] !=0 || hash[30] !=0) continue; + if(hash[31] !=0 || hash[30] !=0) { + // increment nonce + nonce += 2; + continue; + } halfshares++; //Check target to submit @@ -304,26 +317,40 @@ void runMiner(void * name){ Serial.print(" - TX SHARE: "); for (size_t i = 0; i < 32; i++) Serial.printf("%02x", hash[i]); - Serial.println(""); + #ifdef DEBUG_MINING + Serial.println(""); + Serial.print(" - Current nonce: "); Serial.println(nonce); + Serial.print(" - Current block header: "); + for (size_t i = 0; i < 80; i++) { + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); + } + #endif + Serial.println(""); mLastTXtoPool = millis(); } // check if 32bit share - if(hash[29] !=0 || hash[28] !=0) continue; + if(hash[29] !=0 || hash[28] !=0) { + // increment nonce + nonce += 2; + continue; + } shares++; // check if valid header if(checkValid(hash, mMiner.bytearray_target)){ - Serial.printf("[WORKER] %s CONGRATULATIONS! Valid completed with nonce: %d | 0x%x\n", (char *)name, nonce, nonce); + Serial.printf("[WORKER] %d CONGRATULATIONS! Valid block found with nonce: %d | 0x%x\n", miner_id, nonce, nonce); valids++; - Serial.printf("[WORKER] %s Submiting work valid!\n", (char *)name); + Serial.printf("[WORKER] %d Submitted work valid!\n", miner_id); // STEP 3: Submit mining job tx_mining_submit(client, mWorker, mJob, nonce); client.stop(); // exit nonce = MAX_NONCE; break; - } + } + // increment nonce + nonce += 2; } // exit if found a valid result or nonce > MAX_NONCE wc_Sha256Free(&sha256); @@ -338,6 +365,8 @@ void runMiner(void * name){ } uint32_t duration = micros() - startT; + if (esp_task_wdt_reset() == ESP_OK) + Serial.print(">>> Resetting watchdog timer"); } } diff --git a/src/mining.h b/src/mining.h index 742b3e6..4cb28f5 100644 --- a/src/mining.h +++ b/src/mining.h @@ -5,7 +5,7 @@ // Mining #define MAX_NONCE 5000000U #define TARGET_NONCE 471136297U -#define DEFAULT_DIFFICULTY "1e-9" +#define DEFAULT_DIFFICULTY 1e-4 #define KEEPALIVE_TIME_ms 30000 #define POOLINACTIVITY_TIME_ms 60000 @@ -21,7 +21,8 @@ typedef struct{ uint8_t bytearray_pooltarget[32]; uint8_t merkle_result[32]; uint8_t bytearray_blockheader[80]; - float poolDifficulty; + uint8_t bytearray_blockheader2[80]; + double poolDifficulty; bool inRun; bool newJob; bool newJob2; diff --git a/src/stratum.cpp b/src/stratum.cpp index dacaaaf..4970656 100644 --- a/src/stratum.cpp +++ b/src/stratum.cpp @@ -176,15 +176,15 @@ bool parse_mining_notify(String line, mining_job& mJob) mJob.clean_jobs = doc["params"][8]; //bool #ifdef DEBUG_MINING - Serial.print(" job_id: "); Serial.println(job_id); - Serial.print(" prevhash: "); Serial.println(prev_block_hash); - Serial.print(" coinb1: "); Serial.println(coinb1); - Serial.print(" coinb2: "); Serial.println(coinb2); - Serial.print(" merkle_branch size: "); Serial.println(merkle_branches.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); + Serial.print(" job_id: "); Serial.println(mJob.job_id); + Serial.print(" prevhash: "); Serial.println(mJob.prev_block_hash); + Serial.print(" coinb1: "); Serial.println(mJob.coinb1); + Serial.print(" coinb2: "); Serial.println(mJob.coinb2); + Serial.print(" merkle_branch size: "); Serial.println(mJob.merkle_branch.size()); + Serial.print(" version: "); Serial.println(mJob.version); + Serial.print(" nbits: "); Serial.println(mJob.nbits); + Serial.print(" ntime: "); Serial.println(mJob.ntime); + Serial.print(" clean_jobs: "); Serial.println(mJob.clean_jobs); #endif //Check if parameters where correctly received if (checkError(doc)) { @@ -216,7 +216,7 @@ bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job m return true; } -bool parse_mining_set_difficulty(String line, float& difficulty) +bool parse_mining_set_difficulty(String line, double& difficulty) { Serial.println(" Parsing Method [SET DIFFICULTY]"); if(!verifyPayload(&line)) return false; @@ -226,22 +226,18 @@ bool parse_mining_set_difficulty(String line, float& difficulty) if (error) return false; if (!doc.containsKey("params")) return false; - Serial.print(" difficulty: "); Serial.println((float)doc["params"][0],12); - difficulty = (float)doc["params"][0]; - - #ifdef DEBUG_MINING - Serial.print(" job_id: "); Serial.println(job_id); - #endif + Serial.print(" difficulty: "); Serial.println((double)doc["params"][0],12); + difficulty = (double)doc["params"][0]; return true; } -bool tx_suggest_difficulty(WiFiClient& client, const char * difficulty) +bool tx_suggest_difficulty(WiFiClient& client, double difficulty) { char payload[BUFFER] = {0}; id = getNextId(id); - sprintf(payload, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%s]}\n", id, difficulty); + sprintf(payload, "{\"id\": %d, \"method\": \"mining.suggest_difficulty\", \"params\": [%.10g]}\n", id, difficulty); Serial.print(" Sending : "); Serial.print(payload); return client.print(payload); diff --git a/src/stratum.h b/src/stratum.h index cdd47b3..44f65de 100644 --- a/src/stratum.h +++ b/src/stratum.h @@ -62,8 +62,8 @@ bool parse_mining_notify(String line, mining_job& mJob); bool tx_mining_submit(WiFiClient& client, mining_subscribe mWorker, mining_job mJob, unsigned long nonce); //Difficulty Methods -bool tx_suggest_difficulty(WiFiClient& client, const char * difficulty); -bool parse_mining_set_difficulty(String line, float& difficulty); +bool tx_suggest_difficulty(WiFiClient& client, double difficulty); +bool parse_mining_set_difficulty(String line, double& difficulty); #endif // STRATUM_API_H \ No newline at end of file diff --git a/src/utils.cpp b/src/utils.cpp index 3050dc8..8216ef7 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -83,16 +83,16 @@ double le256todouble(const void *target) double dcut64; data64 = (uint64_t *)(target + 24); - dcut64 = bswap64(*data64) * 6277101735386680763835789423207666416102355444464034512896.0; + dcut64 = *data64 * 6277101735386680763835789423207666416102355444464034512896.0; data64 = (uint64_t *)(target + 16); - dcut64 += bswap64(*data64) * 340282366920938463463374607431768211456.0; + dcut64 += *data64 * 340282366920938463463374607431768211456.0; data64 = (uint64_t *)(target + 8); - dcut64 += bswap64(*data64) * 18446744073709551616.0; + dcut64 += *data64 * 18446744073709551616.0; data64 = (uint64_t *)(target); - dcut64 += bswap64(*data64); + dcut64 += *data64; return dcut64; } @@ -100,7 +100,6 @@ double le256todouble(const void *target) double diff_from_target(void *target) { double d64, dcut64; - //reverse_bytes((uint8_t *) target, 32); d64 = truediffone; dcut64 = le256todouble(target); @@ -155,7 +154,7 @@ miner_data init_miner_data(void){ miner_data newMinerData; - newMinerData.poolDifficulty = atof(DEFAULT_DIFFICULTY); + newMinerData.poolDifficulty = DEFAULT_DIFFICULTY; newMinerData.inRun = false; newMinerData.newJob = false; @@ -201,7 +200,7 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ size_t res = to_byte_array(coinbase.c_str(), str_len*2, bytearray); #ifdef DEBUG_MINING - Serial.print(" extranonce2: "); Serial.println(extranonce2); + Serial.print(" extranonce2: "); Serial.println(mWorker.extranonce2); Serial.print(" coinbase: "); Serial.println(coinbase); Serial.print(" coinbase bytes - size: "); Serial.println(res); for (size_t i = 0; i < res; i++) @@ -271,7 +270,7 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ #ifdef DEBUG_MINING Serial.print(" merkle sha : "); for (size_t i = 0; i < 32; i++) - Serial.printf("%02x", merkle_result[i]); + Serial.printf("%02x", mMiner.merkle_result[i]); Serial.println(""); #endif } @@ -285,22 +284,23 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ } merkle_root[65] = 0; Serial.println(""); - + // calculate blockheader // j.block_header = ''.join([j.version, j.prevhash, merkle_root, j.ntime, j.nbits]) - String blockheader = mJob.version + mJob.prev_block_hash + String(merkle_root) + mJob.ntime + mJob.nbits + "00000000"; + String blockheader = mJob.version + mJob.prev_block_hash + String(merkle_root) + mJob.ntime + mJob.nbits + "00000000"; str_len = blockheader.length()/2; //uint8_t bytearray_blockheader[str_len]; res = to_byte_array(blockheader.c_str(), str_len*2, mMiner.bytearray_blockheader); #ifdef DEBUG_MINING + Serial.println(" blockheader: "); Serial.print(blockheader); Serial.println(" blockheader bytes "); Serial.print(str_len); Serial.print(" -> "); #endif // reverse version uint8_t buff; - size_t bsize, boffset; + size_t bword, bsize, boffset; boffset = 0; bsize = 4; for (size_t j = boffset; j < boffset + (bsize/2); j++) { @@ -309,14 +309,42 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; } - // reverse merkle - boffset = 36; + // reverse prev hash (4-byte word swap) + boffset = 4; + bword = 4; bsize = 32; + for (size_t i = 1; i <= bsize / bword; i++) { + for (size_t j = boffset; j < boffset + bword / 2; j++) { + buff = mMiner.bytearray_blockheader[j]; + mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bword - 1 - j]; + mMiner.bytearray_blockheader[2 * boffset + bword - 1 - j] = buff; + } + boffset += bword; + } + +/* + // reverse merkle (4-byte word swap) + boffset = 36; + bword = 4; + bsize = 32; + for (size_t i = 1; i <= bsize / bword; i++) { + for (size_t j = boffset; j < boffset + bword / 2; j++) { + buff = mMiner.bytearray_blockheader[j]; + mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bword - 1 - j]; + mMiner.bytearray_blockheader[2 * boffset + bword - 1 - j] = buff; + } + boffset += bword; + } +*/ + // reverse ntime + boffset = 68; + bsize = 4; for (size_t j = boffset; j < boffset + (bsize/2); j++) { buff = mMiner.bytearray_blockheader[j]; mMiner.bytearray_blockheader[j] = mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j]; mMiner.bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; } + // reverse difficulty boffset = 72; bsize = 4; @@ -330,35 +358,35 @@ miner_data calculateMiningData(mining_subscribe& mWorker, mining_job mJob){ #ifdef DEBUG_MINING Serial.print(" >>> bytearray_blockheader : "); for (size_t i = 0; i < 4; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.print("version "); for (size_t i = 0; i < 4; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.print("prev hash "); for (size_t i = 4; i < 4+32; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.print("merkle root "); for (size_t i = 36; i < 36+32; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); + Serial.println(""); + Serial.print("ntime "); + for (size_t i = 68; i < 68+4; i++) + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.print("nbits "); - for (size_t i = 68; i < 68+4; i++) - Serial.printf("%02x", bytearray_blockheader[i]); - Serial.println(""); - Serial.print("difficulty "); for (size_t i = 72; i < 72+4; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.print("nonce "); for (size_t i = 76; i < 76+4; i++) - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); Serial.println(""); Serial.println("bytearray_blockheader: "); for (size_t i = 0; i < str_len; i++) { - Serial.printf("%02x", bytearray_blockheader[i]); + Serial.printf("%02x", mMiner.bytearray_blockheader[i]); } Serial.println(""); #endif