Skip to content

Commit 574261b

Browse files
committed
Improve SeedShamirShareOptionsView handling when adding/finalizing
1 parent bd95766 commit 574261b

3 files changed

Lines changed: 86 additions & 21 deletions

File tree

src/seedsigner/models/seed_storage.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,34 @@ def discard_pending_shamir_share_set(self):
161161
self._pending_shamir_share_set = []
162162
self._pending_shamir_num_words = None
163163

164+
def get_pending_shamir_threshold(self) -> int | None:
165+
"""Return threshold based on the first parsed share."""
166+
if not self._pending_shamir_share_set:
167+
return None
168+
169+
try:
170+
from embit import slip39
171+
first_share = " ".join(self._pending_shamir_share_set[0])
172+
share = slip39.Share.parse(first_share)
173+
except Exception:
174+
return None
175+
176+
return share.group_threshold
177+
178+
179+
def can_finalize_pending_shamir_share_set(self, passphrase: str = "") -> bool:
180+
"""Return True if the current share set can reconstruct a Shamir seed."""
181+
if not self._pending_shamir_share_set:
182+
return False
183+
184+
try:
185+
ShamirSeed(self._pending_shamir_share_set, passphrase)
186+
except InvalidSeedException:
187+
return False
188+
189+
return True
190+
164191
def convert_pending_shamir_share_set_to_pending_seed(self, passphrase: str = '', finalize: bool = True):
165-
share_set_formatted = [" ".join(share) for share in self._pending_shamir_share_set]
166192
self.pending_seed = ShamirSeed(self._pending_shamir_share_set, passphrase)
167193
self.pending_seed.set_passphrase(passphrase)
168194
if finalize:

src/seedsigner/views/seed_views.py

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010
from seedsigner.gui.components import FontAwesomeIconConstants, SeedSignerIconConstants
1111
from seedsigner.gui.screens import (RET_CODE__BACK_BUTTON, ButtonListScreen,
12-
WarningScreen, DireWarningScreen, seed_screens)
12+
WarningScreen, DireWarningScreen, LargeIconStatusScreen, seed_screens)
1313
from seedsigner.gui.screens.screen import ButtonOption
1414
from seedsigner.models.encode_qr import CompactSeedQrEncoder, GenericStaticQrEncoder, SeedQrEncoder, SpecterXPubQrEncoder, StaticXpubQrEncoder, UrXpubQrEncoder
1515
from seedsigner.models.qr_type import QRType
16-
from seedsigner.models.seed import Seed, ShamirSeed
16+
from seedsigner.models.seed import Seed, ShamirSeed, InvalidSeedException
1717
from seedsigner.models.settings import Settings, SettingsConstants
1818
from seedsigner.models.settings_definition import SettingsDefinition
1919
from seedsigner.models.threads import BaseThread, ThreadsafeCounter
@@ -2446,29 +2446,55 @@ def run(self):
24462446

24472447
# Add the completed share
24482448
self.controller.storage.add_pending_shamir_share()
2449-
return Destination(SeedShamirShareOptionsView)
2449+
can_finalize = self.controller.storage.can_finalize_pending_shamir_share_set()
2450+
share_threshold = self.controller.storage.get_pending_shamir_threshold()
2451+
share_count = self.controller.storage.pending_shamir_share_set_length
2452+
return Destination(
2453+
SeedShamirShareOptionsView,
2454+
view_args={
2455+
"can_finalize": can_finalize,
2456+
"share_threshold": share_threshold,
2457+
"share_count": share_count
2458+
}
2459+
)
24502460

24512461

24522462

24532463
class SeedShamirShareOptionsView(View):
24542464
# TRANSLATOR_NOTE: These options apply to SLIP-39 Shamir shares (add another share or finalize share set).
24552465
ADD_SHARE = ButtonOption("Add another share")
24562466
FINALIZE = ButtonOption("Finalize")
2457-
# TRANSLATOR_NOTE: "Shares" here means SLIP-39 Shamir secret shares.
2458-
toast_error_message: str = _("Need more shares to reconstruct seed")
2459-
2467+
2468+
def __init__(self, can_finalize, share_threshold, share_count):
2469+
super().__init__()
2470+
self.can_finalize = can_finalize
2471+
self.share_threshold = share_threshold
2472+
self.share_count = share_count
2473+
self.shares_remaining = share_threshold - share_count
2474+
24602475

24612476
def run(self):
2462-
button_data = [self.ADD_SHARE, self.FINALIZE]
2477+
button_data = []
2478+
if self.can_finalize:
2479+
button_data.append(self.FINALIZE)
2480+
else:
2481+
button_data.append(self.ADD_SHARE)
24632482

