Post
Topic
Board Development & Technical Discussion
Re: Bitcoin Mining Technical Details. Help
by
xDilettante
on 13/10/2023, 14:45:51 UTC
Could you please tell me what exactly I'm doing wrong with getting the Merkle root? Here is my Python code, but I am not getting the result I need.

Target: "merkleroot": "19f3769778eb2019476630aafb376634cdf3f114e617a7e0a300e822265022bc"

Code:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from hashlib import sha256
import requests, json

DEFAULT_RPC_REGTEST_PORT = "18443"
DEFAULT_RPC_TEST_PORT = "18332"
DEFAULT_RPC_MAIN_PORT = "8332"

rpcAddress = "127.0.0.1"  # localhost
rpcPort = DEFAULT_RPC_MAIN_PORT
rpcUser = "rpcuser"
rpcPassword = "rpcpassword"
rpcUrl = "http://" + rpcAddress + ":" + rpcPort
headers = {'content-type': 'application/json'}

def double_sha256(data):
    return bytes.fromhex(sha256(bytes.fromhex(sha256(bytes.fromhex(data)).hexdigest())).hexdigest())

def request_rpc(method, params):
    payload = json.dumps(
        {
            "jsonrpc": "2.0",
            "id": "1",
            "method": method,
            "params": params
        }
    )
    return requests.request("POST", rpcUrl, data=payload, headers=headers,
                                auth=(rpcUser, rpcPassword))


if __name__ == "__main__":
    res = request_rpc(method="getblock", params=["00000000000000000000bd684e36789d16da2cf5b08b47deb72d1448a73eae5c"])
    tx = res.json()["result"]["tx"]
    print(tx)

    hashes = []
    for i in range(len(tx)):
        res = request_rpc(method="getrawtransaction",
                          params=[tx[i], 1, '00000000000000000000bd684e36789d16da2cf5b08b47deb72d1448a73eae5c'])
        hashes.append(res.json()["result"]["hash"])
    print(len(hashes))
    # print(hashes)

    hashes = [bytes.fromhex(x) for x in hashes]
    while len(hashes) > 1:
        if len(hashes) % 2 == 1:
            hashes.append(hashes[-1])
        parent_level = []
        for x in range(0, len(hashes), 2):
            hash = sha256(hashes[x] + hashes[x + 1]).digest()
            parent_level.append(hash)
        hashes = parent_level

    print(hashes[0].hex())

I also did a double hash, and also tried to get the root by hashing TXID, but that also didn't help me get the result I wanted.

Code:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-

from hashlib import sha256
import requests
import json


def double_sha256(a, b):
    ab = a[::-1] + b[::-1]
    return sha256(sha256(ab).digest()).digest()[::-1]


if __name__ == "__main__":
    block_hash = "00000000000000000000bd684e36789d16da2cf5b08b47deb72d1448a73eae5c"
    response = requests.get(f'https://api.blockchair.com/bitcoin/raw/block/{block_hash}')
    tx = response.json()['data'][block_hash]["decoded_raw_block"]["tx"]
    print(tx)

    hashes = []
    for i in range(len(tx)):
        hashes.append(tx[i])
    print(len(hashes))
    # print(hashes)

    hashes = [bytes.fromhex(x) for x in hashes]
    while len(hashes) > 1:
        if len(hashes) % 2 == 1:
            hashes.append(hashes[-1])
        parent_level = []
        for x in range(0, len(hashes), 2):
            hash = double_sha256(hashes[x], hashes[x + 1])
            parent_level.append(hash)
        hashes = parent_level

    print(hashes[0].hex())



Thank you so much for the example! It's very easy to get confused with these reverse bytes and double hashing.

Here is a fully working code for MainNet:

Code:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
from hashlib import sha256

import json
import requests

DEFAULT_RPC_REGTEST_PORT = "18443"
DEFAULT_RPC_TEST_PORT = "18332"
DEFAULT_RPC_MAIN_PORT = "8332"

rpcAddress = "127.0.0.1"
rpcPort = DEFAULT_RPC_MAIN_PORT
rpcUser = "rpcuser"
rpcPassword = "rpcpassword"
rpcUrl = "http://" + rpcAddress + ":" + rpcPort

headers = {'content-type': 'application/json'}


# Double HASH SHA256
def double_sha256(data): return sha256(sha256(data).digest()).digest()


# Reverse
def r(data): return data[::-1]


def request_rpc(method, params):
    payload = json.dumps(
        {
            "method": method,
            "params": params
        }
    )
    return requests.request("POST", rpcUrl, data=payload, headers=headers,
                            auth=(rpcUser, rpcPassword))


if __name__ == "__main__":
    res = request_rpc(method="getblock", params=["00000000000000000000bd684e36789d16da2cf5b08b47deb72d1448a73eae5c"])
    tx = res.json()["result"]["tx"]

    hashes = [bytes.fromhex(x) for x in tx]
    while len(hashes) > 1:
        if len(hashes) % 2 == 1:
            hashes.append(hashes[-1])
        parent_level = []
        for i in range(0, len(hashes), 2):
            x = r(double_sha256(r(hashes[i]) + r(hashes[i + 1])))
            parent_level.append(x)
        hashes = parent_level
    merkleroot = hashes[0].hex()
    print(merkleroot)