2020-08-08 10:45:37 +02:00
|
|
|
# standard imports
|
2020-08-04 23:41:31 +02:00
|
|
|
import logging
|
|
|
|
import binascii
|
2021-03-27 15:32:05 +01:00
|
|
|
import re
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2021-03-22 18:42:56 +01:00
|
|
|
# external imports
|
2021-04-11 15:09:16 +02:00
|
|
|
#from rlp import encode as rlp_encode
|
2021-03-22 18:42:56 +01:00
|
|
|
from hexathon import (
|
|
|
|
strip_0x,
|
|
|
|
add_0x,
|
2021-03-27 15:32:05 +01:00
|
|
|
int_to_minbytes,
|
2021-03-22 18:42:56 +01:00
|
|
|
)
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
# local imports
|
|
|
|
from crypto_dev_signer.eth.encoding import chain_id_to_v
|
2021-04-11 15:09:16 +02:00
|
|
|
from crypto_dev_signer.eth.rlp import rlp_encode
|
2021-03-27 15:32:05 +01:00
|
|
|
|
|
|
|
logg = logging.getLogger().getChild(__name__)
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2020-08-08 10:45:37 +02:00
|
|
|
|
2020-08-04 23:41:31 +02:00
|
|
|
class Transaction:
|
2020-08-06 11:07:18 +02:00
|
|
|
|
|
|
|
def rlp_serialize(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def serialize(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class EIP155Transaction:
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
def __init__(self, tx, nonce_in, chainId_in=1):
|
|
|
|
to = b''
|
|
|
|
data = b''
|
|
|
|
if tx.get('to') != None:
|
2021-03-26 13:08:36 +01:00
|
|
|
to = bytes.fromhex(strip_0x(tx['to'], allow_empty=True))
|
2021-03-27 15:32:05 +01:00
|
|
|
if tx.get('data') != None:
|
2021-03-26 13:08:36 +01:00
|
|
|
data = bytes.fromhex(strip_0x(tx['data'], allow_empty=True))
|
2020-08-04 23:41:31 +02:00
|
|
|
|
2020-10-26 09:02:29 +01:00
|
|
|
gas_price = None
|
|
|
|
start_gas = None
|
|
|
|
value = None
|
2021-03-27 15:32:05 +01:00
|
|
|
nonce = None
|
|
|
|
chainId = None
|
2020-10-26 09:02:29 +01:00
|
|
|
|
2021-03-27 15:32:05 +01:00
|
|
|
# TODO: go directly from hex to bytes
|
2020-10-26 09:02:29 +01:00
|
|
|
try:
|
|
|
|
gas_price = int(tx['gasPrice'])
|
2021-03-27 15:32:05 +01:00
|
|
|
byts = ((gas_price.bit_length()-1)/8)+1
|
|
|
|
gas_price = gas_price.to_bytes(int(byts), 'big')
|
2020-10-26 09:02:29 +01:00
|
|
|
except ValueError:
|
2021-03-27 15:32:05 +01:00
|
|
|
gas_price = bytes.fromhex(strip_0x(tx['gasPrice'], allow_empty=True))
|
2020-10-26 09:02:29 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
start_gas = int(tx['gas'])
|
2021-03-27 15:32:05 +01:00
|
|
|
byts = ((start_gas.bit_length()-1)/8)+1
|
|
|
|
start_gas = start_gas.to_bytes(int(byts), 'big')
|
2020-10-26 09:02:29 +01:00
|
|
|
except ValueError:
|
2021-03-27 15:32:05 +01:00
|
|
|
start_gas = bytes.fromhex(strip_0x(tx['gas'], allow_empty=True))
|
2020-10-26 09:02:29 +01:00
|
|
|
|
|
|
|
try:
|
|
|
|
value = int(tx['value'])
|
2021-03-27 15:32:05 +01:00
|
|
|
byts = ((value.bit_length()-1)/8)+1
|
|
|
|
value = value.to_bytes(int(byts), 'big')
|
2020-10-26 09:02:29 +01:00
|
|
|
except ValueError:
|
2021-03-27 15:32:05 +01:00
|
|
|
value = bytes.fromhex(strip_0x(tx['value'], allow_empty=True))
|
2020-10-26 09:02:29 +01:00
|
|
|
|
|
|
|
try:
|
2021-03-27 15:32:05 +01:00
|
|
|
nonce = int(nonce_in)
|
|
|
|
byts = ((nonce.bit_length()-1)/8)+1
|
|
|
|
nonce = nonce.to_bytes(int(byts), 'big')
|
2020-10-26 09:02:29 +01:00
|
|
|
except ValueError:
|
2021-03-27 15:32:05 +01:00
|
|
|
nonce = bytes.fromhex(strip_0x(nonce_in, allow_empty=True))
|
2021-01-12 14:50:52 +01:00
|
|
|
|
|
|
|
try:
|
2021-03-27 15:32:05 +01:00
|
|
|
chainId = int(chainId_in)
|
|
|
|
byts = ((chainId.bit_length()-1)/8)+1
|
|
|
|
chainId = chainId.to_bytes(int(byts), 'big')
|
2021-01-12 14:50:52 +01:00
|
|
|
except ValueError:
|
2021-03-27 15:32:05 +01:00
|
|
|
chainId = bytes.fromhex(strip_0x(chainId_in, allow_empty=True))
|
2020-10-26 09:02:29 +01:00
|
|
|
|
2020-08-04 23:41:31 +02:00
|
|
|
self.nonce = nonce
|
2020-10-26 09:02:29 +01:00
|
|
|
self.gas_price = gas_price
|
|
|
|
self.start_gas = start_gas
|
2020-08-04 23:41:31 +02:00
|
|
|
self.to = to
|
2020-10-26 09:02:29 +01:00
|
|
|
self.value = value
|
2020-08-04 23:41:31 +02:00
|
|
|
self.data = data
|
|
|
|
self.v = chainId
|
2020-08-06 11:07:18 +02:00
|
|
|
self.r = b''
|
|
|
|
self.s = b''
|
2021-03-22 18:42:56 +01:00
|
|
|
self.sender = strip_0x(tx['from'])
|
2020-08-04 23:41:31 +02:00
|
|
|
|
|
|
|
|
2021-03-03 18:10:15 +01:00
|
|
|
def __canonical_order(self):
|
2020-08-04 23:41:31 +02:00
|
|
|
s = [
|
|
|
|
self.nonce,
|
|
|
|
self.gas_price,
|
|
|
|
self.start_gas,
|
|
|
|
self.to,
|
|
|
|
self.value,
|
|
|
|
self.data,
|
|
|
|
self.v,
|
|
|
|
self.r,
|
|
|
|
self.s,
|
|
|
|
]
|
2021-03-03 18:10:15 +01:00
|
|
|
|
|
|
|
return s
|
|
|
|
|
2021-03-22 18:42:56 +01:00
|
|
|
|
2021-03-03 18:10:15 +01:00
|
|
|
def bytes_serialize(self):
|
|
|
|
s = self.__canonical_order()
|
|
|
|
b = b''
|
|
|
|
for e in s:
|
|
|
|
b += e
|
|
|
|
return b
|
|
|
|
|
|
|
|
|
|
|
|
def rlp_serialize(self):
|
|
|
|
s = self.__canonical_order()
|
2020-08-04 23:41:31 +02:00
|
|
|
return rlp_encode(s)
|
2020-08-05 22:00:23 +02:00
|
|
|
|
2021-03-03 18:10:15 +01:00
|
|
|
|
2020-08-05 22:00:23 +02:00
|
|
|
def serialize(self):
|
2021-01-12 14:50:52 +01:00
|
|
|
tx = {
|
2021-03-22 18:42:56 +01:00
|
|
|
'nonce': add_0x(self.nonce.hex(), allow_empty=True),
|
|
|
|
'gasPrice': add_0x(self.gas_price.hex()),
|
|
|
|
'gas': add_0x(self.start_gas.hex()),
|
|
|
|
'to': add_0x(self.to.hex()),
|
|
|
|
'value': add_0x(self.value.hex(), allow_empty=True),
|
2021-03-27 15:32:05 +01:00
|
|
|
'data': add_0x(self.data.hex(), allow_empty=True),
|
2021-03-22 18:42:56 +01:00
|
|
|
'v': add_0x(self.v.hex(), allow_empty=True),
|
|
|
|
'r': add_0x(self.r.hex(), allow_empty=True),
|
|
|
|
's': add_0x(self.s.hex(), allow_empty=True),
|
2020-08-05 22:00:23 +02:00
|
|
|
}
|
2021-01-12 14:50:52 +01:00
|
|
|
if tx['data'] == '':
|
|
|
|
tx['data'] = '0x'
|
|
|
|
|
|
|
|
if tx['value'] == '':
|
|
|
|
tx['value'] = '0x00'
|
|
|
|
|
|
|
|
if tx['nonce'] == '':
|
|
|
|
tx['nonce'] = '0x00'
|
|
|
|
|
|
|
|
return tx
|
2021-03-27 15:32:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
def apply_signature(self, chain_id, signature):
|
|
|
|
if len(self.r + self.s) > 0:
|
|
|
|
raise AttributeError('signature already set')
|
|
|
|
if len(signature) < 65:
|
|
|
|
raise ValueError('invalid signature length')
|
|
|
|
v = chain_id_to_v(chain_id, signature)
|
|
|
|
self.v = int_to_minbytes(v)
|
|
|
|
self.r = signature[:32]
|
|
|
|
self.s = signature[32:64]
|
|
|
|
|
|
|
|
for i in range(len(self.r)):
|
|
|
|
if self.r[i] > 0:
|
|
|
|
self.r = self.r[i:]
|
|
|
|
break
|
|
|
|
|
|
|
|
for i in range(len(self.s)):
|
|
|
|
if self.s[i] > 0:
|
|
|
|
self.s = self.s[i:]
|
|
|
|
break
|