2 Commits

Author SHA1 Message Date
davide 95439306df fix: make BIP21 URI scheme network-aware for BitcoinPurple
Adds BIP21_URI_SCHEME to AbstractNet (default 'bitcoin'), overridden
to 'btcp' in BitcoinPurple. All parse/create/scan paths now use
constants.net.BIP21_URI_SCHEME so QR codes with btcp:... URIs are
correctly recognised and generated on the Purple network.
2026-05-07 17:16:20 +02:00
davide ad7d2bd8b3 feat: remove upstream Electrum update check from desktop GUI
Eliminates the startup dialog asking to enable update checks, the
background version check against electrum.org, the status bar button,
and the Help menu entry — all irrelevant for the Purple fork.
2026-05-07 17:07:30 +02:00
7 changed files with 12 additions and 40 deletions
+4 -3
View File
@@ -5,12 +5,13 @@ from decimal import Decimal
from typing import Optional
from . import bitcoin
from . import constants
from .util import format_satoshis_plain
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
from .bolt11 import decode_bolt11_invoice, BOLT11DecodeException
# note: when checking against these, use .lower() to support case-insensitivity
BITCOIN_BIP21_URI_SCHEME = 'bitcoin'
BITCOIN_BIP21_URI_SCHEME = 'bitcoin' # kept for backward-compat imports
LIGHTNING_URI_SCHEME = 'lightning'
# note: URI scheme handler registrations are duplicated all over the codebase:
@@ -36,7 +37,7 @@ def parse_bip21_URI(uri: str) -> dict:
return {'address': uri}
u = urllib.parse.urlparse(uri)
if u.scheme.lower() != BITCOIN_BIP21_URI_SCHEME:
if u.scheme.lower() != constants.net.BIP21_URI_SCHEME:
raise InvalidBitcoinURI("Not a bitcoin URI")
address = u.path
@@ -127,7 +128,7 @@ def create_bip21_uri(addr, amount_sat: Optional[int], message: Optional[str],
v = urllib.parse.quote(v)
query.append(f"{k}={v}")
p = urllib.parse.ParseResult(
scheme=BITCOIN_BIP21_URI_SCHEME,
scheme=constants.net.BIP21_URI_SCHEME,
netloc='',
path=addr,
params='',
+2
View File
@@ -83,6 +83,7 @@ class AbstractNet:
COIN_SYMBOL: str = "BTC"
COIN_NAME: str = "Bitcoin"
BIP21_URI_SCHEME: str = "bitcoin"
# PoW difficulty parameters (Bitcoin defaults; override per chain as needed)
DIFFICULTY_ADJUSTMENT_INTERVAL: int = 2016 # blocks per retarget window
@@ -283,6 +284,7 @@ class BitcoinPurple(AbstractNet):
ADDRTYPE_P2SH = 55
SEGWIT_HRP = "btcp"
BOLT11_HRP = SEGWIT_HRP
BIP21_URI_SCHEME = "btcp"
GENESIS = "000003823fbf82ea4906cbe214617ce7a70a5da29c19ecb1d65618bcf04ec015"
DEFAULT_PORTS = {'t': '50001', 's': '50002'}
BLOCK_HEIGHT_FIRST_LIGHTNING_CHANNELS = 0
+2 -1
View File
@@ -16,6 +16,7 @@ except ImportError:
# Note: missing QtMultimedia will lead to errors when using QR scanner on desktop
from PyQt6.QtCore import QObject as QVideoSink
from electrum import constants
from electrum.logging import get_logger
from electrum.qrreader import get_qr_reader
from electrum.i18n import _
@@ -144,7 +145,7 @@ class QEQRImageProvider(QQuickImageProvider):
# (unknown schemes might be found when a colon is in a serialized TX, which
# leads to mangling of the tx, so we check for supported schemes.)
uri = urllib.parse.urlparse(qstr)
if uri.scheme and uri.scheme in ['bitcoin', 'lightning']:
if uri.scheme and uri.scheme in [constants.net.BIP21_URI_SCHEME, 'lightning']:
# urlencode request parameters
query = urllib.parse.parse_qs(uri.query)
query = urllib.parse.urlencode(query, doseq=True, quote_via=urllib.parse.quote)
-33
View File
@@ -95,7 +95,6 @@ from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialo
getOpenFileName, getSaveFileName, ShowQRLineEdit, scan_qr_from_screenshot)
from .wizard.wallet import WIF_HELP_TEXT
from .history_list import HistoryList, HistoryModel
from .update_checker import UpdateCheck, UpdateCheckThread
from .channels_list import ChannelsList
from .confirm_tx_dialog import ConfirmTxDialog, TxEditorContext
from .rbf_dialog import BumpFeeDialog, DSCancelDialog
@@ -296,26 +295,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
self.contacts.fetch_openalias(self.config)
# If the option hasn't been set yet
if not config.cv.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS.is_set():
choice = self.question(title="Electrum - " + _("Enable update check"),
msg=_("For security reasons we advise that you always use the latest version of Electrum.") + " " +
_("Would you like to be notified when there is a newer version of Electrum available?"))
config.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS = bool(choice)
self._update_check_thread = None
if config.AUTOMATIC_CENTRALIZED_UPDATE_CHECKS:
# The references to both the thread and the window need to be stored somewhere
# to prevent GC from getting in our way.
def on_version_received(v):
if UpdateCheck.is_newer(v):
self.update_check_button.setText(_("Update to Electrum {} is available").format(v))
self.update_check_button.clicked.connect(lambda: self.show_update_check(v))
self.update_check_button.show()
self._update_check_thread = UpdateCheckThread()
self._update_check_thread.checked.connect(on_version_received)
self._update_check_thread.start()
def run_coroutine_dialog(self, coro, text):
""" run coroutine in a waiting dialog, with a Cancel button that cancels the coroutine"""
from .util import RunCoroutineDialog
@@ -848,7 +827,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
about_action.setMenuRole(QAction.MenuRole.AboutRole) # make sure OS recognizes it as "About"
self.help_menu.addAction(about_action)
self.help_menu.addAction(_("&Changelog"), lambda: webopen(constants.RELEASE_NOTES_URL))
self.help_menu.addAction(_("&Check for updates"), self.show_update_check)
self.help_menu.addAction(_("&Official website"), lambda: webopen("https://electrum.org"))
self.help_menu.addSeparator()
self.help_menu.addAction(_("&Documentation"), lambda: webopen("http://docs.electrum.org/")).setShortcut(QKeySequence.StandardKey.HelpContents)
@@ -902,9 +880,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
return
webopen('file:///' + filename)
def show_update_check(self, version=None):
self.gui_object._update_check = UpdateCheck(latest_version=version)
def show_report_bug(self):
msg = ' '.join([
_("Please report any bugs as issues on github:<br/>"),
@@ -1812,12 +1787,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
self.search_box.hide()
sb.addPermanentWidget(self.search_box)
self.update_check_button = QPushButton("")
self.update_check_button.setFlat(True)
self.update_check_button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
self.update_check_button.setIcon(read_QIcon("update.png"))
self.update_check_button.hide()
sb.addPermanentWidget(self.update_check_button)
self.password_required_button = QPushButton(_('Password required'))
self.password_required_button.setFlat(True)
@@ -2821,8 +2790,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
self.qr_window.close()
self.close_wallet()
if self._update_check_thread:
self._update_check_thread.stop()
if self.tray:
self.tray = None
self.timer.stop()
+1 -1
View File
@@ -1562,7 +1562,7 @@ class Interface(Logger):
return ''
if not isinstance(res, str):
raise RequestCorrupted(f'{res!r} should be a str')
address = res.removeprefix('bitcoin:')
address = res.removeprefix(constants.net.BIP21_URI_SCHEME + ':')
if not bitcoin.is_address(address):
# note: do not hard-fail -- allow server to use future-type
# bitcoin address we do not recognize
+1 -1
View File
@@ -341,7 +341,7 @@ class Request(BaseInvoice):
if lightning_invoice:
extra['lightning'] = lightning_invoice
if not addr and lightning_invoice:
return "bitcoin:?lightning="+lightning_invoice
return f"{constants.net.BIP21_URI_SCHEME}:?lightning=" + lightning_invoice
if not addr and not lightning_invoice:
return None
uri = create_bip21_uri(addr, amount, message, extra_query_params=extra)
+2 -1
View File
@@ -7,6 +7,7 @@ from enum import IntEnum
from typing import NamedTuple, Optional, Callable, List, TYPE_CHECKING, Tuple, Union
from . import bitcoin
from . import constants
from .contacts import AliasNotFoundException
from .i18n import _
from .invoices import Invoice
@@ -249,7 +250,7 @@ class PaymentIdentifier(Logger):
self._type = PaymentIdentifierType.LNURL
self.lnurl = lnurl_url
self.set_state(PaymentIdentifierState.NEED_RESOLVE)
elif text.lower().startswith(BITCOIN_BIP21_URI_SCHEME + ':'):
elif text.lower().startswith(constants.net.BIP21_URI_SCHEME + ':'):
try:
out = parse_bip21_URI(text)
except InvalidBitcoinURI as e: