0

Anyone can give step-by-step explanation about the code below (if possible, with a c/c++ equivalent)?

import hashlib, struct

ver = 2
prev_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
mrkl_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
time_ = 0x53058b35 # 2014-02-20 04:57:25
bits = 0x19015f53

# https://en.bitcoin.it/wiki/Difficulty
exp = bits >> 24
mant = bits & 0xffffff
target_hexstr = '%064x' % (mant * (1<<(8*(exp - 3))))
target_str = target_hexstr.decode('hex')

nonce = 0
while nonce < 0x100000000:
    header = ( struct.pack("<L", ver) + prev_block.decode('hex')[::-1] +
          mrkl_root.decode('hex')[::-1] + struct.pack("<LLL", time_, bits, nonce))
    hash = hashlib.sha256(hashlib.sha256(header).digest()).digest()
    print nonce, hash[::-1].encode('hex')
    if hash[::-1] < target_str:
        print 'success'
        break
    nonce += 1

I am trying create my own implementation; I already read the block data with json-rpc and stored in this struct:

struct block {
  unsigned char* hash;
  int confirmations;
  long strippedsize;
  long size;
  long weight;
  long height;
  long version;
  unsigned char* versionHex;
  unsigned char* merkleroot;
  long blocktime;
  long mediantime;
  long nonce;
  unsigned char* bits;
  double difficulty;
  unsigned char* chainwork;
  unsigned char* previousblockhash;
};

Now I want extract the data from this struct and use to execute the same calculations in this code, but I need to understand what the code does with more details.

0

First we define some information which goes on the block, namely what version the block is, what the previous block hash was (because each block references the previous one to create the chain), what the merkle root of all the transactions in this block is (see Wikipedia if you don't know what this is), the current timestamp, and the current difficulty encoded in the bits variable:

import hashlib, struct

ver = 2
prev_block = "000000000000000117c80378b8da0e33559b5997f2ad55e2f7d18ec1975b9717"
mrkl_root = "871714dcbae6c8193a2bb9b2a69fe1c0440399f38d94b3a0f1b447275a29978a"
time_ = 0x53058b35 # 2014-02-20 04:57:25
bits = 0x19015f53

Then we take the bits value, and convert it into a difficulty target based on the steps listed in the linked wiki page on difficulty. The target is basically a number we want to find a hash below (e.g. if the target was 10, only hashes less than 10 would be valid):

# https://en.bitcoin.it/wiki/Difficulty
exp = bits >> 24
mant = bits & 0xffffff
target_hexstr = '%064x' % (mant * (1<<(8*(exp - 3))))
target_str = target_hexstr.decode('hex')

Now we start a loop, hashing the block many many times with different nonce values until we find a hash less than the target. We start the nonce off at 0, and increase it by 1 each loop so we get a different hash every time:

nonce = 0
while nonce < 0x100000000:

This is just putting the data we defined earlier (including the nonce) together into the serialised block ready to be hashed:

    header = ( struct.pack("<L", ver) + prev_block.decode('hex')[::-1] +
          mrkl_root.decode('hex')[::-1] + struct.pack("<LLL", time_, bits, nonce))

This is where we actually hash the serialised block data, obtaining a hash, which we print out (encoded as a hexadecimal string) with the nonce for logging purposes:

    hash = hashlib.sha256(hashlib.sha256(header).digest()).digest()
    print nonce, hash[::-1].encode('hex')

Finally, we compare the hash value to the target, and if it's lower than the target, we've successfully found a valid block, otherwise try the next nonce:

    if hash[::-1] < target_str:
        print 'success'
        break
    nonce += 1

Note that this is a very simple program, good for understanding, but wouldn't really work in real mining because changing the nonce alone is no longer enough variation to find a block, data is also varies in the coinbase transaction to change the merkle root as well. That's just because the target is so low (difficulty so high) that the chance of hitting it is quite low to combat the massive mining power on the network. The program also doesn't calculate the merkle root itself, which needs to be done if you're starting straight from transactions.

  • how I get the data which will goes on the block? If I get some block from the bitcoin network (with getbestblokchash json-rpc command, for instance) I can use the data extract from this block as a base for the generated header? Or I just need create all new data for a completely new block? In this last case, how I get this transactions for generate de merkle root? Or is it generated only with the coinbase transaction? – Kleber Mota Aug 21 '17 at 14:12
  • getbestblockhash will give you prev_block. The difficulty is found using the difficulty retargeting algorithm. Transactions are picked up over time by nodes connected to the network, in the mempool. Please don't ask multiple questions as comments, either edit your original question or post a new one. – MeshCollider Aug 21 '17 at 20:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.