2464-
share_count = self.controller.storage.pending_shamir_share_set_length
24652483
# TRANSLATOR_NOTE: "Shares" here means SLIP-39 Shamir's secret shares.
2466-
title = _("Shares Added: {}").format(share_count)
2484+
title = _("Share Added")
2485+
text = None
2486+
if self.share_threshold is not None and self.shares_remaining is not None:
2487+
if self.shares_remaining > 0:
2488+
# TRANSLATOR_NOTE: Indicates how many more SLIP-39 shares must be collected.
2489+
text = _("Shares entered: {}\nShares remaining: {}").format(self.share_count, self.shares_remaining)
2490+
else:
2491+
text = _("Required shares collected.\nReady to finalize.")
24672492

24682493
selected_menu_num = self.run_screen(
2469-
ButtonListScreen,
2494+
LargeIconStatusScreen,
24702495
title=title,
24712496
button_data=button_data,
2497+
text=text,
24722498
)
24732499

24742500
if selected_menu_num == RET_CODE__BACK_BUTTON:
@@ -2478,16 +2504,19 @@ def run(self):
24782504
return Destination(SeedShamirShareMnemonicEntryView)
24792505

24802506
elif button_data[selected_menu_num] == self.FINALIZE:
2481-
# Try to finalize with current shares
2482-
from seedsigner.models.seed import InvalidSeedException
24832507
try:
24842508
self.controller.storage.convert_pending_shamir_share_set_to_pending_seed(finalize=False)
2485-
return Destination(SeedShamirShareFinalizeView)
24862509
except InvalidSeedException:
2487-
# If seed does not reconstruct, more shares are needed
2488-
from seedsigner.gui.toast import ErrorToast
2489-
self.controller.activate_toast(ErrorToast(self.toast_error_message))
2490-
return Destination(SeedShamirShareOptionsView)
2510+
logger.exception("Pending Shamir share set unexpectedly failed to reconstruct despite eligibility.")
2511+
return Destination(
2512+
SeedShamirShareOptionsView,
2513+
view_args={
2514+
"can_finalize": self.can_finalize,
2515+
"share_threshold": self.share_threshold,
2516+
"share_count": self.share_count
2517+
}
2518+
)
2519+
return Destination(SeedShamirShareFinalizeView)
24912520

24922521

24932522

@@ -2523,7 +2552,17 @@ def run(self):
25232552
return Destination(MainMenuView)
25242553

25252554
else:
2526-
return Destination(SeedShamirShareOptionsView)
2555+
can_finalize = self.controller.storage.can_finalize_pending_shamir_share_set()
2556+
share_threshold = self.controller.storage.get_pending_shamir_threshold()
2557+
share_count = self.controller.storage.pending_shamir_share_set_length
2558+
return Destination(
2559+
SeedShamirShareOptionsView,
2560+
view_args={
2561+
"can_finalize": can_finalize,
2562+
"share_threshold": share_threshold,
2563+
"share_count": share_count
2564+
}
2565+
)
25272566

25282567

25292568

tests/screenshot_generator/generator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,8 @@ def PSBTOpReturnView_raw_hex_data_cb_before():
370370
ScreenshotConfig(seed_views.SeedShamirShareStartView),
371371
ScreenshotConfig(seed_views.SeedShamirShareImportSelectWordCount),
372372
ScreenshotConfig(seed_views.SeedShamirShareMnemonicEntryView),
373-
ScreenshotConfig(seed_views.SeedShamirShareOptionsView),
374-
ScreenshotConfig(seed_views.SeedShamirShareOptionsView, screenshot_name='SeedShamirShareOptionsView_ErrorToast', toast_thread=ErrorToast(seed_views.SeedShamirShareOptionsView.toast_error_message, activation_delay=0, duration=0)),
373+
ScreenshotConfig(seed_views.SeedShamirShareOptionsView, dict(can_finalize=False, share_threshold=3, share_count=2), screenshot_name="SeedShamirShareOptionsView_AddShare"),
374+
ScreenshotConfig(seed_views.SeedShamirShareOptionsView, dict(can_finalize=True, share_threshold=3, share_count=3), screenshot_name="SeedShamirShareOptionsView_Finalize"),
375375
ScreenshotConfig(seed_views.SeedShamirShareFinalizeView),
376376
ScreenshotConfig(seed_views.SeedShamirShareInvalidView),
377377
],

0 commit comments

Comments
 (0)