Introduction: ESP8266 Bitcoin Miner

About: Internet of things projects

With the price of Bitcoin continuing to climb and with a couple of ESP8266's always plugged in but not really doing much I thought why not try and implement a Solo Bitcoin Miner. After a little bit of experimenting I got the ESP8266 up to ~1200 hashes/sec and as of December 2017 the Bitcoin network was performing around 12,000,000 tera hashes per second (you can check blockchaininfo for the latest numbers).

So based on those numbers we would have a 1 in 1e16 chance of successfully mining a block every ten minutes where a block is currently worth $212,000. Sure it's a lot like buying a lotto ticket, only with a much much smaller chance of winning, but you know the old saying, someone has to win it. With both the Gate Mate and Super Squirter ESP8266 projects most of the time they are not doing any work, they're just plugged in and waiting on requests or inputs, so why not put them to it and maybe win some coinage. The first step was to try and figure out if it was even possible to perform a double SHA256 on the Blockheader on an ESP8266. In the Bitcoin world the 'hash' is actually a double SHA256, but we'll just refer to it as the hash. Anyways after a little bit of googling around I found these two pages which provided all the info needed to get hashing.

1. Block Hashing Algorithm

2. Bitcoin Mining the hard way: the algorithms, protocols and bytes

It's worth noting that the getwork protocol, as detailed in the above links, has been deprecated. It's been replaced with the getblocktemplate protocol which makes it a bit more complicated to build a block header, specifically you have to build your own merkle root. For all the nitty gritty check out the getblocktemplate wiki .

Step 1: The Algorithm

Let's jump right in, the ESP8266 code is at the ESP8266BitcoinMiner GitHub repo. I'm not going to rehash all the information from the above links but rather just highlight the main points.

char header_hex[]="0100000081cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000e320b6c2fffc8d750423db8b1eb942ae710e951ed797f7affc8892b0f1fc122bc7f5d74df2b9441a42a14695";

char header_hex is the block header and is built from six fields, Version, hashPrevBlock, hashMerkleRoot, Time, Bits and the Nonce all concatenated togther as little endian values in hex notation. That was just copied from the link above but in an actual fully fledged miner you would recieve each of those fields in a json object and then have to sort out the endianness and put it together on the fly every 10 minutes.

uint8_t* hex_decode(const char *in, size_t len, uint8_t *out){
        unsigned int i, mg, ng, rg;
        for (mg = 0, i = 0; i < len; i+=2,++mg) { 
                ng = in[i] > '9' ? in[i] - 'a' + 10 : in[i] - '0';
                rg = in[i+1] > '9' ? in[i+1] - 'a' + 10 : in[i+1] - '0';
                out[mg] = (ng << 4 ) | rg;
        }
        return out;
}

hex_decode takes the header_hex string, which contains hexadecimal ascii characters, and populates the uint8_t hashbytes[80] with their respective byte values ready for the SHA256 hasher.

void hash(){ 
  hex_decode(header_hex,strlen(header_hex),hashbytes); 
  unsigned long start = micros();
  hasher.doUpdate(hashbytes, sizeof(hashbytes));
  byte hash[SHA256_SIZE];
  hasher.doFinal(hash);

  hashagain.doUpdate(hash, sizeof(hash));
  byte hash2[SHA256_SIZE];
  hashagain.doFinal(hash2);
 
  unsigned long ended = micros();
  unsigned long delta = ended - start;
  Serial.println(delta);
  Serial.print("Big Endian: ");
  for (byte i=32; i > 0; i--){
     if (hash2[i-1]<0x10) { Serial.print('0'); }
      Serial.print(hash2[i-1], HEX);
   }
   
   Serial.println();
   Serial.print("Little Endian: ");
   for (byte i=0; i < SHA256_SIZE ; i++){
     if (hash2[i]<0x10) { Serial.print('0'); }
      Serial.print(hash2[i], HEX);
   }    
}

hash simply hashes the hashbytes twice (double SHA256), prints the useconds it took and prints out the resultant hash as a big endian and little endian. If the hashes were nested in only one SHA256 hasher it would probably be a little quicker but anyways with the above code it takes 832 useconds to perform the double hash and you cna see from the screenshot we get the correct hash.

Step 2: Hitting a Wall and a Really Big Block

So if it takes 832 useconds to do one hash we can perform 1/0.000834 = 1201 hashes /sec.

Just to be clear we took the information from block #125552 where we knew the nonce, it's already been mined and used that information as a test case to make sure we could get the same hash with the ESP8266. So once a gain with a fully fleshed out miner you would randomly take a guess at the nonce, hash the blockheader with it and then compare the result to the difficulty for that block. If the hash meets the difficulty, it is then submitted to the network for verification.

Ok so that's great we can perform the hash, sure the rate is awful but when looking at it as a lottery a guess is a guess. Here's the but, upon closer inspection it soon becomes clear you need to be running a full node to able to communicate with the network, kind of obvious when you stop and think about what mining actually is.

So if you look at the diagram you can see that the bitcoin daemon which is a part of the bitcoin core takes care of the communication between the network and the miner. What this really means is you need to be running the Bitcoin core on a server so that the ESP8266 can get a new blockheader every 10 minutes and then be able to submit back to the network.

I haven't tried it but it looks like you would have to sync the entire blockchain at around 130 Gigs before it would properly communicate with network, in the wiki they mention certain steps have to be completed before all functionality is available, so pretty sure thats what they mean.

So that pulled me up there, from a research point of view it was all very interesting and it was pretty cool to see the little ESP8266 successfully hash the test case but practically speaking I don't see many people downloading the core, syncing the entire blockchain, keeping everything up to date, keeping up with security issues all for a 1 in 1e16 chance of winning the block. A bridge to far for me.

From the get go I knew the hash rate would be terrible but curiosity got the better of me and I had to give it a go. Rather than solo mining there might be a mining pool out there that can be connected to directly from the ESP8266 without a monumental effort or there might be another cryptocurrency that is more suitable. If you find either please let me know.

Step 3: References