0

I am trying to build a TransactionsTrie with python. I am using this [trie][1]-Library. I followed the Instructions.

Edit: Removed the original question because it was stupid.

@carver Thank you very much. Your reply was really helpful. So I am trying to use the method You referenced from py-evm.

Here is my full code:

import requests
import json
import ethereum.utils as utils
from eth.db.trie import make_trie_root_and_nodes as make_trie
from eth.rlp.transactions import BaseTransactionFields
from eth.rlp.transactions import BaseTransaction

url = 'https://ropsten.infura.io/1234'

headers = {
    "Content-Type": "application/json"
}
data = {}
data['jsonrpc'] = '2.0'
data['id'] = 1
data['method'] = 'eth_getBlockByHash'
data['params'] = ["0xd993562b847a2b61f858ee2baa2351f05e22d755d3657444f06a8c51f88a11f8", True]
data = json.dumps(data)

response = requests.post(url, headers=headers, data=str(data) )
print(response.text)
block = json.loads(response.text)
result = block['result']
raw_transactions = result['transactions']

transactions = tuple()
for tx in raw_transactions:
    nonce = tx['nonce']
    nonce = utils.int_to_big_endian(int(nonce[2:], 16))
    gas_price = tx['gasPrice']
    gas_price = utils.int_to_big_endian(int(gas_price[2:], 16))
    gas = tx['gas']
    gas = utils.int_to_big_endian(int(gas[2:], 16))
    to = tx['to']
    to = bin(int(to[2:], 16))
    value = tx['value']
    value = utils.int_to_big_endian(int(value[2:], 16))
    data = tx['input']
    print(data)
    if data != '0x':
        data = bin(int(data[2:], 16))
    else:
        data = bin(0)
    print(data)
    v = tx['v']
    v = utils.int_to_big_endian(int(v[2:], 16))
    r = tx['r']
    r = utils.int_to_big_endian(int(r[2:], 16))
    s = tx['s']
    s = utils.int_to_big_endian(int(s[2:], 16))
    f = BaseTransactionFields(nonce = nonce, gas_price = gas_price, gas = gas, to = to, value = value, data = data, v = v, r = r, s = s)
    transactions += tuple(f)

tx_root, _ = make_trie(transactions)
print(tx_root.hex())

Still my txRoot is not the same as the one in the Block. What am I doing wrong?

  • 1
    I wouldn't use BaseTransactionFields directly, for one. It's hard to say without looking at one specific transaction that is not encoding correctly. Are all transactions failing, or just some? Try to narrow it down to a single transaction that's not encoding correctly by doing Web3.sha3(rlp.encode(rebuilt_transaction)) == original_tx['hash']. Then a newly posted question could be focused on something like "why is my hash of this specific transaction not matching the client's hash?" – carver Oct 1 '18 at 19:41
1

When building a transaction trie in Ethereum, both key and value are rlp-encoded. The key is the zero-based order of inclusion, and the value is the full transaction (not the hash).

You can see an example utility that trinity uses to generate the transaction trie (edited for clarity):

items = tuple(rlp.encode(object) for object in rlp_objects)

kv_store = {}  # type: Dict[Hash32, bytes]
trie = HexaryTrie(kv_store, BLANK_ROOT_HASH)

for index, item in enumerate(items):
    index_key = rlp.encode(index, sedes=rlp.sedes.big_endian_int)
    trie[index_key] = item

transaction_root = trie.root_hash
| improve this answer | |
  • could you be so kind to take some of your very valuable time to tell me why I'm Stupid? See the Edit. – SimonSchuler Oct 1 '18 at 15:02
0

Just for the record I am posting my complete code, so that maybe someone else can use it :)

def _create_transaction(*, nonce, gasprice, startgas, to, value, data=b'', v=None, r=None, s=None, network_id=None):
    if to:
        to = address_decoder(to)
    else:
        to = b''

    if network_id is not None:
        if r is not None or s is not None:
            raise Exception(
                "cannot set network id at the same time as r and s values")
        v = network_id

    tx = Transaction(nonce, gasprice, startgas, to,
                     value, data, v or 0, r or 0, s or 0)
    tx._sender = None

    return tx


def create_transaction(tx):

    nonce = tx['nonce']
    gas_price = tx['gasPrice']
    gas = tx['gas']
    to = tx['to']
    value = tx['value']
    data = tx['input'][2:]
    if data == "":
        data = b''
    else:
        data = data_decoder(data)
    v = tx['v']
    r = int.from_bytes(tx['r'], byteorder='big')
    s = int.from_bytes(tx['s'], byteorder='big')
    return _create_transaction(nonce=nonce, gasprice=gas_price, startgas=gas, to=to, data=data, value=value, v=v, r=r, s=s)


def make_trie_root_and_nodes(items: Transactions) -> TrieRootAndData:
    return _make_trie_root_and_nodes(tuple(rlp.encode(item) for item in items))


def _make_trie_root_and_nodes(items: Tuple[bytes, ...]) -> TrieRootAndData:
    kv_store = {}  # type: Dict[Hash32, bytes]
    trie = HexaryTrie(kv_store)
    with trie.squash_changes() as memory_trie:
        for index, item in enumerate(items):
            index_key = rlp.encode(index, sedes=rlp.sedes.big_endian_int)
            memory_trie[index_key] = item
    return trie.root_hash, kv_store

the make_trie_root_and_nodes functions are copied(and slightly modified) from here (trinity)

| improve this answer | |

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.