Raw-Transaction

為交易數據序列化字節數組

  • March 2, 2018

我已經從 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)。

引用自:https://ethereum.stackexchange.com/questions/40849