0

I've created a function for parsing Json Objects and values and just when I think nothing can stop me, just when I feel like I'm the king of the blockchain and I can finally join in on the mining race ..... I get a painful reminder/reality check...

The transactions within the getblocktemplate each have these as keys and thier values.


Question

Which Key value from the list of contents within each transaction array is my merkleroot function supposed to use to build a merklerot Hash.... Is it data or hash ? Or is it the txid?

Merkleroot needs transaction hash....so is it hash Json Key or is it the data Json Key ?


Thanks in advance

2 Answers 2

1

The transaction Merkle tree, whose root is stored in the block header, is computed over the individual transactions' txid value (which are the double-SHA256 of their data after stripping the witness).

The witness Merkle tree, whose root is stored in a coinbase output (only required for blocks containing segwit transactions, see BIP141), is computed over the transactions' hash value (which are the double-SHA256 of their data including the witness).

I recommend you study the source code of existing mining software, instead of asking questions about every tiny detail of the process.

4
  • Okay thanks... So which I'm I to feed to the merkleroot function to build a valid merklehash.. Is it hash or txid.. Remember that I'm manually placing coinbase as index 0 within list of transactions so this is pretty much the lingering difficulties. Dec 12, 2021 at 15:09
  • Also if you noticed, most of my questions are from this angle only..... Its really the only part that both vital and somewhat hard to understand. Every other part I've implemented.... Thanks for your patience and answers.. They've been really helpful. Dec 12, 2021 at 15:12
  • 1
    Please re-read my answer. I have answered your question exactly. You need both a Merkle tree of txids, and one of hashes. If these details confuse you, you'll have 100s more questions before you have a functioning miner. You really should look at example mining code instead. Dec 12, 2021 at 15:16
  • Okay Thanks. I appreciate the help. Dec 13, 2021 at 4:12
0

Just as Pieter-Wuille explained but in clearer detail........


The transaction data needed to compute a merkleroot in regards to bitcoins mining process is the "txid" key returned by the getblocktemplate response. This applies to non witness transaction processing.

In order to process transactions with witness data, you would need to gat the "hash" key value instead!

It all depends on whether or not you want your miner to process witness tagged transactions.



From getblocktemplate response


data - Raw transaction data.

txid - Double hashed output of raw transaction data.

hash - Witness hash output for transactions with witness data.



This is a working merkleRoot function I developed myself. Works as intended.


#include <iostream>
#include <vector>
#include "sha256.h" // Your sha256 solution with hex parsing function

using std::string;
using std::vector;
using std::cout;


string MKccx(vector<string> &transactions_vector)
{
    string hash;
    string temp1;
    int x = 0, d = 0;
    vector<string> calculate_tx;
    // calculate_tx[0] = SwapPerRound_2bits(coinbase_hash); // Store swapped endian format in vector index 0
    if (transactions_vector.empty())
    {
        std::cout << "\n" << "ERROR! NO TRANSACTION FOUND IN ARRAY!!... NOT EVEN A COINBASE TRANSACTION!!!... EXITING FUNCTION!" << "\n \n";
        throw;
    }
    else if (transactions_vector.size() == 1)
    {
        hash = transactions_vector[0];
        return hash;
    }
    for(int i = 0; i < transactions_vector.size(); i++) // Swap 2 bytes and reverse order of all txid's within transactions array
        transactions_vector[i] = SwapPerRound_2bits(transactions_vector[i]);

    while(true)
    {
        int z = 0;
        if (transactions_vector.size()%2 == 1) // IF SIZE OF VECTOR % 2 == 1
        {
            temp1 = transactions_vector[transactions_vector.size()-1]; // STORE VALUE OF LAST VECTOR INDEX TO TEMP1
            transactions_vector.push_back(temp1); // ADD THAT VALUE INTO VECTOR
            for(int i = 0, z = i+1; i < transactions_vector.size(); i+=2)
            {
                hash = transactions_vector[i] + transactions_vector[z]; // Concatenate txid pairs together
                hash = double_Hex_sha256(hash); // DoubleHash concatenated txid's
                calculate_tx.push_back(hash);
                z+=2;
            }
            for (int i = 0; i < calculate_tx.size(); i++)
            {
                temp1 = calculate_tx[i];
                transactions_vector[i] = temp1;
            }
            transactions_vector.resize(calculate_tx.size());
            if (calculate_tx.size() == 2)
            {
                hash = calculate_tx[0] + calculate_tx[1];
                hash = double_Hex_sha256(hash);
                hash = SwapPerRound_2bits(hash);
                return hash;
            }
            calculate_tx.clear();
        }
        else if (transactions_vector.size()%2 == 0) // IF SIZE OF VECTOR % 2 == 0
        {
            for(int i = 0, z = i+1; i < transactions_vector.size(); i+=2)
            {
                hash = transactions_vector[i] + transactions_vector[z]; // Concatenate txid pairs together
                hash = double_Hex_sha256(hash); // DoubleHash concatenated txid's
                calculate_tx.push_back(hash);
                z+=2;
            }
            for (int i = 0; i < calculate_tx.size(); i++)
            {
                temp1 = calculate_tx[i];
                transactions_vector[i] = temp1;
            }
            transactions_vector.resize(calculate_tx.size());
            if (calculate_tx.size() == 2)
            {
                hash = calculate_tx[0] + calculate_tx[1];
                hash = double_Hex_sha256(hash);
                hash = SwapPerRound_2bits(hash);
                return hash;
            }
            calculate_tx.clear();
        }       
    }
}// Successful compilation on 06/02/2022



