Serialisierendes Byte-Array für Transaktionsdaten

Ich habe von Python 2 auf Python 3 aktualisiert und einige Codes, die früher funktionierten, sind jetzt kaputt. Ich kann es anscheinend nicht reparieren. Irgendwelche Vorschläge?

Arbeitete in Python 2

# Convert hex string to byte array
hex_string = "0x00012345...."
data_bytearray = bytearray.fromhex(hex_string.replace("0x", ""))

# Then I pass data_bytearray into transactions.Transaction and it works.  
try:
    return {'error': False, 'sign': rlp.encode(transactions.Transaction(nonce, gasPrice_int, gas_int, to, value, data_bytearray).sign(privkey)).encode('hex')}
except Exception as msg:
    return {'error': True, 'message': msg}

Derselbe Code funktioniert nicht in Python 3 und beachten Sie, dass sich der Datentyp des Byte-Arrays in geändert hat

<class 'bytearray'>   # python 3 produces this from bytearray.fromhex
<type 'bytearray'>    # python 2 produces this from bytearray.fromhex

Ich bekomme folgenden Fehler:

{'error': True, 'message': ObjectSerializationError('Serialization failed because of field data ("Object is not a serializable (<class \'bytearray\'>)")',)}

Ich habe versucht, die Ausgabe mit Pickle zu serialisieren, habe aber einen anderen Fehler erhalten:

import pickle
data_bytearray = pickle.dumps(data_bytearray)

{'error': True, 'message': AttributeError("'bytes' object has no attribute 'encode'",)}

Was mache ich hier falsch?

Lösung:

try:
    data_hex_with0xRemoved = data_hex.replace("0x", "")
    # If I use bytearray.fromhex, it results in {'error': True, 'message': ObjectSerializationError('Serialization failed because of field data ("Object is not a serializable (<class \'bytearray\'>)")',)}
    # data = bytearray.fromhex('deadbeef')
    # So instead I use bytes.fromhex
    data = bytes.fromhex(data_hex_with0xRemoved)
    unsigned_transaction = transactions.Transaction(nonce, gasPrice_int, gas_int, to, value, data)
    raw_transaction_bytes = rlp.encode(unsigned_transaction.sign(privkey))
    raw_transaction_hex = Web3.toHex(raw_transaction_bytes)
    raw_transaction_hex_0xRemoved = raw_transaction_hex.replace("0x", "")
    return {'error': False, 'sign': raw_transaction_hex_0xRemoved}
except Exception as msg:
    return {'error': True, 'message': msg}
Hast du es bytesstattdessen versucht bytearray? Außerdem könnte Ihnen gefallen: data_bytes = Web3.toBytes(hexstr="0x00012345")from web3.py
Ja, sowohl Bytes als auch Web3.toBytes gaben mir einen ähnlichen Fehler wie pickle.dumps: {'error': True, 'message': AttributeError("'bytes' object has no attribute 'encode'")}.
Dies ist nicht wirklich eine Lösung, aber Sie könnten ein py2-Skript aufrufen, das diese Operation ausführt und den Wert an das py3-Skript zurückgibt. Ich bin auf das gleiche Problem gestoßen und hatte zu viele wichtigere Schlachten zu wählen, also habe ich die schnelle Problemumgehung genommen, die es mir ermöglichte, mich wichtigeren Dingen zuzuwenden. Ich bin auch gespannt, wie man das richtig macht.

Antworten (1)

Lösung

try:
    unsigned_transaction = transactions.Transaction(nonce, gasPrice_int, gas_int, to, value, data_bytearray)
    raw_transaction = rlp.encode(unsigned_transaction.sign(privkey))
    return {'error': False, 'sign': Web3.toHex(raw_transaction)}
except Exception as msg:
    return {'error': True, 'message': msg}

Die einzige bemerkenswerte Änderung ist von raw_transaction.encode('hex')zu Web3.toHex(raw_transaction).

Die anderen Unterschiede zur ursprünglichen Zeile bestanden lediglich darin, die Menge an Logik pro Zeile zu reduzieren.


Warum?

Sowohl Bytes als auch Web3.toBytes gaben mir einen ähnlichen Fehler wie pickle.dumps:{'error': True, 'message': AttributeError("'bytes' object has no attribute 'encode'",)}

Dieser ^-Kommentar war am hilfreichsten, obwohl er nicht erklärt, warum Sie nicht denselben Fehler mit bytearray(ich denke, Sie sollten) erhalten. Sehen:

In [1]: b'\xaf'.encode('hex')
AttributeError: 'bytes' object has no attribute 'encode'

In [2]: bytearray(b'\xaf').encode('hex')
AttributeError: 'bytearray' object has no attribute 'encode'

Das hat nicht wirklich etwas mit Ethereum zu tun, sondern nur damit, zu lernen, wie das Codieren und Beizen in Python 3 funktioniert. Ich würde beispielsweise erwarten, dass sich Folgendes genau so verhält wie das erste Codebeispiel aus der Frage:

try:
    return {'error': False, 'sign': bytearray(b'\xaf').encode('hex')}
except Exception as msg:
    return {'error': True, 'message': msg}

Die Codierung in Python 2 hatte eine schlampige API und erlaubte es den Leuten, unsinnige Dinge zu tun, wie z. B. Binärdaten zu „codieren“ (die bereits codiert sind, also binär sind). Also, encode()wurde ganz aus dem bytesTyp Python 3 entfernt. Wenn Sie in Python 3 in Hex konvertieren möchten bytes, gibt es einige Möglichkeiten, dies zu tun:

Meine persönliche Lieblingsvariante

> Web3.toHex(b'\xaf')
'0xaf'

Alternativ können Sie in Python 3.5+ Folgendes verwenden:

> b'\xaf'.hex()
'af'
# note that you don't get the "0x" prefix

Eine weitere integrierte Option ist binascii

> import binascii
> hex_in_bytes = binascii.hexlify(b'\xaf')
b'af'

# binascii made the nonsensical choice to return the hex value in a `bytes` type
# which you can fix up by decoding to a string

> hex_in_bytes.decode('utf8')
'af'

(Alle außer Web3funktionieren bytearrayauch mit).

Sie hatten Recht, die Probleme, auf die ich stieß, hingen alle mit meinen Missverständnissen in Bezug auf Python 3 und nicht auf Ethereum zusammen. Danke, dass du das für mich aufgeschlüsselt hast. Ich habe den endgültigen Code, mit dem ich oben gegangen bin, gepostet. Am Ende musste ich aus dem oben aufgeführten Grund bytes.fromhex anstelle von bytearray.fromhex verwenden.
Verstanden, das könnte dir auch gefallen data = Web3.toBytes(hexstr=data_hex).