Raw-Transaction
為交易數據序列化字節數組
我已經從 python 2 升級到 python 3,一些以前可以工作的程式碼現在被破壞了。我似乎無法修復它。有什麼建議麼?
在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}
相同的程式碼在 python 3 中不起作用,請注意字節數組數據類型已更改為
<class 'bytearray'> # python 3 produces this from bytearray.fromhex <type 'bytearray'> # python 2 produces this from bytearray.fromhex
我收到以下錯誤:
{'error': True, 'message': ObjectSerializationError('Serialization failed because of field data ("Object is not a serializable (<class \'bytearray\'>)")',)}
我嘗試使用 pickle 序列化輸出,但又遇到了另一個錯誤:
import pickle data_bytearray = pickle.dumps(data_bytearray) {'error': True, 'message': AttributeError("'bytes' object has no attribute 'encode'",)}
我在這裡做錯了什麼?
解決方案:
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}
解決方案
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}
唯一顯著的變化是從
raw_transaction.encode('hex')
到Web3.toHex(raw_transaction)
。與原始行的其他區別只是減少了每行的邏輯量。
為什麼?
bytes 和 Web3.toBytes 都給了我與 pickle.dumps 類似的錯誤:
{'error': True, 'message': AttributeError("'bytes' object has no attribute 'encode'",)}
這個 ^ 評論是最有幫助的,雖然它沒有解釋為什麼你沒有得到同樣的錯誤
bytearray
(我認為你應該)。看: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'
這與乙太坊沒有任何關係,只是學習如何在 Python 3 中進行編碼和酸洗。例如,我希望以下內容的行為與問題中的第一個程式碼範例完全相同:
try: return {'error': False, 'sign': bytearray(b'\xaf').encode('hex')} except Exception as msg: return {'error': True, 'message': msg}
Python 2 中的編碼有一個草率的 API,並且允許人們做一些無意義的事情,比如“編碼”二進制數據(已經編碼,是二進制的)。因此,
encode()
完全從 Python 3bytes
類型中刪除。如果你想bytes
在 Python 3 中轉換為十六進制,有幾種方法可以做到:我個人最喜歡的選擇
> Web3.toHex(b'\xaf') '0xaf'
或者,在 Python 3.5+ 中,您可以使用:
> b'\xaf'.hex() 'af' # note that you don't get the "0x" prefix
另一個內置選項是 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'
(所有這些都
Web3
可以使用bytearray
)。