Verwenden von Python try zum Erstellen von transactionTrie. Warum ist mein Transactionsroot falsch?

Ich versuche, einen TransactionsTrie mit Python zu erstellen. Ich verwende diese [trie][1]-Library. Ich habe mich an die Anleitung gehalten.

Bearbeiten: Ursprüngliche Frage entfernt, weil sie dumm war.

@Carver Vielen Dank. Ihre Antwort war wirklich hilfreich. Also versuche ich, die Methode zu verwenden, auf die Sie von py-evm verwiesen haben.

Hier ist mein vollständiger 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())

Trotzdem ist mein txRoot nicht das gleiche wie das im Block. Was mache ich falsch?

Ich würde nicht BaseTransactionFieldsdirekt verwenden, zum einen. Es ist schwer zu sagen, ohne eine bestimmte Transaktion zu betrachten, die nicht richtig codiert ist. Sind alle Transaktionen fehlgeschlagen oder nur einige? Versuchen Sie, es auf eine einzelne Transaktion einzugrenzen, die nicht korrekt kodiert ist, indem Sie Folgendes tun Web3.sha3(rlp.encode(rebuilt_transaction)) == original_tx['hash']. Dann könnte sich eine neu gestellte Frage auf etwas wie „Warum stimmt mein Hash dieser spezifischen Transaktion nicht mit dem Hash des Kunden überein?“ konzentrieren.

Antworten (2)

Beim Erstellen eines Transaktionsversuchs in Ethereum sind sowohl der Schlüssel als auch der Wert rlp-codiert. Der Schlüssel ist die nullbasierte Reihenfolge der Einbeziehung, und der Wert ist die vollständige Transaktion (nicht der Hash).

Sie können ein Beispiel-Dienstprogramm sehen, das Trinity verwendet, um den Transaktions-Trie zu generieren (zur Verdeutlichung bearbeitet):

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
Könnten Sie so freundlich sein, etwas von Ihrer sehr wertvollen Zeit zu nehmen, um mir zu sagen, warum ich dumm bin? Siehe Bearbeiten.

Nur für die Aufzeichnung poste ich meinen vollständigen Code, damit ihn vielleicht jemand anderes verwenden kann :)

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

Die make_trie_root_and_nodes-Funktionen werden von hier kopiert (und leicht modifiziert) (trinity)