Neither JS nor PY cares about extra fields on tranasction objects, see ethereum/go-ethereum#15628 for a scenario where this can lead to problems. Particularly if there is a field input
which is used in place of data
. Parity does not allow extra fields, Geth explicitly checks if input
is present, and of so, uses that as data
. If both are present, an error is prodiced.
// main chainid
> account.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1},"0x5384837ece911af85b8b2f2a0e6fe73f5f2add257fc25e1efbeebd4ee72226b7")
{ messageHash: '0xc1cdfb8128c3ca12f0448617d20222313b052291d2f2a1b1cc492b3994ebfd78',
v: '0x26',
r: '0x7b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79ea',
s: '0x35908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753',
rawTransaction: '0xf84b808082520880808026a07b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79eaa035908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753' }
>
# V is set to `0x26` == 38
//test chainid
account.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0,"chainId":14},"0x5384837ece911af85b8b2f2a0e6fe73f5f2add257fc25e1efbeebd4ee72226b7")
{ messageHash: '0xb28085cdc25f6ecd1a90f511f041d0b93d58af430f337da9072113dd0a5a7148',
v: '0x40',
r: '0x7a90a62179d39a7241af2212908dce6c89bc6f1da6bef93716d44e9dcc3bdace',
s: '0x91433fad2893a8f7d18f4daf2b0f8370f09d681e62d30016f995af9c4ca0a77',
rawTransaction: '0xf84b808082520880808040a07a90a62179d39a7241af2212908dce6c89bc6f1da6bef93716d44e9dcc3bdacea0091433fad2893a8f7d18f4daf2b0f8370f09d681e62d30016f995af9c4ca0a77' }
#JS uses `data`
> account.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1,"data":"0xff"},"0x5384837ece911af85b8b2f2a0e6fe73f5f2add257fc25e1efbeebd4ee72226b7")
{ messageHash: '0xa807646cb0d1811a3f4a8055d1137e12e0b21b0b1608e27ef54c4962406ab5e3',
v: '0x26',
r: '0x7d4824225b3ceff1bac6d2ad5a2fb71cdeb5681936b67ff33321e49dcf4fe94f',
s: '0x6c9835d05bed94b33f96b3eaba2e3f51666fa2fa5c3ef5fc6a199444a6d85605',
rawTransaction: '0xf84c8080825208808081ff26a07d4824225b3ceff1bac6d2ad5a2fb71cdeb5681936b67ff33321e49dcf4fe94fa06c9835d05bed94b33f96b3eaba2e3f51666fa2fa5c3ef5fc6a199444a6d85605' }
# JS silently ignores `input`
> account.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1,"input":"0xff"},"0x5384837ece911af85b8b2f2a0e6fe73f5f2add257fc25e1efbeebd4ee72226b7")
{ messageHash: '0xc1cdfb8128c3ca12f0448617d20222313b052291d2f2a1b1cc492b3994ebfd78',
v: '0x26',
r: '0x7b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79ea',
s: '0x35908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753',
rawTransaction: '0xf84b808082520880808026a07b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79eaa035908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753' }
# Requires the to-field to be set:
>>> la.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/src/app/web3/utils/signing.py", line 173, in signTransaction
return self._publicapi.signTransaction(transaction_dict, self.privateKey)
File "/usr/src/app/web3/utils/decorators.py", line 14, in _wrapper
return self.method(obj, *args, **kwargs)
File "/usr/src/app/web3/account.py", line 167, in signTransaction
) = sign_transaction_dict(account._key_obj, transaction_dict)
File "/usr/src/app/web3/utils/signing.py", line 28, in sign_transaction_dict
unsigned_transaction = serializable_unsigned_transaction_from_dict(web3, transaction_dict)
File "/usr/src/app/web3/utils/transactions.py", line 51, in serializable_unsigned_transaction_from_dict
return serializer.from_dict(filled_transaction)
File "/usr/src/app/web3/utils/encoding.py", line 276, in from_dict
return cls(**field_dict)
File "/usr/local/lib/python3.6/site-packages/rlp/sedes/lists.py", line 181, in __init__
raise TypeError('Not all fields initialized')
TypeError: Not all fields initialized
>>>
# V is set to `0x26` == 38
>>> la.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1,"to":""})
AttributeDict({'rawTransaction': HexBytes('0xf84b808082520880808026a07b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79eaa035908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753'), 'hash': HexBytes('0xdbe65aac443ad5f749939739ed752ab0280a0fd6a1ea0a00077a884957397ae8'), 'r': 55687118970470510547136965950997387526335795195977147650950269035342895675882, 's': 24227918541840761910366350430158278426875887423795240935429470879338619455315, 'v': 38})
# Py uses `data`
>>> la.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1,"to":"", "data":"0xff"})
AttributeDict({'rawTransaction': HexBytes('0xf84c8080825208808081ff26a07d4824225b3ceff1bac6d2ad5a2fb71cdeb5681936b67ff33321e49dcf4fe94fa06c9835d05bed94b33f96b3eaba2e3f51666fa2fa5c3ef5fc6a199444a6d85605'), 'hash': HexBytes('0x768b5c26b02591909a3047433e258065243d227c217bee694637361676d7b1ab'), 'r': 56666568450687500047565986506343001281974936404822881852058783468469162600783, 's': 49118719810745524668480418231531582400137060782954719179938068568634960664069, 'v': 38})
# Py silently ignores `input`
>>> la.signTransaction({'nonce':0, "value":0,"gas":21000,"gasPrice":0, "chainId":1,"to":"", "input":"0xff"})
AttributeDict({'rawTransaction': HexBytes('0xf84b808082520880808026a07b1dcad9fe49d3f88cd3c8bd76d8b9e6ef657da10310446f14dcb8a017aa79eaa035908414bccc859ecd4691c0c37dea7d72c71d44f4125051f12f9d54436fc753'), 'hash': HexBytes('0xdbe65aac443ad5f749939739ed752ab0280a0fd6a1ea0a00077a884957397ae8'), 'r': 55687118970470510547136965950997387526335795195977147650950269035342895675882, 's': 24227918541840761910366350430158278426875887423795240935429470879338619455315, 'v': 38})
Ah, it's because of prepending: https://github.com/ethereum/web3.js/blob/1.0/packages/web3-eth-accounts/src/index.js#L218