Merge branch 'master' of https://github.com/alcar21/NerdMiner_v2 into feature/add_platformio_support_and_improvements

# Conflicts:
#	.gitignore
#	Lib/Free_Fonts.h
#	Lib/images.h
#	Lib/myFonts.h
#	NerdMinerV2.ino
#	README.md
#	TFT_setup/User_Setup.h
#	lib/TFT_eSPI/User_Setup.h
#	platformio.ini
#	src/Lib/Free_Fonts.h
#	src/Lib/images.h
#	src/Lib/myFonts.h
#	src/NerdMinerV2.ino
#	src/NerdMinerV2.ino.cpp
#	src/TFT_setup/User_Setup.h
#	src/media/Free_Fonts.h
#	src/media/images.h
#	src/media/myFonts.h
#	src/mining.cpp
#	src/mining.h
#	src/wManager.h
This commit is contained in:
Alfonso C. Alvarez 2023-04-17 15:04:42 +02:00
commit cf0e667668
13 changed files with 210 additions and 72 deletions

6
.gitignore vendored
View File

@ -1,6 +1,2 @@
.pio .pio
.vscode/.browse.c_cpp.db* .vscode
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.vscode/*

View File

@ -1,33 +1,83 @@
# NerdSoloMiner # NerdSoloMiner
The NerdSoloMiner v2 **The NerdSoloMiner v2**
This is a **free and open source project** that let you try to reach a bitcoin block with a small piece of hardware.
The main aim of this project is to let you **learn more about minery** and to have a beautiful piece of hardware in your desktop.
Original project https://github.com/valerio-vaccaro/HAN Original project https://github.com/valerio-vaccaro/HAN
![image](https://raw.githubusercontent.com/BitMaker-hub/NerdMiner_v2/master/images/NerdMinerv2.jpg) ![image](images/NerdMinerv2.jpg)
## Requirements ## Requirements
- TTGO T-Display S3 - TTGO T-Display S3
- 3D BOX [here](3d_files/) - 3D BOX [here](3d_files/)
## Description ### Project description
ESP32 implementing Stratum protocol to mine on solo pool. Pool can be changed but originally works with ckpool. **ESP32 implementing Stratum protocol** to mine on solo pool. Pool can be changed but originally works with ckpool.
This project is using ESP32-S3, uses WifiManager to modify miner settings and save them to SPIFF. This project is using ESP32-S3, uses WifiManager to modify miner settings and save them to SPIFF.
This miner is multicore and multithreads, each thread mine a different block template. After 1,000,000 trials the block in refreshed in order to avoid mining on old template. This miner is multicore and multithreads, each thread mine a different block template. After 1,000,000 trials the block in refreshed in order to avoid mining on old template.
## TUTORIAL ***Current project is still in developement and more features will be added***
Create your own miner using the online tool ESPtool and the binary files that you will find in the bin folder.
## Build Tutorial
### Hardware requirements
- TTGO T-Display S3 > Buy it on aliexpress or amazon
- 3D BOX
### Flash firmware
Create your own miner using the online tool **ESPtool** and the **binary files** that you will find in the src/bin folder.
If you want you can compile the entire project using Arduino, PlatformIO or Expressif IDF. If you want you can compile the entire project using Arduino, PlatformIO or Expressif IDF.
1. Get a TTGO T-display S3 1. Get a TTGO T-display S3
1. Download this repository 1. Download this repository
1. Go to ESPtool online: https://espressif.github.io/esptool-js/ 1. Go to ESPtool online: https://espressif.github.io/esptool-js/
1. Load the firmware with the binaries from the bin folder. 1. Load the firmware with the binaries from the src/bin folder.
1. Plug your board and select each file from src/bin with its address
Complete tutorial on YouTube: #### Build troubleshooting
1. Online ESPtool works with chrome, chromium, brave
1. ESPtool recommendations: use 115200bps
1. Build errors > If during firmware download upload stops, it's recommended to enter the board in boot mode. Unplug cable, hold right bottom button and then plug cable. Try programming
### NerdMiner configuration
After programming, you will only need to setup your Wifi and BTC address.
1. Connect to NerdMinerAP
1. Setup your Wifi Network
1. Add your BTCaddress
Optional you can select other pool:
| Pool URL | Port | URL |
|--- |--- |--- |
| solo.ckpool.org | 3333 | https://solo.ckpool.org/ |
| btc.zsolo.bid | 6057 | https://zsolo.bid/en/btc-solo-mining-pool |
| eu.stratum.slushpool.com | 3333 | https://braiins.com/pool |
**If you need to reboot your currentConfig**, hold right top button during 5 seconds and config will be deleted.
#### Build video
[![Ver video aquí](https://img.youtube.com/vi/POUT2R_opDs/0.jpg)](https://youtu.be/POUT2R_opDs) [![Ver video aquí](https://img.youtube.com/vi/POUT2R_opDs/0.jpg)](https://youtu.be/POUT2R_opDs)
## DEVELOPMENT ## Developers
You can use platformio pltaform to develop this project. ### Project guidelines
- Current project was addapted to work with PlatformIO
- Current project works with ESP32-S3 but any ESP32 can be used.
- Partition squeme should be build as huge app
- All libraries needed shown on platform.ini
### On process
- [x] Move project to platformIO
- [x] Bug rectangle on screen when 1milion shares
- [x] Bug memory leaks
- [x] Bug Reboots when received JSON contains some null values
- [ ] Improve hashrate using Blockstream Jade miner code
- [ ] Add blockHeight to screen
- [ ] Add new screen with global mining stats
- [ ] Add support to control BM1397
Enjoy

View File

@ -1,2 +0,0 @@
Navegar al directorio mis documentos, arduino y allí cambiar la configuración del fichero user_setup.h por este.
Verigicar que el user_setup_select.h está indicado que es user_setup.h

BIN
bin/0x0000_bootloader.bin Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/0x10000_firmware.bin Normal file

Binary file not shown.

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

View File

@ -7,6 +7,7 @@
; ;
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[platformio] [platformio]
globallib_dir = lib globallib_dir = lib
@ -29,7 +30,8 @@ build_flags =
-D BOARD_HAS_PSRAM -D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1 -D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_CDC_ON_BOOT=1
-D DEBUG_MINING=1
lib_deps = lib_deps =
https://github.com/takkaO/OpenFontRender https://github.com/takkaO/OpenFontRender
bblanchon/ArduinoJson@^6.21.1 bblanchon/ArduinoJson@^6.21.2
https://github.com/tzapu/WiFiManager.git https://github.com/tzapu/WiFiManager.git

View File

@ -14,6 +14,7 @@
unsigned long templates = 0; unsigned long templates = 0;
unsigned long hashes= 0; unsigned long hashes= 0;
unsigned long Mhashes = 0; unsigned long Mhashes = 0;
int halfshares; // increase if blockhash has 16 bits of zeroes int halfshares; // increase if blockhash has 16 bits of zeroes
int shares; // increase if blockhash has 32 bits of zeroes int shares; // increase if blockhash has 32 bits of zeroes
int valids; // increased if blockhash <= target int valids; // increased if blockhash <= target
@ -34,6 +35,14 @@ bool checkHalfShare(unsigned char* hash) {
break; break;
} }
} }
#ifdef DEBUG_MINING
if (valid) {
Serial.print("\thalf share : ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x ", hash[i]);
Serial.println();
}
#endif
return valid; return valid;
} }
@ -45,6 +54,14 @@ bool checkShare(unsigned char* hash) {
break; break;
} }
} }
#ifdef DEBUG_MINING
if (valid) {
Serial.print("\tshare : ");
for (size_t i = 0; i < 32; i++)
Serial.printf("%02x ", hash[i]);
Serial.println();
}
#endif
return valid; return valid;
} }
@ -59,12 +76,14 @@ bool checkValid(unsigned char* hash, unsigned char* target) {
break; break;
} }
} }
#ifdef DEBUG_MINING
if (valid) { if (valid) {
Serial.print("\tvalid : "); Serial.print("\tvalid : ");
for (size_t i = 0; i < 32; i++) for (size_t i = 0; i < 32; i++)
Serial.printf("%02x ", hash[i]); Serial.printf("%02x ", hash[i]);
Serial.println(); Serial.println();
} }
#endif
return valid; return valid;
} }
@ -141,12 +160,14 @@ void runWorker(void *name) {
Serial.print(" extranonce2_size: "); Serial.println(extranonce2_size); Serial.print(" extranonce2_size: "); Serial.println(extranonce2_size);
Serial.print(" error: "); Serial.println(error); Serial.print(" error: "); Serial.println(error);
if((extranonce1.length() == 0) || line.length() == 0 || (error != 0)) { if((extranonce1.length() == 0) || line.length() == 0 || (error != 0)) {
Serial.printf("[WORKER] %s >>>>>>>>> Worker aborted\n", (char *)name); Serial.printf("[WORKER] %s >>>>>>>>> Work aborted\n", (char *)name);
Serial.printf("extranonce1 length: %u | line2 length: %u | error code: %u \n", Serial.printf("extranonce1 length: %u | line2 length: %u | error code: %u \n",
extranonce1.length(), extranonce1.length(),
line.length(), line.length(),
error); error);
client.stop(); client.stop();
doc.clear();
doc.garbageCollect();
continue; continue;
} }
@ -160,6 +181,7 @@ void runWorker(void *name) {
Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n')); Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n'));
Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n')); Serial.print(" Receiving: "); Serial.println(client.readStringUntil('\n'));
client.stop(); client.stop();
deserializeJson(doc, line); deserializeJson(doc, line);
String job_id = String((const char*) doc["params"][0]); String job_id = String((const char*) doc["params"][0]);
String prevhash = String((const char*) doc["params"][1]); String prevhash = String((const char*) doc["params"][1]);
@ -170,6 +192,8 @@ void runWorker(void *name) {
String nbits = String((const char*) doc["params"][6]); String nbits = String((const char*) doc["params"][6]);
String ntime = String((const char*) doc["params"][7]); String ntime = String((const char*) doc["params"][7]);
bool clean_jobs = doc["params"][8]; //bool bool clean_jobs = doc["params"][8]; //bool
#ifdef DEBUG_MINING
Serial.print(" job_id: "); Serial.println(job_id); Serial.print(" job_id: "); Serial.println(job_id);
Serial.print(" prevhash: "); Serial.println(prevhash); Serial.print(" prevhash: "); Serial.println(prevhash);
Serial.print(" coinb1: "); Serial.println(coinb1); Serial.print(" coinb1: "); Serial.println(coinb1);
@ -179,6 +203,7 @@ void runWorker(void *name) {
Serial.print(" nbits: "); Serial.println(nbits); Serial.print(" nbits: "); Serial.println(nbits);
Serial.print(" ntime: "); Serial.println(ntime); Serial.print(" ntime: "); Serial.println(ntime);
Serial.print(" clean_jobs: "); Serial.println(clean_jobs); Serial.print(" clean_jobs: "); Serial.println(clean_jobs);
#endif
doc.clear(); doc.clear();
templates++; templates++;
@ -223,24 +248,26 @@ void runWorker(void *name) {
for (int k = 0; k < pad; k++) { for (int k = 0; k < pad; k++) {
extranonce2_b_char[k] = '0'; extranonce2_b_char[k] = '0';
} }
extranonce2_b_char[pad+1] = 0; extranonce2_b_char[pad+1] = 0;
extranonce2_b = String(extranonce2_b_char) + extranonce2_b; extranonce2_b = String(extranonce2_b_char) + extranonce2_b;
String extranonce2 = String(extranonce2_a + extranonce2_b).substring(0, 17 - (2 * extranonce2_size)); String extranonce2 = String(extranonce2_a + extranonce2_b).substring(0, 17 - (2 * extranonce2_size));
Serial.print(" extranonce2: "); Serial.println(extranonce2);
//get coinbase - coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest() //get coinbase - coinbase_hash_bin = hashlib.sha256(hashlib.sha256(binascii.unhexlify(coinbase)).digest()).digest()
String coinbase = coinb1 + extranonce1 + extranonce2 + coinb2; String coinbase = coinb1 + extranonce1 + extranonce2 + coinb2;
Serial.print(" coinbase: "); Serial.println(coinbase);
size_t str_len = coinbase.length()/2; size_t str_len = coinbase.length()/2;
uint8_t bytearray[str_len]; uint8_t bytearray[str_len];
size_t res = to_byte_array(coinbase.c_str(), str_len*2, bytearray); size_t res = to_byte_array(coinbase.c_str(), str_len*2, bytearray);
Serial.print(" coinbase bytes - size ");
Serial.println(res); #ifdef DEBUG_MINING
Serial.print(" extranonce2: "); Serial.println(extranonce2);
Serial.print(" coinbase: "); Serial.println(coinbase);
Serial.print(" coinbase bytes - size: "); Serial.println(res);
for (size_t i = 0; i < res; i++) for (size_t i = 0; i < res; i++)
Serial.printf("%02x ", bytearray[i]); Serial.printf("%02x ", bytearray[i]);
Serial.println("---"); Serial.println("---");
#endif
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
mbedtls_md_init(&ctx); mbedtls_md_init(&ctx);
@ -257,10 +284,12 @@ void runWorker(void *name) {
mbedtls_md_update(&ctx, interResult, 32); mbedtls_md_update(&ctx, interResult, 32);
mbedtls_md_finish(&ctx, shaResult); mbedtls_md_finish(&ctx, shaResult);
#ifdef DEBUG_MINING
Serial.print(" coinbase double sha: "); Serial.print(" coinbase double sha: ");
for (size_t i = 0; i < 32; i++) for (size_t i = 0; i < 32; i++)
Serial.printf("%02x", shaResult[i]); Serial.printf("%02x", shaResult[i]);
Serial.println(""); Serial.println("");
#endif
byte merkle_result[32]; byte merkle_result[32];
// copy coinbase hash // copy coinbase hash
@ -272,15 +301,21 @@ void runWorker(void *name) {
uint8_t bytearray[32]; uint8_t bytearray[32];
size_t res = to_byte_array(merkle_element, 64, bytearray); size_t res = to_byte_array(merkle_element, 64, bytearray);
// Serial.print("\tmerkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element); #ifdef DEBUG_MINING
Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element);
#endif
for (size_t i = 0; i < 32; i++) { for (size_t i = 0; i < 32; i++) {
merkle_concatenated[i] = merkle_result[i]; merkle_concatenated[i] = merkle_result[i];
merkle_concatenated[32 + i] = bytearray[i]; merkle_concatenated[32 + i] = bytearray[i];
} }
// Serial.print("\tmerkle concatenated: ");
// for (size_t i = 0; i < 64; i++) #ifdef DEBUG_MINING
// Serial.printf("%02x", merkle_concatenated[i]); Serial.print(" merkle element "); Serial.print(k); Serial.print(": "); Serial.println(merkle_element);
// Serial.println(""); Serial.print(" merkle concatenated: ");
for (size_t i = 0; i < 64; i++)
Serial.printf("%02x", merkle_concatenated[i]);
Serial.println("");
#endif
mbedtls_md_starts(&ctx); mbedtls_md_starts(&ctx);
mbedtls_md_update(&ctx, merkle_concatenated, 64); mbedtls_md_update(&ctx, merkle_concatenated, 64);
@ -290,14 +325,16 @@ void runWorker(void *name) {
mbedtls_md_update(&ctx, interResult, 32); mbedtls_md_update(&ctx, interResult, 32);
mbedtls_md_finish(&ctx, merkle_result); mbedtls_md_finish(&ctx, merkle_result);
// Serial.print("\tmerkle sha : "); #ifdef DEBUG_MINING
// for (size_t i = 0; i < 32; i++) Serial.print(" merkle sha : ");
// Serial.printf("%02x", merkle_result[i]); for (size_t i = 0; i < 32; i++)
// Serial.println(""); Serial.printf("%02x", merkle_result[i]);
Serial.println("");
#endif
} }
// merkle root from merkle_result // merkle root from merkle_result
Serial.print("\tmerkle sha : "); Serial.print(" merkle sha : ");
char merkle_root[65]; char merkle_root[65];
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
Serial.printf("%02x", merkle_result[i]); Serial.printf("%02x", merkle_result[i]);
@ -310,9 +347,11 @@ void runWorker(void *name) {
String blockheader = version + prevhash + String(merkle_root) + nbits + ntime + "00000000"; String blockheader = version + prevhash + String(merkle_root) + nbits + ntime + "00000000";
str_len = blockheader.length()/2; str_len = blockheader.length()/2;
uint8_t bytearray_blockheader[str_len]; uint8_t bytearray_blockheader[str_len];
Serial.println(" blockheader bytes "); Serial.print(str_len); Serial.print(" -> ");
res = to_byte_array(blockheader.c_str(), str_len*2, bytearray_blockheader); res = to_byte_array(blockheader.c_str(), str_len*2, bytearray_blockheader);
Serial.println(res);
#ifdef DEBUG_MINING
Serial.println(" blockheader bytes "); Serial.print(str_len); Serial.print(" -> ");
#endif
// reverse version // reverse version
uint8_t buff; uint8_t buff;
@ -342,38 +381,42 @@ void runWorker(void *name) {
bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff; bytearray_blockheader[2 * boffset + bsize - 1 - j] = buff;
} }
#ifdef DEBUG_MINING
Serial.print(" >>> bytearray_blockheader : "); Serial.print(" >>> bytearray_blockheader : ");
for (size_t i = 0; i < 4; i++) for (size_t i = 0; i < 4; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("version"); Serial.println("version");
for (size_t i = 0; i < 4; i++) for (size_t i = 0; i < 4; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("prev hash"); Serial.println("prev hash");
for (size_t i = 4; i < 4+32; i++) for (size_t i = 4; i < 4+32; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("merkle root"); Serial.println("merkle root");
for (size_t i = 36; i < 36+32; i++) for (size_t i = 36; i < 36+32; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("time"); Serial.println("time");
for (size_t i = 68; i < 68+4; i++) for (size_t i = 68; i < 68+4; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("difficulty"); Serial.println("difficulty");
for (size_t i = 72; i < 72+4; i++) for (size_t i = 72; i < 72+4; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
Serial.println("nonce"); Serial.println("nonce");
for (size_t i = 76; i < 76+4; i++) for (size_t i = 76; i < 76+4; i++)
Serial.printf("%02x ", bytearray_blockheader[i]); Serial.printf("%02x", bytearray_blockheader[i]);
Serial.println(""); Serial.println("");
#endif
// search a valid nonce // search a valid nonce
uint32_t nonce = 0; uint32_t nonce = 0;
uint32_t startT = micros(); uint32_t startT = micros();
Serial.println(">>> STARTING TO HASH NONCES");
while(true) { while(true) {
bytearray_blockheader[76] = (nonce >> 0) & 0xFF; bytearray_blockheader[76] = (nonce >> 0) & 0xFF;
bytearray_blockheader[77] = (nonce >> 8) & 0xFF; bytearray_blockheader[77] = (nonce >> 8) & 0xFF;
@ -395,9 +438,6 @@ void runWorker(void *name) {
// check if share // check if share
if(checkShare(shaResult)) { if(checkShare(shaResult)) {
shares++; shares++;
}
}
// check if valid header // check if valid header
if(checkValid(shaResult, bytearray_target)) { if(checkValid(shaResult, bytearray_target)) {
//Serial.printf("%s on core %d: ", (char *)name, xPortGetCoreID()); //Serial.printf("%s on core %d: ", (char *)name, xPortGetCoreID());
@ -419,9 +459,12 @@ void runWorker(void *name) {
nonce = MAX_NONCE; nonce = MAX_NONCE;
break; break;
} }
}
}
nonce++; nonce++;
hashes++; hashes++;
if(hashes++>1000000) { Mhashes++; hashes=0;} if(hashes++>1000000) { Mhashes++; hashes=0;}
// exit // exit
if (nonce >= MAX_NONCE) { if (nonce >= MAX_NONCE) {

View File

@ -1,5 +1,3 @@
//Botón configuración //Botón configuración
#define PIN_BUTTON_1 0 #define PIN_BUTTON_1 0
#define PIN_BUTTON_2 14 #define PIN_BUTTON_2 14
@ -8,3 +6,4 @@ void init_WifiManager();
void wifiManagerProcess(); void wifiManagerProcess();
void checkResetConfigButton(); void checkResetConfigButton();
void checkRemoveConfiguration(); void checkRemoveConfiguration();

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html