Browse Source

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

The MMGen Project 7 months ago
parent
commit
856058941c
5 changed files with 57 additions and 7 deletions
  1. 1 1
      mmgen/data/version
  2. 42 2
      mmgen/proto/eth/tx/base.py
  3. 3 1
      mmgen/proto/eth/tx/unsigned.py
  4. 1 0
      mmgen/tx/base.py
  5. 10 3
      mmgen/tx/completed.py

+ 1 - 1
mmgen/data/version

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

+ 42 - 2
mmgen/proto/eth/tx/base.py

@@ -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')

+ 3 - 1
mmgen/proto/eth/tx/unsigned.py

@@ -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

+ 1 - 0
mmgen/tx/base.py

@@ -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):

+ 10 - 3
mmgen/tx/completed.py

@@ -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()