Skip to content

Conversation

@codeflash-ai
Copy link

@codeflash-ai codeflash-ai bot commented Nov 5, 2025

📄 60% (0.60x) speedup for NewWalletWizard.on_have_cosigner_seed in electrum/wizard.py

⏱️ Runtime : 32.3 microseconds 20.2 microseconds (best of 39 runs)

📝 Explanation and details

The optimization achieves a 59% speedup by eliminating redundant function calls and reducing dictionary lookups in hot paths. Here are the key improvements:

Function Call Elimination: The original code made expensive function calls in needs_derivation_path() (calling current_cosigner()) and on_have_cosigner_seed() (calling both current_cosigner() and last_cosigner()). The optimized version inlines this logic directly, eliminating the function call overhead which was consuming 90.6% of execution time in needs_derivation_path().

Dictionary Access Optimization: The inlined logic reduces repeated dictionary lookups by storing intermediate values in local variables (e.g., cosigner_key = str(cosigner), required = wizard_data['multisig_participants'] - 1). This is particularly effective for the multisig workflow where the same keys are accessed multiple times.

Membership Testing Improvement: Changed the seed variant check from list ['bip39', 'slip39'] to tuple ('bip39', 'slip39') for slightly faster constant membership testing.

Control Flow Optimization: In last_cosigner(), reordered conditions to handle the common non-multisig case first, allowing faster early returns.

Performance Impact: The test results show consistent speedups across all scenarios (45-72% faster), with the largest gains in complex multisig workflows. Functions like on_have_cosigner_seed() that previously spent significant time in function calls (46.8% on current_cosigner(), 35.3% on needs_derivation_path()) now execute this logic inline, explaining the substantial performance improvement.

These optimizations are particularly valuable for wallet setup workflows involving multisig configurations, where these functions are called repeatedly during the wizard navigation process.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 39 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime
import pytest from electrum.wizard import NewWalletWizard class DummyPlugins: def load_plugin_by_name(self, name): pass def get_plugin(self, name): return None class DummyDaemon: pass # Fixtures for reuse in large scale tests @pytest.fixture def wizard(): return NewWalletWizard(DummyDaemon(), DummyPlugins()) # 1. Basic Test Cases def test_basic_last_cosigner_no_derivation_path(wizard): # Last cosigner, no derivation path needed wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 3.18μs -> 1.94μs (63.9% faster) def test_basic_not_last_cosigner_no_derivation_path(wizard): # Not last cosigner, no derivation path needed wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 3, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {}, '2': {}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.65μs -> 1.74μs (52.5% faster) def test_basic_needs_derivation_path_missing(wizard): # Needs derivation path, but missing in cosigner data wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {'seed_variant': 'bip39'}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 1.86μs -> 1.26μs (47.9% faster) def test_basic_needs_derivation_path_present(wizard): # Needs derivation path, present in cosigner data, last cosigner wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {'seed_variant': 'bip39', 'derivation_path': "m/44'/0'/0'/0"}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.67μs -> 1.59μs (67.8% faster) # 2. Edge Test Cases def test_edge_non_multisig_wallet(wizard): # Non-multisig wallet should always be last cosigner wizard_data = { 'wallet_type': 'standard' } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 1.41μs -> 846ns (66.1% faster) def test_edge_max_participants(wizard): # Maximum allowed participants (e.g., 15 for Electrum multisig) max_participants = 15 cosigner_data = {str(i): {} for i in range(1, max_participants)} wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': max_participants, 'multisig_current_cosigner': max_participants - 1, 'multisig_cosigner_data': cosigner_data } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 3.06μs -> 1.82μs (68.3% faster) def test_edge_missing_multisig_current_cosigner(wizard): # Missing multisig_current_cosigner, should fallback to root wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_cosigner_data': {'1': {}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 1.87μs -> 1.29μs (45.0% faster) def test_edge_seed_variant_slip39(wizard): # slip39 seed variant, missing derivation_path wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {'seed_variant': 'slip39'}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 1.98μs -> 1.30μs (51.6% faster) def test_edge_seed_variant_other(wizard): # Unknown seed_variant, should not trigger derivation_path logic wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 2, 'multisig_current_cosigner': 1, 'multisig_cosigner_data': {'1': {'seed_variant': 'electrum'}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.66μs -> 1.59μs (66.5% faster) def test_edge_derivation_path_present_not_last_cosigner(wizard): # Derivation path present, but not last cosigner wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': 4, 'multisig_current_cosigner': 2, 'multisig_cosigner_data': {'1': {'seed_variant': 'bip39', 'derivation_path': "m/44'/0'/0'/0"}, '2': {'seed_variant': 'bip39', 'derivation_path': "m/44'/0'/0'/1"}} } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.53μs -> 1.62μs (55.6% faster) # 3. Large Scale Test Cases def test_large_many_cosigners_last(wizard): # Large number of cosigners, last cosigner num_cosigners = 999 cosigner_data = {str(i): {'seed_variant': 'bip39', 'derivation_path': f"m/44'/0'/0'/{i}"} for i in range(1, num_cosigners)} wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': num_cosigners, 'multisig_current_cosigner': num_cosigners - 1, 'multisig_cosigner_data': cosigner_data } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 3.20μs -> 1.97μs (62.8% faster) def test_large_many_cosigners_missing_derivation_path(wizard): # Large number of cosigners, current cosigner missing derivation_path num_cosigners = 500 cosigner_data = {str(i): {'seed_variant': 'bip39', 'derivation_path': f"m/44'/0'/0'/{i}"} for i in range(1, num_cosigners)} # Remove derivation_path from current cosigner cosigner_data[str(num_cosigners-1)] = {'seed_variant': 'bip39'} wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': num_cosigners, 'multisig_current_cosigner': num_cosigners - 1, 'multisig_cosigner_data': cosigner_data } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.34μs -> 1.36μs (72.1% faster) def test_large_all_cosigners_no_seed_variant(wizard): # Large number of cosigners, none need derivation_path, last cosigner num_cosigners = 900 cosigner_data = {str(i): {} for i in range(1, num_cosigners)} wizard_data = { 'wallet_type': 'multisig', 'multisig_participants': num_cosigners, 'multisig_current_cosigner': num_cosigners - 1, 'multisig_cosigner_data': cosigner_data } codeflash_output = wizard.on_have_cosigner_seed(wizard_data); result = codeflash_output # 2.93μs -> 1.89μs (55.2% faster) #------------------------------------------------ import pytest from electrum.wizard import NewWalletWizard # The function to test (copied from above, simplified for test isolation) def on_have_cosigner_seed(wizard_data: dict) -> str: """  Determines the next step in the wizard after entering a cosigner's seed.  - If derivation path is needed and missing: go to script_and_derivation.  - If this is the last cosigner: go to wallet_password.  - Otherwise: go to cosigner_keystore.  """ def current_cosigner(wizard_data): wdata = wizard_data if wizard_data.get('wallet_type') == 'multisig' and 'multisig_current_cosigner' in wizard_data: cosigner = wizard_data['multisig_current_cosigner'] wdata = wizard_data['multisig_cosigner_data'][str(cosigner)] return wdata def needs_derivation_path(wizard_data): wdata = current_cosigner(wizard_data) return 'seed_variant' in wdata and wdata['seed_variant'] in ['bip39', 'slip39'] def is_multisig(wizard_data): return wizard_data.get('wallet_type') == 'multisig' def last_cosigner(wizard_data): if not is_multisig(wizard_data): return True # Participants: total number of cosigners required # multisig_cosigner_data: dict of cosigner data # If we have enough cosigners, return True if len(wizard_data.get('multisig_cosigner_data', {})) < (wizard_data.get('multisig_participants', 2) - 1): return False return True current = current_cosigner(wizard_data) if needs_derivation_path(wizard_data) and 'derivation_path' not in current: return 'multisig_cosigner_script_and_derivation' elif last_cosigner(wizard_data): return 'wallet_password' else: return 'multisig_cosigner_keystore' # ------------------- UNIT TESTS ------------------- # 1. Basic Test Cases #------------------------------------------------ from electrum.wizard import NewWalletWizard