int main(int argc, char const *argv[])
{
    // HARDCODED TXID'S 
    vector<string> transaction = {"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87","fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4","6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4","e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d","c02092b00aa0aea8463c624ccebdb0efdb18347068aa48c3d1b42766ca7e92ba"};

    vector<string> block100000 = {"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87","fff2525b8931402dd09222c50775608f75787bd2b87e56995a7bdd30f79702c4","6359f0868171b1d194cbee1af2f16ea598ae8fad666d9b012c8ed2b79a236ec4","e9a66845e05d5abc0ad04ec80f774a7e585c6e8db975962d069a522137b80c1d"};

    vector<string> transaction2 = {"8c14f0db3df150123e6f3dbbf30f8b955a8249b62ac1d1ff16284aefa3d06d87"};

    vector<string> transaction3 = {};
    string merk;
    merk = MKccx(transaction3);
    std::cout << "MerkleRoot Hash is : " << merk << "\n \n";
    // std::cout << "Merkle hash of Block 100,000 is : " << merk << "\n \n";

    return 0;
}

SwapPerRound_2bits() - Whatever solution you use for swapping endianness

double_Hex_sha256() - Equivalent of sha256(sha256());



WONDERING HOW IT ALL COMES TOGETHER??

YOU'LL NEED A JSON LIBRARY TO GET THE TRANSACTIONS INTO YOUR C++ PROGRAM

IF YOU DON'T ALREADY HAVE A WORKING JSON PARSER/SERIALIZATION LIBRARY THEN I RECOMMEND nlohmann json library FOR JSON PARSING & SERIALIZATION.

Just include its single header ".hpp" file in project folder and you're good to go!

A little batch script used but nothing advanced.

#include "json.hpp" // for json serialization parser
#include <fstream> // for ifstream
#include <stdlib.h> // for system calls
#include "windows.h" // if on windows
using namespace nlohmann;
using std::ifstream;


inline void RunCommand_With_Output_Without_SYMBOL_Defined(string Command_To_Run, string Output_FileName)
{
    string xx_combine = Command_To_Run + " >" + Output_FileName;
    char run_command[xx_combine.length()];
    strcpy(run_command, xx_combine.c_str());
    system(run_command); // execute the command 
} // Successfully compiled on 20/01/2022 10:20PM


void GETBLOCKTEMPLATE()
{
    string getblocktemplate_syntax = "cd \"C:\\Users\\YOUR DESKTOP NAME\\Desktop\\Z Code\" && call gt.bat";
    string filename = "getblocktemplate_Response.json"; // Create file Name
    RunCommand_With_Output_Without_SYMBOL_Defined(getblocktemplate_syntax, filename); // create json file with getblockresponse output
} // Successfully compiled on 31/01/2022 11:30AM



int main(int argc, char const *argv[])
{
    // DYNAMIC APPROACH FOR USAGE 
    string merk;
    GETBLOCKTEMPLATE(); // Call getblocktemplate() 
    ifstream file_input("getblocktemplate_Response.json"); // Open file
    json object = json::parse(file_input); // Parse json data
    file_input.close(); // close file
    vector<string> Txid_Retreiver; // vector for holding transactions

    auto &Array_Txid = object["transactions"]; // Create object pointing to 'transactions' array
    for(auto &target : Array_Txid) // Traverse through transaction array
        Txid_Retreiver.push_back(target["txid"].get<std::string>());
    

    merk = MKccx(Txid_Retreiver);
    std::cout << "MerkleRoot Hash is : " << merk << "\n \n";

    return 0;
}


And that's pretty much how I pulled it off.

Hope this helps someone.

Cheers....

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.