Bitcoin

Stratum – How should block header data be ordered in messages with a pool?

First of all, I wrote this post to help all of you who are interested in understanding and building your own miner from scratch. There is so much material, but so little in common.

I need help verifying that the order of issues in block headers is correct for mining. I’m building my own miner as a challenge, but I’m still struggling with the proper format. There are lots of examples on the web, but in practice even pools don’t specify the order in which data is sent for the client. So for absolute clarity I thought we could get a definitive answer to the question here.

Some developers flip the full hash and even flip the bytes.

hex2byte(ph, bp);
 revFlip(bp);

Others just copy the Bitcoin wiki solution, for example, without realizing that the previous hash is the opposite of what the mining pool provides.

 $prevBlockHash = SwapOrder('00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81');
  $rootHash = SwapOrder('2b12fcf1b09288fcaff797d71e950e71ae42b91e8bdb2304758dfcffc2b620e3');
  $

Some people say we need to change our ways. nbits,hour, version – But this has already been reversed in the pool, right?

So the question is:

When talking to the pool, how should I sort the data for the block header so that I can compare it to the target after hashing?

This is so important that a mistake here will cause the miner to calculate an irrelevant hash and thus not find a valid ‘nonce’. This is so wasteful that we need to make it clear.

Since we are talking about swimming pools here, we will base our explanation on: solo.ckpool.org yes.

So let’s connect to the pool from the beginning and retrieve the data we need to use to construct the block header.

Now, the data being sent to me is: solo.ckpool.org am:

"result":((("mining.notify","71ae8ae6")),"5324fa6e",8),"id":1,"error":null

"params":("64851638000ea04d","6a2be50e9bfb43f4973d1b2a84fc5fa27a11730b000209b00000000000000000","01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3503a9d20c0004b8852666047a773e130c","0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff03c432eb1b000000001976a914c987a18977a2139835193b3df2eea097f834966888ac76dc91000000000016001451ed61d2f6aa260cc72cdf743e4e436a82c010270000000000000000266a24aa21a9ed5c2c1c347c20b2c0818daeda78f4d407f55b405e5652265bbc0b5ab948c615cb00000000",("3d14cb3882afe1cdb6121b77a1c6fe1ace1cfb4f56796875c0e5dc7475d794e5","90107e0ab73bfb0cb540cf129823a3fdd4d2df2d1cfb8a50f2ec4f10da6e4e3f","ce46e565beea4882ea532dfaecb83cc879a60c36a298ab40ec2a3c4e5ae42d65","afbead8f037a81818082f0d276e4a438a3456f0dfcce87255c349264a77ffdf1","67dcbd833c2676450e1f388da5781f902c6c4ca423a88fac6cf2a16827ebd567","7ffff8567be6efa8acd37a27b3c60bd194ca990bca74c9e71dd673d3e0c3f621","53514468979f077ace9ba497d3fa44e5091150188d29ed3dcb80a89f36662839","ff0c843842dde895d2ee8e698d35240517de66bdd839ec3f88d7c3a2b2337724","81a08847bb764ec45481a3e491640d5557fc78276091b69534af71267d1610a5","fb60c793ec790c71bb5b54e93cd8db5f134d9730754ec7c88f71862e07151d7f","bcd9c2f483e5a422e735f23610a40d07790f0ef47bea1218a4fbc1489865202c","b9a275e502fab0f76cb10e9d791a16ef18cf8addbf2ebdc92ede9a07a62dee84"),"20000000","17034219","662685b8",true),"id":null,"method":"mining.notify"

The pool is sending the previous hash like this: 6a2be50e9bfb43f4973d1b2a84fc5fa27a11730b000209b00000000000000000 So some parts are already inverted (but nowhere does it say if they are inverted and can be used as is).

So, based on the above, let’s move on to my thoughts on how to properly structure your headers.

Configuration (connection)

  1. Do not revert versions in the pool. 20000000
  2. Don’t invert the previous hash (compared to https://en.bitcoin.it/wiki/Block_hashing_algorithm it looks like it’s inverted). 6a2be50e9bfb43f4973d1b2a84fc5fa27a11730b000209b00000000000000000
  3. Dash the merkle and flip it over.
  4. Do not return ntime from the pool. 662685b8
  5. Do not invert nbits in the pool. 17034219
  6. Generate a random nonce and do not revert it (since we are working on a Little Endian machine)

Add everything as usual.
version+prev_block_hash+merkle_hash+ntime+nbits+nonce

For clarity: version+prev_block_hash+reverse(merkle_hash)+ntime+nbits+nonce

And the output I generate is:

Coinbase1           : 01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3503a9d20c0004b8852666047a773e130c
Coinbase2           : 0a636b706f6f6c112f736f6c6f2e636b706f6f6c2e6f72672fffffffff03c432eb1b000000001976a914c987a18977a2139835193b3df2eea097f834966888ac76dc91000000000016001451ed61d2f6aa260cc72cdf743e4e436a82c010270000000000000000266a24aa21a9ed5c2c1c347c20b2c0818daeda78f4d407f55b405e5652265bbc0b5ab948c615cb00000000
Extranonce1         : 5324fa6e
Extranonce2         : 000000008f6bc892
Extranonce2 size    : 8
Merkle 0            :3d14cb3882afe1cdb6121b77a1c6fe1ace1cfb4f56796875c0e5dc7475d794e5
Merkle 1            :90107e0ab73bfb0cb540cf129823a3fdd4d2df2d1cfb8a50f2ec4f10da6e4e3f
Merkle 2            :ce46e565beea4882ea532dfaecb83cc879a60c36a298ab40ec2a3c4e5ae42d65
Merkle 3            :afbead8f037a81818082f0d276e4a438a3456f0dfcce87255c349264a77ffdf1
Merkle 4            :67dcbd833c2676450e1f388da5781f902c6c4ca423a88fac6cf2a16827ebd567
Merkle 5            :7ffff8567be6efa8acd37a27b3c60bd194ca990bca74c9e71dd673d3e0c3f621
Merkle 6            :53514468979f077ace9ba497d3fa44e5091150188d29ed3dcb80a89f36662839
Merkle 7            :ff0c843842dde895d2ee8e698d35240517de66bdd839ec3f88d7c3a2b2337724
Merkle 8            :81a08847bb764ec45481a3e491640d5557fc78276091b69534af71267d1610a5
Merkle 9            :fb60c793ec790c71bb5b54e93cd8db5f134d9730754ec7c88f71862e07151d7f
Merkle 10            :bcd9c2f483e5a422e735f23610a40d07790f0ef47bea1218a4fbc1489865202c
Merkle 11            :b9a275e502fab0f76cb10e9d791a16ef18cf8addbf2ebdc92ede9a07a62dee84
Version             : 536870912 / 20000000
Merklehash          : bc65e13b5f7c69e9ce91adbb063d46b9be2445805e6a2498e13863708d57392c
ntime               : 662685b8 / 662685b8
nbits               : 17034219 / 17034219
Nonce               : 00
Block prevhash      : 6a2be50e9bfb43f4973d1b2a84fc5fa27a11730b000209b00000000000000000
Block Header        : 000000206a2be50e9bfb43f4973d1b2a84fc5fa27a11730b000209b000000000000000002c39578d706338e198246a5e804524beb9463d06bbad91cee9697c5f3be165bcb88526661942031700000000
Block hash(reversed): 03752b55669564dccb91e47cb1d5fe421fac014e1e9fb2d563d1bd8fe44c86f2
Target(reversed)    : 0000000000000000000000000000000000000000194203000000000000000000

You then need to double hash the merkle and block headers using SHA256. As far as I know SHA256 always shows BE, so you need to invert the hash after completing the double hash.

hashing

  1. Compute the Merkle, double hash it and reverse it (since you are doing SHA256).

  2. DHashing the header and then reversing it (since we are doing SHA256).

Comparison But that’s a different story.

Thank you in advance. I’ve seen a lot of implementations of different miners, so any help here would be appreciated. Even with the same pool, many do things differently.

Related Articles

Back to top button