What changed, and why it matters
This commit only adds and updates automated tests for restoring an old Electrum wallet from either its word seed or its equivalent hex seed. It also adds a small clarifying comment to a helper function. There is no change to production wallet logic, no bug fix, and no security-relevant behavior change.
No action required; this is a test-only change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff extends test coverage in tests/test_wallet_vertical.py and tests/test_wizard.py to verify that an ‘old’ Electrum seed can be restored both from its mnemonic phrase and from its raw hex representation, producing the same master public key, addresses, and normalized seed. It adds a docstring to Old_KeyStore.format_seed() in electrum/keystore.py. No cryptographic or keystore code paths are modified.
Changed components
tests/test_wallet_vertical.pytests/test_wizard.pyelectrum/keystore.py (docstring only)Inspect captured patch +44 / −11
diff --git a/electrum/keystore.py b/electrum/keystore.py
index 65c4ec3..b7f39c1 100644
--- a/electrum/keystore.py
+++ b/electrum/keystore.py
@@ -757,6 +757,10 @@ class Old_KeyStore(MasterPublicKeyMixin, Deterministic_KeyStore):
self.mpk = mpk
def format_seed(self, seed):
+ """Returns seed in hex format.
+
+ seed: either in hex or as mnemonic words
+ """
from . import old_mnemonic, mnemonic
seed = mnemonic.normalize_text(seed)
# see if seed was entered as hex
diff --git a/tests/test_wallet_vertical.py b/tests/test_wallet_vertical.py
index ffe737a..c1c73dc 100644
--- a/tests/test_wallet_vertical.py
+++ b/tests/test_wallet_vertical.py
@@ -175,20 +175,27 @@ class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase):
@mock.patch.object(wallet.Abstract_Wallet, 'save_db')
async def test_electrum_seed_old(self, mock_save_db):
seed_words = 'powerful random nobody notice nothing important anyway look away hidden message over'
- self.assertEqual(calc_seed_type(seed_words), 'old')
+ seed_hex = 'acb740e454c3134901d7c8f16497cc1c'
- ks = keystore.from_seed(seed_words, passphrase='', for_multisig=False)
+ for seed_to_restore_from in (seed_words, seed_hex):
+ with self.subTest(seed_to_restore_from=seed_to_restore_from):
+ self.assertEqual(calc_seed_type(seed_to_restore_from), 'old')
- WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
- self.assertTrue(isinstance(ks, keystore.Old_KeyStore))
+ ks = keystore.from_seed(seed_to_restore_from, passphrase='', for_multisig=False)
- self.assertEqual(ks.mpk, 'e9d4b7866dd1e91c862aebf62a49548c7dbf7bcc6e4b7b8c9da820c7737968df9c09d5a3e271dc814a29981f81b3faaf2737b551ef5dcc6189cf0f8252c442b3')
+ WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
+ self.assertTrue(isinstance(ks, keystore.Old_KeyStore))
- w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
- self.assertEqual(w.txin_type, 'p2pkh')
+ self.assertEqual(ks.mpk, 'e9d4b7866dd1e91c862aebf62a49548c7dbf7bcc6e4b7b8c9da820c7737968df9c09d5a3e271dc814a29981f81b3faaf2737b551ef5dcc6189cf0f8252c442b3')
+ self.assertEqual(ks.seed, seed_hex)
+ self.assertEqual(ks._get_hex_seed(password=None), seed_hex)
+ self.assertEqual(ks.get_seed(password=None), seed_words)
+
+ w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
+ self.assertEqual(w.txin_type, 'p2pkh')
- self.assertEqual(w.get_receiving_addresses()[0], '1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo')
- self.assertEqual(w.get_change_addresses()[0], '1KRW8pH6HFHZh889VDq6fEKvmrsmApwNfe')
+ self.assertEqual(w.get_receiving_addresses()[0], '1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo')
+ self.assertEqual(w.get_change_addresses()[0], '1KRW8pH6HFHZh889VDq6fEKvmrsmApwNfe')
@mock.patch.object(wallet.Abstract_Wallet, 'save_db')
async def test_electrum_seed_2fa_legacy_pre27_25words(self, mock_save_db):
diff --git a/tests/test_wizard.py b/tests/test_wizard.py
index a758377..6bbab88 100644
--- a/tests/test_wizard.py
+++ b/tests/test_wizard.py
@@ -7,7 +7,7 @@ from electrum.network import NetworkParameters, ProxySettings
from electrum.plugin import Plugins, DeviceInfo, Device
from electrum.wizard import ServerConnectWizard, NewWalletWizard, WizardViewState, KeystoreWizard
from electrum.daemon import Daemon
-from electrum.wallet import Abstract_Wallet
+from electrum.wallet import Abstract_Wallet, Deterministic_Wallet
from electrum import util
from electrum import slip39
from electrum.bip32 import KeyOriginInfo
@@ -584,7 +584,29 @@ class WalletWizardTestCase(WizardTestCase):
'seed': 'powerful random nobody notice nothing important anyway look away hidden message over',
'seed_type': 'old', 'seed_extend': False, 'seed_variant': 'electrum'})
v = w.resolve_next(v.view, d)
- self._set_password_and_check_address(v=v, w=w, recv_addr="1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo")
+ wallet = self._set_password_and_check_address(v=v, w=w, recv_addr="1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo")
+
+ self.assertIsInstance(wallet, Deterministic_Wallet)
+ self.assertEqual(wallet.get_seed(password=None), 'powerful random nobody notice nothing important anyway look away hidden message over')
+
+ async def test_create_standard_wallet_haveseed_electrum_oldseed_in_hex_format(self):
+ w = self._wizard_for(wallet_type='standard')
+ v = w._current
+ d = v.wizard_data
+ self.assertEqual('keystore_type', v.view)
+
+ d.update({'keystore_type': 'haveseed'})
+ v = w.resolve_next(v.view, d)
+ self.assertEqual('have_seed', v.view)
+
+ d.update({
+ 'seed': 'acb740e454c3134901d7c8f16497cc1c',
+ 'seed_type': 'old', 'seed_extend': False, 'seed_variant': 'electrum'})
+ v = w.resolve_next(v.view, d)
+ wallet = self._set_password_and_check_address(v=v, w=w, recv_addr="1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo")
+
+ self.assertIsInstance(wallet, Deterministic_Wallet)
+ self.assertEqual(wallet.get_seed(password=None), 'powerful random nobody notice nothing important anyway look away hidden message over')
async def test_create_standard_wallet_haveseed_electrum_oldseed_passphrase(self):
w = self._wizard_for(wallet_type='standard')
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.