fix: chainname regtest bug (classproperty); add no-heirs buttons in build-will dialog
- bal/core/plugin_base.py: change chainname from frozen class attribute to @classproperty so it reads constants.net.NET_NAME at runtime, fixing regtest/testnet always downloading the mainnet executor list - bal/core/willexecutors.py: remove module-level chainname capture; all uses now read BalPlugin.chainname directly - bal/gui/qt/dialogs.py: when BalBuildWillDialog detects no heirs, return 'no_heirs' signal and show Heirs/Wizard/Close buttons (mirroring the existing no-willexecutor pattern); add HeirsDialog with full HeirListWidget (New Heir, Import, Export)
This commit is contained in:
@@ -30,6 +30,7 @@ from electrum import constants, json_db
|
||||
from electrum.logging import get_logger
|
||||
from electrum.plugin import BasePlugin
|
||||
from electrum.transaction import tx_from_any
|
||||
from electrum.util import classproperty
|
||||
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
@@ -169,9 +170,12 @@ class BalPlugin(BasePlugin):
|
||||
}
|
||||
|
||||
# Human-readable chain name ("bitcoin", "testnet", "regtest", ...).
|
||||
chainname = (
|
||||
constants.net.NET_NAME if constants.net.NET_NAME != "mainnet" else "bitcoin"
|
||||
)
|
||||
# Must be a classproperty (not a plain class attribute) because the class
|
||||
# is defined before constants.net is set to the correct network — a plain
|
||||
# attribute would capture "bitcoin" and never update.
|
||||
@classproperty
|
||||
def chainname(cls):
|
||||
return constants.net.NET_NAME if constants.net.NET_NAME != "mainnet" else "bitcoin"
|
||||
|
||||
# Default geometry hint for some dialogs (kept from the original code).
|
||||
SIZE = (159, 97)
|
||||
|
||||
@@ -112,8 +112,6 @@ def is_tor_active():
|
||||
return False
|
||||
|
||||
|
||||
chainname = BalPlugin.chainname
|
||||
|
||||
|
||||
class Willexecutors:
|
||||
|
||||
@@ -146,9 +144,9 @@ class Willexecutors:
|
||||
|
||||
@staticmethod
|
||||
def save(bal_plugin, willexecutors):
|
||||
_logger.debug(f"save {willexecutors},{chainname}")
|
||||
_logger.debug(f"save {willexecutors},{BalPlugin.chainname}")
|
||||
aw = bal_plugin.WILLEXECUTORS.get()
|
||||
aw[chainname] = willexecutors
|
||||
aw[BalPlugin.chainname] = willexecutors
|
||||
bal_plugin.WILLEXECUTORS.set(aw)
|
||||
_logger.debug(f"saved: {aw}")
|
||||
# bal_plugin.WILLEXECUTORS.set(willexecutors)
|
||||
@@ -158,7 +156,7 @@ class Willexecutors:
|
||||
bal_plugin, update=False, bal_window: Any = None, force=False, task=True
|
||||
):
|
||||
willexecutors = bal_plugin.WILLEXECUTORS.get()
|
||||
willexecutors = willexecutors.get(chainname, {})
|
||||
willexecutors = willexecutors.get(BalPlugin.chainname, {})
|
||||
to_del = []
|
||||
for w in willexecutors:
|
||||
if not isinstance(willexecutors[w], dict):
|
||||
@@ -172,7 +170,7 @@ class Willexecutors:
|
||||
)
|
||||
)
|
||||
del willexecutors[w]
|
||||
bal = bal_plugin.WILLEXECUTORS.default.get(chainname, {})
|
||||
bal = bal_plugin.WILLEXECUTORS.default.get(BalPlugin.chainname, {})
|
||||
for bal_url, bal_executor in bal.items():
|
||||
if bal_url not in willexecutors:
|
||||
_logger.debug(f"force add {bal_url} willexecutor")
|
||||
@@ -368,7 +366,7 @@ class Willexecutors:
|
||||
_logger.debug(f"{willexecutor['url']}: {willexecutor['txs']}")
|
||||
if w := Willexecutors.send_request(
|
||||
"post",
|
||||
willexecutor["url"] + "/" + chainname + "/pushtxs",
|
||||
willexecutor["url"] + "/" + BalPlugin.chainname + "/pushtxs",
|
||||
data=willexecutor["txs"].encode("ascii"),
|
||||
timeout=timeout,
|
||||
max_retries=max_retries,
|
||||
@@ -408,7 +406,7 @@ class Willexecutors:
|
||||
# single short timeout instead of retrying 10x with sleeps, which
|
||||
# used to freeze the UI for minutes per unreachable server.
|
||||
w = Willexecutors.send_request(
|
||||
"get", url + "/" + chainname + "/info",
|
||||
"get", url + "/" + BalPlugin.chainname + "/info",
|
||||
timeout=timeout, max_retries=max_retries, retry_sleep=retry_sleep,
|
||||
)
|
||||
if isinstance(w, dict):
|
||||
@@ -788,7 +786,7 @@ class Willexecutors:
|
||||
welist_server = welist_server if welist_server[-1] == '/' else welist_server+'/'
|
||||
willexecutors = Willexecutors.send_request(
|
||||
"get",
|
||||
f"{welist_server}data/{chainname}?page=0&limit=100",
|
||||
f"{welist_server}data/{BalPlugin.chainname}?page=0&limit=100",
|
||||
)
|
||||
if not isinstance(willexecutors, dict):
|
||||
_logger.warning(
|
||||
|
||||
@@ -643,8 +643,7 @@ class BalBuildWillDialog(BalDialog):
|
||||
return None, tx
|
||||
except NoHeirsException:
|
||||
self.msg_set_status("Checking variables", varrow,"No Heirs",self.COLOR_ERROR)
|
||||
#self.msg_set_checking("No Heirs")
|
||||
return False, None
|
||||
return "no_heirs", None
|
||||
except Exception as e:
|
||||
raise e
|
||||
try:
|
||||
@@ -1439,6 +1438,10 @@ class BalBuildWillDialog(BalDialog):
|
||||
self._add_no_willexecutor_buttons()
|
||||
return
|
||||
|
||||
if self.have_to_sign == "no_heirs":
|
||||
self._add_no_heirs_buttons()
|
||||
return
|
||||
|
||||
_logger.debug("have to sign {}".format(self.have_to_sign))
|
||||
password = None
|
||||
if self.have_to_sign is None:
|
||||
@@ -1646,6 +1649,70 @@ class BalBuildWillDialog(BalDialog):
|
||||
on_error=self.on_error_phase1,
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------------ #
|
||||
# No-heirs error handling (mirrors the no-willexecutor pattern above)
|
||||
# ------------------------------------------------------------------ #
|
||||
|
||||
def _add_no_heirs_buttons(self):
|
||||
"""Add "Heirs", "Wizard" and "Close" buttons when no heirs are
|
||||
configured."""
|
||||
if getattr(self, "_no_heirs_buttons_added", False):
|
||||
return
|
||||
self._no_heirs_buttons_added = True
|
||||
btn_row = QHBoxLayout()
|
||||
btn_row.addStretch(1)
|
||||
|
||||
heirs_btn = QPushButton(_("Heirs"))
|
||||
heirs_btn.clicked.connect(self._open_heir_dialog)
|
||||
btn_row.addWidget(heirs_btn)
|
||||
|
||||
wizard_btn = QPushButton(_("\U0001f52e Wizard"))
|
||||
wizard_btn.clicked.connect(self._open_heirs_wizard)
|
||||
btn_row.addWidget(wizard_btn)
|
||||
|
||||
close_btn = QPushButton(_("Close"))
|
||||
close_btn.clicked.connect(self.close)
|
||||
btn_row.addWidget(close_btn)
|
||||
|
||||
self._no_heirs_layout = btn_row
|
||||
self.vbox.addLayout(btn_row)
|
||||
self.resize(self.vbox.sizeHint())
|
||||
|
||||
def _open_heir_dialog(self):
|
||||
"""Open the heirs management dialog, then retry the build."""
|
||||
d = HeirsDialog(self.bal_window, parent=self)
|
||||
d.exec()
|
||||
self._retry_build_after_heirs()
|
||||
|
||||
def _open_heirs_wizard(self):
|
||||
"""Close the build-will dialog and open the wizard at the heirs
|
||||
step so the user can add heirs."""
|
||||
self.close()
|
||||
wizard = BalWizardDialog(self.bal_window)
|
||||
wizard.exec()
|
||||
|
||||
def _retry_build_after_heirs(self):
|
||||
"""Remove the no-heirs buttons, reset the message panel,
|
||||
and re-run ``task_phase1`` on the same thread."""
|
||||
self._no_heirs_buttons_added = False
|
||||
if self._no_heirs_layout:
|
||||
while self._no_heirs_layout.count():
|
||||
item = self._no_heirs_layout.takeAt(0)
|
||||
w = item.widget()
|
||||
if w:
|
||||
w.setParent(None)
|
||||
w.deleteLater()
|
||||
self.vbox.removeItem(self._no_heirs_layout)
|
||||
self._no_heirs_layout = None
|
||||
self.labels = []
|
||||
self.msg_update()
|
||||
self.thread.add(
|
||||
self.task_phase1,
|
||||
on_success=self.on_success_phase1,
|
||||
on_done=self.on_accept,
|
||||
on_error=self.on_error_phase1,
|
||||
)
|
||||
|
||||
def _ics_provider(self):
|
||||
"""Return the .ics content for the current will data."""
|
||||
from datetime import datetime
|
||||
@@ -2197,3 +2264,49 @@ class WillExecutorDialog(BalDialog, MessageBoxMixin):
|
||||
event.accept()
|
||||
|
||||
|
||||
class HeirsDialog(BalDialog, MessageBoxMixin):
|
||||
def __init__(self, bal_window, parent=None):
|
||||
if not parent:
|
||||
parent = bal_window.window
|
||||
BalDialog.__init__(self, parent, bal_window.bal_plugin)
|
||||
self.bal_plugin = bal_window.bal_plugin
|
||||
self.bal_window = bal_window
|
||||
|
||||
self.setWindowTitle(_("Heirs"))
|
||||
self.setMinimumSize(800, 300)
|
||||
|
||||
from .lists import HeirListWidget
|
||||
vbox = QVBoxLayout(self)
|
||||
self.heir_list_widget = HeirListWidget(bal_window, self)
|
||||
vbox.addWidget(self.heir_list_widget)
|
||||
|
||||
btn_row = QHBoxLayout()
|
||||
new_heir_btn = QPushButton(_("New Heir"))
|
||||
new_heir_btn.clicked.connect(self._add_heir)
|
||||
btn_row.addWidget(new_heir_btn)
|
||||
|
||||
import_btn = QPushButton(_("Import"))
|
||||
import_btn.clicked.connect(self._import_heirs)
|
||||
btn_row.addWidget(import_btn)
|
||||
|
||||
export_btn = QPushButton(_("Export"))
|
||||
export_btn.clicked.connect(self._export_heirs)
|
||||
btn_row.addWidget(export_btn)
|
||||
|
||||
btn_row.addStretch(1)
|
||||
vbox.addLayout(btn_row)
|
||||
|
||||
def _add_heir(self):
|
||||
self.bal_window.new_heir_dialog()
|
||||
self.heir_list_widget.update()
|
||||
|
||||
def _import_heirs(self):
|
||||
self.bal_window.import_heirs()
|
||||
self.heir_list_widget.update()
|
||||
|
||||
def _export_heirs(self):
|
||||
self.bal_window.export_heirs()
|
||||
|
||||
def closeEvent(self, event):
|
||||
event.accept()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user