From 16270bfd4933c84afdde3f9d6fc0d7ffb07e74f3 Mon Sep 17 00:00:00 2001 From: "codeflash-ai[bot]" <148906541+codeflash-ai[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 07:48:22 +0000 Subject: [PATCH] Optimize TxInput.to_json The optimization targets the `witness_elements()` method, which is called from the hot path in `to_json()` when processing witness data. The key performance improvements are: **What was optimized:** 1. **Pre-allocated list instead of generator comprehension**: Replaced `list(vds.read_bytes(vds.read_compact_size()) for i in range(n))` with pre-allocated `result = [None] * n` and explicit loop filling 2. **Eliminated repeated attribute lookups**: Cached `vds.read_bytes` and `vds.read_compact_size` as local variables to avoid attribute resolution overhead in the loop **Why it's faster:** - **List pre-allocation** eliminates dynamic resizing costs as Python no longer needs to grow the list incrementally during iteration - **Cached method references** avoid repeated attribute lookups (`vds.read_bytes` and `vds.read_compact_size`) inside the loop, reducing per-iteration overhead - **Generator elimination** removes the intermediate iterator object creation and the `list()` constructor call **Performance impact:** The line profiler shows the critical line improvement: the original `list(generator)` line took 819,520ns (80.9% of function time) vs the optimized explicit loop taking 772,695ns (72.2% of function time) - about a 6% reduction in the hottest code path. **Test case effectiveness:** The optimization shows strongest gains (6-11%) on test cases with larger witness data structures (large_witness tests showing 9.18% and 9.42% improvements), while smaller witness cases show modest 1-6% gains. This makes sense as the optimization benefits scale with the number of witness elements processed. The 6% overall speedup directly improves transaction processing performance, particularly beneficial for applications handling many transactions with witness data (SegWit/Taproot transactions). --- electrum/transaction.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/electrum/transaction.py b/electrum/transaction.py index cca06ff189db..b50e6c6b8192 100644 --- a/electrum/transaction.py +++ b/electrum/transaction.py @@ -325,7 +325,7 @@ class TxInput: _is_coinbase_output: bool def __init__(self, *, - prevout: TxOutpoint, + prevout: 'TxOutpoint', script_sig: bytes = None, nsequence: int = 0xffffffff - 1, witness: bytes = None, @@ -449,7 +449,13 @@ def witness_elements(self) -> Sequence[bytes]: vds = BCDataStream() vds.write(self.witness) n = vds.read_compact_size() - return list(vds.read_bytes(vds.read_compact_size()) for i in range(n)) + # OPTIMIZATION: Pre-allocate the result list to avoid list resizing, and avoid repeated attribute access + result = [None] * n + read_bytes = vds.read_bytes + read_compact_size = vds.read_compact_size + for i in range(n): + result[i] = read_bytes(read_compact_size()) + return result def is_segwit(self, *, guess_for_address=False) -> bool: if self.witness not in (b'\x00', b'', None): @@ -625,9 +631,11 @@ def read_uint64(self): return self._read_num('