Settle is_high_fee once in parse()

Both PSBTOverviewView and PSBTMathView asked the parser whether the fee was
high, and the overview asked twice (once for the screen, once for routing).
Each call re-summed the outputs through psbt.tx, which rebuilds the whole
transaction on every access. The totals it depends on are all fixed by the end
of parse(), so compute it there once and store it as is_high_fee, the same way
the other totals are exposed. has_high_fee() stays as the computation itself.
This commit is contained in:
okaybro
2026-09-20 16:13:13 +05:30
parent 5b15804a7a
commit 2195adfdbd
3 changed files with 32 additions and 5 deletions
+8
View File
@@ -177,6 +177,11 @@ class PSBTParser():
self.destination_amounts = []
self.op_return_data: bytes = None
# Whether the fee is high relative to what is being sent; see has_high_fee().
# Computed once at the end of parse() so the views can read it without each
# re-walking the outputs.
self.is_high_fee: bool = False
# Contains one entry per input in psbt.inputs and per output in psbt.outputs. Each
# entry is either the derivation path the seed genuinely owns there, or it is set
# to `None`.
@@ -303,6 +308,9 @@ class PSBTParser():
if rt == False:
return False
# Every total is known now, so settle this once rather than per view.
self.is_high_fee = self.has_high_fee()
return True
+3 -5
View File
@@ -163,8 +163,6 @@ class PSBTOverviewView(View):
else:
num_self_transfer_outputs += 1
is_high_fee_tx = psbt_parser.has_high_fee()
# Run the overview screen
selected_menu_num = self.run_screen(
PSBTOverviewScreen,
@@ -176,7 +174,7 @@ class PSBTOverviewView(View):
num_change_outputs=num_change_outputs,
destination_addresses=psbt_parser.destination_addresses,
has_op_return=psbt_parser.op_return_data is not None,
is_high_fee_tx=is_high_fee_tx,
is_high_fee_tx=psbt_parser.is_high_fee,
)
if selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -188,7 +186,7 @@ class PSBTOverviewView(View):
if psbt_parser.policy == None:
return Destination(PSBTUnsupportedScriptTypeWarningView)
elif is_high_fee_tx:
elif psbt_parser.is_high_fee:
return Destination(PSBTHighFeeWarningView, view_args={"warning_threshold_percent": psbt_parser.HIGH_FEES_WARNING_THRESHOLD})
elif psbt_parser.change_amount == 0:
@@ -298,7 +296,7 @@ class PSBTMathView(View):
num_recipients=psbt_parser.num_destinations,
fee_amount=psbt_parser.fee_amount,
change_amount=psbt_parser.change_amount,
is_high_fee_tx=psbt_parser.has_high_fee(),
is_high_fee_tx=psbt_parser.is_high_fee,
)
if selected_menu_num == RET_CODE__BACK_BUTTON:
+21
View File
@@ -445,6 +445,27 @@ class TestPSBTParser:
assert parser.has_high_fee() is expected
def test_parse_sets_is_high_fee(self):
"""
parse() should settle is_high_fee once, from the real totals, so the views
can read it without recomputing. Checked in both directions: a realistic fee
leaves it False, a fee dwarfing the spend sets it True.
"""
# 272 sat fee on a 2 BTC spend: nowhere near the threshold
psbt = PSBT.parse(a2b_base64(PSBTTestData.SINGLE_SIG_NATIVE_SEGWIT_2_INPUTS))
psbt_parser = PSBTParser(p=psbt, seed=PSBTTestData.two_input_seed, network=SettingsConstants.REGTEST)
assert psbt_parser.is_high_fee is False
assert psbt_parser.is_high_fee == psbt_parser.has_high_fee()
# 1 BTC input paying a 50,000 sat recipient and 10,000 sats change: almost all fee
psbt = PSBT.parse(a2b_base64(PSBTTestData.SINGLE_SIG_NATIVE_SEGWIT_1_INPUT))
psbt.outputs.append(create_output(PSBTTestData.SINGLE_SIG_NATIVE_SEGWIT_RECEIVE, 50_000))
psbt.outputs.append(create_output(PSBTTestData.SINGLE_SIG_NATIVE_SEGWIT_CHANGE, 10_000))
psbt_parser = PSBTParser(p=psbt, seed=PSBTTestData.seed, network=SettingsConstants.REGTEST)
assert psbt_parser.is_high_fee is True
assert psbt_parser.is_high_fee == psbt_parser.has_high_fee()
# TODO: Refactor all tests to be in the TestPSBTParser class(?)
def test_p2tr_change_detection():