From 650f1902f8dcec35bb98f6dc9d9ff6e86065f217 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Wed, 9 Sep 2026 18:33:59 +0000 Subject: [PATCH] tx.completed: new `legacy_fmt_chk()` method See dd714815, 852cdeda Reject Ethereum transaction files with double-encoded serialized data as well. --- mmgen/autosign/__init__.py | 4 +++- mmgen/exception.py | 2 +- mmgen/proto/eth/tx/unsigned.py | 1 + mmgen/tx/completed.py | 17 +++++++++++++++++ mmgen/tx/file.py | 8 +------- test/cmdtest_d/autosign.py | 2 +- test/overlay/fakemods/mmgen/tx/completed.py | 9 +++++++++ 7 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 test/overlay/fakemods/mmgen/tx/completed.py diff --git a/mmgen/autosign/__init__.py b/mmgen/autosign/__init__.py index dbb3dbda..9bbf2838 100755 --- a/mmgen/autosign/__init__.py +++ b/mmgen/autosign/__init__.py @@ -272,7 +272,9 @@ class Autosign: except Exception as e: ymsg('An error occurred with {} ‘{}’:\n {}: ‘{}’'.format( target.desc, f.name, type(e).__name__, e)) - if type(e).__name__ == 'LegacyTxSignRequestError': + if type(e).__name__ == 'TxFileVersionError': + self.do_umount() + self.led.set('on') raise except: ymsg('An error occurred with {} ‘{}’'.format(target.desc, f.name)) diff --git a/mmgen/exception.py b/mmgen/exception.py index a409c795..8506e6c3 100755 --- a/mmgen/exception.py +++ b/mmgen/exception.py @@ -86,7 +86,7 @@ class WalletFileError(Exception): mmcode = 3 class HexadecimalStringError(Exception): mmcode = 3 class SeedLengthError(Exception): mmcode = 3 class PrivateKeyError(Exception): mmcode = 3 -class LegacyTxSignRequestError(Exception):mmcode = 3 +class TxFileVersionError(Exception): mmcode = 3 class MMGenCalledProcessError(Exception): mmcode = 3 class TestSuiteFatalException(Exception): mmcode = 3 diff --git a/mmgen/proto/eth/tx/unsigned.py b/mmgen/proto/eth/tx/unsigned.py index e2d1969c..46f4e6d8 100755 --- a/mmgen/proto/eth/tx/unsigned.py +++ b/mmgen/proto/eth/tx/unsigned.py @@ -30,6 +30,7 @@ class Unsigned(VmUnsigned, Completed, TxBase.Unsigned): if isinstance(self.serialized, dict): d = self.serialized else: + self.legacy_fmt_chk('double-encoded serialized data') d = json.loads(self.serialized) o = { diff --git a/mmgen/tx/completed.py b/mmgen/tx/completed.py index 0b15a4db..0c6a1127 100755 --- a/mmgen/tx/completed.py +++ b/mmgen/tx/completed.py @@ -12,6 +12,7 @@ tx.completed: completed transaction class """ +from ..cfg import gc from ..util import msg, ymsg, die from .base import Base @@ -102,9 +103,25 @@ class Completed(Base): if self.is_swap: raise ValueError('missing or invalid memo in swap transaction') + def die_on_version_error(self, errmsg): # overridden by test.overlay.fakemods + die('TxFileVersionError', errmsg) + + def legacy_fmt_chk(self, desc): + if 'sign' in gc.prog_name: + a, b = ('sign', 'Has your online installation been compromised?') + elif 'send' in gc.prog_name: + a, b = ('send', 'Is your offline installation out of date?') + else: + return + fs = f'Request to {{}} legacy-format transaction ({desc}). {{}}' + self.die_on_version_error(fs.format(a, b)) + class DummyCompleted: # required by MMGenTxFile.get_proto() desc = 'dummy transaction' def __init__(self, cfg): self.cfg = cfg + + die_on_version_error = Completed.die_on_version_error + legacy_fmt_chk = Completed.legacy_fmt_chk diff --git a/mmgen/tx/file.py b/mmgen/tx/file.py index 0ceec6b1..8e8421c1 100755 --- a/mmgen/tx/file.py +++ b/mmgen/tx/file.py @@ -22,7 +22,6 @@ tx.file: Transaction file operations for the MMGen suite import os, json -from ..cfg import gc from ..util import ymsg, make_chksum_6, die from ..obj import MMGenObject, HexStr, MMGenTxID, CoinTxID, MMGenTxComment @@ -134,12 +133,7 @@ class MMGenTxFile(MMGenObject): tx = self.tx tx.file_format = 'legacy' - if 'sign' in gc.prog_name: - m = 'Request to sign legacy-format transaction. Has your online installation been compromised?' - if tx.cfg.test_suite: - ymsg(m) - else: - die('LegacyTxSignRequestError', m) + tx.legacy_fmt_chk('non-JSON') def deserialize(raw_data, *, desc): from ast import literal_eval diff --git a/test/cmdtest_d/autosign.py b/test/cmdtest_d/autosign.py index da802602..990c5ded 100755 --- a/test/cmdtest_d/autosign.py +++ b/test/cmdtest_d/autosign.py @@ -930,7 +930,7 @@ class CmdTestAutosign(CmdTestAutosignBase): if exc_exit_val: return do_return() - t.expect('compromised') + t.expect('legacy-format') t.expect( f'{self.tx_count} {tx_desc}{suf(self.tx_count)} signed' if self.tx_count else diff --git a/test/overlay/fakemods/mmgen/tx/completed.py b/test/overlay/fakemods/mmgen/tx/completed.py new file mode 100644 index 00000000..30e5e2af --- /dev/null +++ b/test/overlay/fakemods/mmgen/tx/completed.py @@ -0,0 +1,9 @@ +from .completed_orig import * + +class overlay_fake_Completed(Completed): + + def die_on_version_error(self, errmsg): + ymsg(errmsg) + +Completed.die_on_version_error = overlay_fake_Completed.die_on_version_error +DummyCompleted.die_on_version_error = overlay_fake_Completed.die_on_version_error