To edit these changes git checkout codeflash/optimize-NewWalletWizard.on_have_cosigner_seed-mhlb4rb4 and push.

Codeflash Static Badge

The optimization achieves a **59% speedup** by eliminating redundant function calls and reducing dictionary lookups in hot paths. Here are the key improvements: **Function Call Elimination**: The original code made expensive function calls in `needs_derivation_path()` (calling `current_cosigner()`) and `on_have_cosigner_seed()` (calling both `current_cosigner()` and `last_cosigner()`). The optimized version inlines this logic directly, eliminating the function call overhead which was consuming 90.6% of execution time in `needs_derivation_path()`. **Dictionary Access Optimization**: The inlined logic reduces repeated dictionary lookups by storing intermediate values in local variables (e.g., `cosigner_key = str(cosigner)`, `required = wizard_data['multisig_participants'] - 1`). This is particularly effective for the multisig workflow where the same keys are accessed multiple times. **Membership Testing Improvement**: Changed the seed variant check from list `['bip39', 'slip39']` to tuple `('bip39', 'slip39')` for slightly faster constant membership testing. **Control Flow Optimization**: In `last_cosigner()`, reordered conditions to handle the common non-multisig case first, allowing faster early returns. **Performance Impact**: The test results show consistent speedups across all scenarios (45-72% faster), with the largest gains in complex multisig workflows. Functions like `on_have_cosigner_seed()` that previously spent significant time in function calls (46.8% on `current_cosigner()`, 35.3% on `needs_derivation_path()`) now execute this logic inline, explaining the substantial performance improvement. These optimizations are particularly valuable for wallet setup workflows involving multisig configurations, where these functions are called repeatedly during the wizard navigation process.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 5, 2025 01:16
@codeflash-ai codeflash-ai bot added ⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash labels Nov 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

⚡️ codeflash Optimization PR opened by Codeflash AI 🎯 Quality: Medium Optimization Quality according to Codeflash

1 participant