Skip to content

Conversation

@codeflash-ai
Copy link

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

📄 22% (0.22x) speedup for digifinex.parse_deposit_address in python/ccxt/digifinex.py

⏱️ Runtime : 24.6 milliseconds 20.2 milliseconds (best of 50 runs)

📝 Explanation and details

The optimization achieves a 21% speedup by eliminating performance bottlenecks in frequently called utility methods that handle dictionary lookups.

Key Optimizations Applied

1. Micro-optimized safe_string method

  • Original: Used Exchange.key_exists() method call for every dictionary access, adding significant overhead
  • Optimized: Direct isinstance(dictionary, dict) check with dictionary.get(key, None) for fast path
  • Impact: Reduces method call overhead and eliminates expensive exception handling in key_exists

2. Micro-optimized safe_string_upper method

  • Original: Same Exchange.key_exists() bottleneck as safe_string
  • Optimized: Inline dictionary check with direct .get() access followed by .upper() conversion
  • Impact: Line profiler shows 33% reduction in time spent (from 12.1ms to 8.17ms)

3. Enhanced key_exists method

  • Original: Generic implementation with try/except for all collection types
  • Optimized: Fast path for dictionaries using key in dictionary check, avoiding exception handling
  • Impact: Though not directly profiled, this supports the fallback cases in the optimized safe methods

Why This Optimization Works

Dictionary Access Pattern: The profiled code shows heavy dictionary usage (21,630+ safe_string calls, 8,540+ safe_string_upper calls). The original code treated all collections generically, but dictionaries dominate the workload.

Method Call Elimination: By inlining the dictionary checks, we avoid the overhead of static method calls to Exchange.key_exists(), which was the primary bottleneck consuming 100% of time in safe_string.

Exception Handling Avoidance: The original key_exists used try/except for key lookups. The optimized version uses dict.get() and key in dict patterns that are significantly faster for the common case.

Test Case Performance

The optimization shows consistent 11-29% improvements across all test scenarios:

  • Basic cases: 11-17% faster (typical usage patterns)
  • Edge cases: 14-20% faster (missing fields, type conversions)
  • Large scale: 20-29% faster (batch processing scenarios)

This optimization is particularly effective for cryptocurrency exchange APIs where deposit address parsing happens frequently with dictionary-heavy data structures, making the micro-optimizations compound significantly across high-volume usage.

Correctness verification report:

Test Status
⚙️ Existing Unit Tests 🔘 None Found
🌀 Generated Regression Tests 8634 Passed
⏪ Replay Tests 🔘 None Found
🔎 Concolic Coverage Tests 🔘 None Found
📊 Tests Coverage 100.0%
🌀 Generated Regression Tests and Runtime

import pytest
from ccxt.digifinex import digifinex

unit tests

@pytest.fixture
def exchange():
return digifinex()

1. Basic Test Cases

