The Cryptonight PoW hash function (cns008) expects an input (a blob on which to mine a new block).

I know that a mining blob can easily be obtained via the monerod daemon's JSON-RPC interface by calling getblocktemplate. However, for a mining pool project I am investigating whether or not I can generate the blob myself and reproduce Monero project's logic.

From the Monero project's source, I traced the above RPC call to this:

  blobdata get_block_hashing_blob(const block& b)
    blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
    crypto::hash tree_root_hash = get_tx_tree_hash(b);
    blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
    return blob;

Here, they:

  1. initialize a blob with a block header, then

  2. append the root of some tree data-structure that stores transactions (presumably a Merkle tree) to the blob, and finally they

  3. append the number of transactions in this tree to the blob.

Unfortunately, the rest of logic is refactored into so many fragments in their codebase that I gave up trying...

So once, again my question is how can I generate the blob needed, and more specifically could somebody explain in pseudo-code terms what get_block_hashing_blob is doing under the hood?


The process to compute the mining blob can be described by the following pseudo-code:

miner_transaction = build_miner_transaction(...)
miner_transaction_id = compute_transaction_id(miner_transaction)
header = serialize(build_block_header(...))

transaction_ids = append(miner_transaction_id, other_transaction_ids...)
count = serialize_varint(number_of_transactions)  // miner transaction included
tree_root_hash = compute_merkle_tree_root_hash(transaction_ids)

blob = append(header, tree_root_hash, count)

Then the blob is hashed using the Cryptonight function.

Some details about the formats of block headers and miner transactions can be found in What is the format of a block in the Monero Blockchain.

Your Answer

