fix: remove negative fee assert from get_tx_fee_warning
What changed, and why it matters
This commit removes a hard crash (assertion) in Electrum's wallet code when a user loads a partially-signed Bitcoin transaction (PSBT) whose calculated fee is negative. Instead of crashing, Electrum now logs a warning and continues. A negative fee can happen if transaction inputs and outputs are crafted or edited in unusual ways. The change prevents a denial-of-service-like crash when opening such a transaction, but it does not by itself fix whatever produced the negative fee.
Treat as a minor hardening/DoS-mitigation patch. Review whether downstream fee-ratio warnings behave safely with negative values, and consider validating PSBT fees earlier in the import flow. No urgent security response is indicated by the diff alone.
Security signals we found
assertion replaced with warning log
negative transaction fee handling
PSBT loading robustness
potential denial-of-service via crafted transaction file
Evidence from the diff
In electrum/wallet.py, Abstract_Wallet.get_tx_fee_warning() previously asserted fee >= 0. The patch replaces that assertion with an if fee < 0: warning log and continues execution. The downstream code still computes feerate = Decimal(fee) / tx_size and fee_ratio = Decimal(fee) / invoice_amt, so a negative fee will now propagate through the fee-warning logic instead of raising AssertionError. This is a robustness fix for handling malformed or manipulated PSBTs.
Changed components
electrum/wallet.pyAbstract_Wallet.get_tx_fee_warning()Inspect captured patch +2 / −1
diff --git a/electrum/wallet.py b/electrum/wallet.py
index 3529403..00f5c93 100644
--- a/electrum/wallet.py
+++ b/electrum/wallet.py
@@ -3402,7 +3402,8 @@ class Abstract_Wallet(ABC, Logger, EventListener):
txid: Optional[str]) -> Optional[Tuple[bool, str, str]]:
assert invoice_amt >= 0, f"{invoice_amt=!r} must be non-negative satoshis"
- assert fee >= 0, f"{fee=!r} must be non-negative satoshis"
+ if fee < 0:
+ self.logger.warning(f"transaction {txid=} has negative {fee=}")
is_future_tx = txid is not None and txid in self.adb.future_tx
feerate = Decimal(fee) / tx_size # sat/byte
fee_ratio = Decimal(fee) / invoice_amt if invoice_amt else 0
Why this scored 37/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.