def test_basic_eth_address(exchange):
# Typical ETH address with USDT, ERC20 chain, no tag
deposit = {
"addressTag": "",
"address": "0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.6μs -> 10.0μs (15.5% faster)

def test_basic_btc_address(exchange):
# Typical BTC address, no tag
deposit = {
"addressTag": "",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"currency": "BTC",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.7μs -> 9.96μs (17.3% faster)

def test_basic_with_tag(exchange):
# XRP address with tag
deposit = {
"addressTag": "123456",
"address": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
"currency": "XRP",
"chain": "XRP"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.3μs -> 9.82μs (14.8% faster)

def test_basic_currency_case_insensitive(exchange):
# Lowercase currency code should be uppercased
deposit = {
"addressTag": "",
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"currency": "btc",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.3μs -> 9.98μs (12.9% faster)

def test_basic_currency_common_code(exchange):
# Common currency code should be normalized
deposit = {
"addressTag": "",
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"currency": "XBT",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.2μs -> 10.1μs (11.1% faster)

2. Edge Test Cases

def test_missing_address_tag(exchange):
# addressTag missing
deposit = {
"address": "rDsbeomae4FXwgQTJp9Rs64Qg9vDiTCdBv",
"currency": "XRP",
"chain": "XRP"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.5μs -> 9.83μs (17.5% faster)

def test_missing_address_field(exchange):
# address missing
deposit = {
"addressTag": "123456",
"currency": "XRP",
"chain": "XRP"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.68μs (14.8% faster)

def test_missing_currency_field(exchange):
# currency missing
deposit = {
"addressTag": "",
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 9.82μs -> 8.57μs (14.5% faster)

def test_empty_fields(exchange):
# All fields empty strings
deposit = {
"addressTag": "",
"address": "",
"currency": "",
"chain": ""
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 9.37μs -> 8.45μs (10.8% faster)

def test_non_string_address(exchange):
# address is not a string, but an integer
deposit = {
"addressTag": "",
"address": 1234567890,
"currency": "BTC",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.7μs -> 10.0μs (16.9% faster)

def test_non_string_tag(exchange):
# addressTag is not a string, but None
deposit = {
"addressTag": None,
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"currency": "BTC",
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.5μs -> 9.60μs (19.8% faster)

def test_currency_is_number(exchange):
# currency is a number
deposit = {
"addressTag": "",
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"currency": 123,
"chain": "BTC"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.7μs -> 10.0μs (16.4% faster)

def test_extra_fields_ignored(exchange):
# depositAddress has extra fields
deposit = {
"addressTag": "",
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
"currency": "BTC",
"chain": "BTC",
"foo": "bar",
"baz": 42
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 11.4μs -> 9.83μs (16.3% faster)

def test_minimal_input(exchange):
# Only address field present
deposit = {
"address": "1BoatSLRHtKNngkdXEeobR76b53LETtpyT"
}
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 9.97μs -> 8.70μs (14.5% faster)

def test_none_input(exchange):
# depositAddress is None
codeflash_output = exchange.parse_deposit_address(None); result = codeflash_output # 8.73μs -> 8.70μs (0.299% faster)

def test_empty_dict_input(exchange):
# depositAddress is empty dict
codeflash_output = exchange.parse_deposit_address({}); result = codeflash_output # 9.90μs -> 8.42μs (17.6% faster)

def test_currency_code_normalization(exchange):
# currency code normalization for BCC and BCHSV
deposit1 = {"addressTag": "", "address": "addr", "currency": "BCC"}
deposit2 = {"addressTag": "", "address": "addr", "currency": "BCHSV"}
codeflash_output = exchange.parse_deposit_address(deposit1); result1 = codeflash_output # 11.1μs -> 10.1μs (9.90% faster)
codeflash_output = exchange.parse_deposit_address(deposit2); result2 = codeflash_output # 5.07μs -> 4.12μs (22.9% faster)

3. Large Scale Test Cases

def test_large_scale_batch(exchange):
# Test with a batch of 1000 addresses, all valid
batch = []
for i in range(1000):
batch.append({
"addressTag": str(i),
"address": f"addr_{i}",
"currency": "BTC",
"chain": "BTC"
})
# Ensure all are parsed correctly
for i, deposit in enumerate(batch):
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 3.09ms -> 2.52ms (22.9% faster)

def test_large_scale_mixed_missing(exchange):
# Batch with missing fields in half of the inputs
batch = []
for i in range(500):
batch.append({
"addressTag": str(i),
"address": f"addr_{i}",
"currency": "BTC"
})
for i in range(500, 1000):
batch.append({
"address": f"addr_{i}"
# missing addressTag and currency
})
# First 500 should have currency/tag, rest should not
for i, deposit in enumerate(batch):
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 2.90ms -> 2.35ms (23.2% faster)
if i < 500:
pass
else:
pass

def test_large_scale_varied_currencies(exchange):
# Test with 1000 addresses, cycling through known currency codes, including normalization
codes = ["BTC", "ETH", "USDT", "XBT", "BCC", "BCHSV", "DOGE"]
batch = []
for i in range(1000):
code = codes[i % len(codes)]
batch.append({
"addressTag": "",
"address": f"addr_{i}",
"currency": code
})
# Check normalization for XBT, BCC, BCHSV
for i, deposit in enumerate(batch):
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 3.04ms -> 2.53ms (20.2% faster)
code = deposit["currency"].upper()
if code == "XBT":
pass
elif code == "BCC":
pass
elif code == "BCHSV":
pass
else:
pass

def test_large_scale_empty_fields(exchange):
# 1000 addresses, all fields empty strings
batch = []
for i in range(1000):
batch.append({
"addressTag": "",
"address": "",
"currency": "",
"chain": ""
})
for deposit in batch:
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 2.50ms -> 2.18ms (14.5% faster)

def test_large_scale_none_fields(exchange):
# 1000 addresses, all fields None
batch = []
for i in range(1000):
batch.append({
"addressTag": None,
"address": None,
"currency": None,
"chain": None
})
for deposit in batch:
codeflash_output = exchange.parse_deposit_address(deposit); result = codeflash_output # 2.47ms -> 2.16ms (14.7% faster)

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

#------------------------------------------------
import pytest
from ccxt.digifinex import digifinex

unit tests

@pytest.fixture
def df():
# Create a digifinex instance for all tests
return digifinex()

-------------------------

1. BASIC TEST CASES

-------------------------

def test_basic_eth_address(df):
# Standard ETH address, no tag, USDT currency, ERC20 chain
deposit = {
"addressTag": "",
"address": "0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.4μs -> 9.91μs (14.8% faster)

def test_basic_btc_address(df):
# Standard BTC address, no tag, BTC currency
deposit = {
"addressTag": "",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"currency": "BTC",
"chain": "BTC"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.4μs -> 9.72μs (17.0% faster)

def test_basic_with_tag(df):
# XRP address with tag
deposit = {
"addressTag": "123456",
"address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
"currency": "XRP",
"chain": "XRP"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.2μs -> 9.84μs (13.6% faster)

def test_basic_currency_normalization(df):
# Test that XBT is normalized to BTC
deposit = {
"addressTag": "",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"currency": "XBT",
"chain": "BTC"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.3μs -> 9.89μs (13.9% faster)

def test_basic_currency_case_insensitivity(df):
# Lowercase currency should be uppercased and normalized
deposit = {
"addressTag": "",
"address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"currency": "xbt",
"chain": "BTC"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.95μs (11.5% faster)

-------------------------

2. EDGE TEST CASES

-------------------------

def test_missing_address(df):
# Missing address field
deposit = {
"addressTag": "",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.73μs (14.1% faster)

def test_missing_tag(df):
# Missing addressTag field
deposit = {
"address": "0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.74μs (14.1% faster)

def test_missing_currency(df):
# Missing currency field
deposit = {
"addressTag": "",
"address": "0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 9.98μs -> 8.73μs (14.3% faster)

def test_missing_all_fields(df):
# All fields missing
deposit = {}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 9.62μs -> 8.41μs (14.4% faster)

def test_extra_fields(df):
# Extra fields should be preserved in 'info'
deposit = {
"addressTag": "abc",
"address": "randomaddress",
"currency": "USDT",
"chain": "ERC20",
"extra": "should_be_ignored"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.0μs -> 9.86μs (11.9% faster)

def test_numeric_tag(df):
# Numeric tag should be converted to string
deposit = {
"addressTag": 789,
"address": "rEb8TK3gBgk5auZkwc6sHnwrGVJH8DuaLh",
"currency": "XRP",
"chain": "XRP"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.7μs -> 10.0μs (16.6% faster)

def test_currency_with_spaces(df):
# Currency with spaces should be uppercased and normalized
deposit = {
"addressTag": "",
"address": "address",
"currency": " xbt ",
"chain": "BTC"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.95μs (11.3% faster)

def test_tag_none(df):
# Explicit None tag
deposit = {
"addressTag": None,
"address": "address",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.3μs -> 9.86μs (14.8% faster)

def test_address_empty_string(df):
# Address is empty string
deposit = {
"addressTag": "",
"address": "",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.1μs -> 9.83μs (12.7% faster)

def test_tag_empty_string(df):
# Tag is empty string
deposit = {
"addressTag": "",
"address": "address",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.4μs -> 9.97μs (14.1% faster)

def test_currency_none(df):
# Currency is None
deposit = {
"addressTag": "",
"address": "address",
"currency": None,
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 9.58μs -> 8.55μs (12.1% faster)

def test_currency_empty_string(df):
# Currency is empty string
deposit = {
"addressTag": "",
"address": "address",
"currency": "",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 9.43μs -> 8.61μs (9.61% faster)

def test_tag_boolean(df):
# Tag is boolean True/False
deposit = {
"addressTag": True,
"address": "address",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.5μs -> 10.1μs (14.1% faster)

deposit["addressTag"] = False
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 5.11μs -> 4.32μs (18.3% faster)

def test_currency_numeric(df):
# Currency is numeric
deposit = {
"addressTag": "",
"address": "address",
"currency": 123,
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.6μs -> 9.93μs (17.3% faster)

def test_address_numeric(df):
# Address is numeric
deposit = {
"addressTag": "",
"address": 456789,
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 11.7μs -> 10.1μs (16.8% faster)

-------------------------

3. LARGE SCALE TEST CASES

-------------------------

def test_large_scale_unique_addresses(df):
# Test with 1000 unique addresses
for i in range(1000):
deposit = {
"addressTag": str(i),
"address": f"address_{i}",
"currency": "USDT",
"chain": "ERC20"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 3.08ms -> 2.50ms (23.1% faster)

def test_large_scale_varied_currencies(df):
# Test with 500 different currencies, including normalization
currencies = ['BTC', 'ETH', 'XBT', 'BCHSV', 'USDT', 'TRX', 'LTC', 'DOGE', 'XRP', 'BNB']
for i in range(500):
currency = currencies[i % len(currencies)]
deposit = {
"addressTag": "",
"address": f"addr_{currency}_{i}",
"currency": currency,
"chain": "CHAIN"
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 1.53ms -> 1.27ms (21.2% faster)
# Normalization for XBT->BTC, BCHSV->BSV
expected = {'XBT': 'BTC', 'BCHSV': 'BSV'}.get(currency, currency)

def test_large_scale_missing_fields(df):
# Test with 1000 deposits missing different fields
for i in range(1000):
deposit = {}
if i % 3 == 0:
deposit['address'] = f"address_{i}"
if i % 5 == 0:
deposit['addressTag'] = f"tag_{i}"
if i % 7 == 0:
deposit['currency'] = "BTC"
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 2.85ms -> 2.24ms (27.5% faster)
expected_address = deposit.get('address', None)
expected_tag = deposit.get('addressTag', None)
expected_currency = None
if 'currency' in deposit:
expected_currency = 'BTC'

def test_large_scale_all_empty(df):
# Test with 1000 empty dicts
for _ in range(1000):
deposit = {}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 2.75ms -> 2.13ms (29.2% faster)

def test_large_scale_long_strings(df):
# Test with long address/tag/currency strings
long_str = "a" * 500
deposit = {
"addressTag": long_str,
"address": long_str,
"currency": long_str,
"chain": long_str
}
codeflash_output = df.parse_deposit_address(deposit); result = codeflash_output # 12.2μs -> 10.9μs (11.9% faster)

codeflash_output is used to check that the output of the original code is the same as that of the optimized code.

To edit these changes git checkout codeflash/optimize-digifinex.parse_deposit_address-mhu1k73z and push.

Codeflash

The optimization achieves a **21% speedup** by eliminating performance bottlenecks in frequently called utility methods that handle dictionary lookups.

## Key Optimizations Applied

**1. Micro-optimized `safe_string` method**
- **Original**: Used `Exchange.key_exists()` method call for every dictionary access, adding significant overhead
- **Optimized**: Direct `isinstance(dictionary, dict)` check with `dictionary.get(key, None)` for fast path
- **Impact**: Reduces method call overhead and eliminates expensive exception handling in `key_exists`

**2. Micro-optimized `safe_string_upper` method**
- **Original**: Same `Exchange.key_exists()` bottleneck as `safe_string`
- **Optimized**: Inline dictionary check with direct `.get()` access followed by `.upper()` conversion
- **Impact**: Line profiler shows 33% reduction in time spent (from 12.1ms to 8.17ms)

**3. Enhanced `key_exists` method** 
- **Original**: Generic implementation with `try/except` for all collection types
- **Optimized**: Fast path for dictionaries using `key in dictionary` check, avoiding exception handling
- **Impact**: Though not directly profiled, this supports the fallback cases in the optimized safe methods

## Why This Optimization Works

**Dictionary Access Pattern**: The profiled code shows heavy dictionary usage (21,630+ `safe_string` calls, 8,540+ `safe_string_upper` calls). The original code treated all collections generically, but dictionaries dominate the workload.

**Method Call Elimination**: By inlining the dictionary checks, we avoid the overhead of static method calls to `Exchange.key_exists()`, which was the primary bottleneck consuming 100% of time in `safe_string`.

**Exception Handling Avoidance**: The original `key_exists` used try/except for key lookups. The optimized version uses `dict.get()` and `key in dict` patterns that are significantly faster for the common case.

## Test Case Performance

The optimization shows consistent **11-29% improvements** across all test scenarios:
- **Basic cases**: 11-17% faster (typical usage patterns)
- **Edge cases**: 14-20% faster (missing fields, type conversions)  
- **Large scale**: 20-29% faster (batch processing scenarios)

This optimization is particularly effective for cryptocurrency exchange APIs where deposit address parsing happens frequently with dictionary-heavy data structures, making the micro-optimizations compound significantly across high-volume usage.
@codeflash-ai codeflash-ai bot requested a review from mashraf-222 November 11, 2025 03:58
@codeflash-ai codeflash-ai bot added the ⚡️ codeflash Optimization PR opened by Codeflash AI label Nov 11, 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant