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?
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
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)
Schnitzer
BaseTransactionFields
direkt 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 tunWeb3.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.