proto.eth.tx.base: check serialized data integrity

This commit is contained in:
The MMGen Project 2025-04-26 10:38:55 +00:00
commit 856058941c
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
5 changed files with 57 additions and 7 deletions

View file

@ -1 +1 @@
15.1.dev29
15.1.dev30

View file

@ -89,9 +89,49 @@ class Base(TxBase):
tx = tx,
rx = rx)
def check_serialized_integrity(self): # TODO
return True
def check_serialized_integrity(self):
if self.signed:
from .. import rlp
o = self.txobj
d = rlp.decode(bytes.fromhex(self.serialized))
to_key = 'token_addr' if self.is_token else 'to'
if o['nonce'] == 0:
assert d[0] == b'', f'{d[0]}: invalid nonce in serialized data'
else:
assert int(d[0].hex(), 16) == o['nonce'], f'{d[0]}: invalid nonce in serialized data'
if o.get(to_key):
assert d[3].hex() == o[to_key], f'{d[3].hex()}: invalid ‘to’ address in serialized data'
if not self.is_token:
if o['amt']:
assert int(d[4].hex(), 16) == o['amt'].to_unit('wei'), (
f'{d[4].hex()}: invalid amt in serialized data')
if self.is_swap:
assert d[5] == self.swap_memo.encode(), (
f'{d[5]}: invalid swap memo in serialized data')
class TokenBase(Base):
dfl_gas = 52000
contract_desc = 'token contract'
def check_serialized_integrity(self):
if self.signed:
super().check_serialized_integrity()
from .. import rlp
from ....amt import TokenAmt
d = rlp.decode(bytes.fromhex(self.serialized))
o = self.txobj
assert d[4] == b'', f'{d[4]}: non-empty amount field in token transaction in serialized data'
data = d[5].hex()
assert data[:8] == 'a9059cbb', (
f'{data[:8]}: invalid MethodID for op ‘transfer’ in serialized data')
assert data[32:72] == o['token_to'], (
f'{data[32:72]}: invalid ‘token_to‘ address in serialized data')
assert TokenAmt(
int(data[72:], 16),
decimals = o['decimals'],
from_unit = 'atomic') == o['amt'], (
f'{data[72:]}: invalid amt in serialized data')

View file

@ -94,7 +94,9 @@ class Unsigned(Completed, TxBase.Unsigned):
await self.do_sign(o, keys[0].sec.wif)
msg('OK')
from ....tx import SignedTX
return await SignedTX(cfg=self.cfg, data=self.__dict__, automount=self.automount)
tx = await SignedTX(cfg=self.cfg, data=self.__dict__, automount=self.automount)
tx.check_serialized_integrity()
return tx
except Exception as e:
msg(f'{e}: transaction signing failed!')
return False

View file

@ -123,6 +123,7 @@ class Base(MMGenObject):
self.name = type(self).__name__
self.proto = kwargs['proto']
self.twctl = kwargs.get('twctl')
self.is_token = 'Token' in self.name
@property
def coin(self):

View file

@ -31,9 +31,16 @@ class Completed(Base):
self.name = type(self).__name__
else:
from .file import MMGenTxFile
MMGenTxFile(self).parse(str(filename), quiet_open=quiet_open)
self.check_serialized_integrity()
try:
MMGenTxFile(self).parse(str(filename), quiet_open=quiet_open)
self.check_serialized_integrity()
except Exception as e:
from ..color import orange
from ..util import msg
msg(orange(
f'Something is wrong with transaction file ‘{filename}\n'
'To fix this problem, please move or delete the file'))
raise e
# repeat with sign and send, because coin daemon could be restarted
self.check_correct_chain()