diff --git a/electrum/commands.py b/electrum/commands.py index 3159f4ed5..b17bb540b 100644 --- a/electrum/commands.py +++ b/electrum/commands.py @@ -1400,6 +1400,7 @@ def add_global_options(parser): group.add_argument("--testnet", action="store_true", dest="testnet", default=False, help="Use Testnet") group.add_argument("--regtest", action="store_true", dest="regtest", default=False, help="Use Regtest") group.add_argument("--simnet", action="store_true", dest="simnet", default=False, help="Use Simnet") + group.add_argument("--signet", action="store_true", dest="signet", default=False, help="Use Signet") group.add_argument("-o", "--offline", action="store_true", dest="offline", default=False, help="Run offline") def add_wallet_option(parser): diff --git a/electrum/constants.py b/electrum/constants.py index 6e5f7435e..b31654e1b 100644 --- a/electrum/constants.py +++ b/electrum/constants.py @@ -60,6 +60,7 @@ class AbstractNet: class BitcoinMainnet(AbstractNet): + NET_NAME = "mainnet" TESTNET = False WIF_PREFIX = 0x80 ADDRTYPE_P2PKH = 0 @@ -98,6 +99,7 @@ class BitcoinMainnet(AbstractNet): class BitcoinTestnet(AbstractNet): + NET_NAME = "testnet" TESTNET = True WIF_PREFIX = 0xef ADDRTYPE_P2PKH = 111 @@ -134,6 +136,7 @@ class BitcoinTestnet(AbstractNet): class BitcoinRegtest(BitcoinTestnet): + NET_NAME = "regtest" SEGWIT_HRP = "bcrt" GENESIS = "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206" DEFAULT_SERVERS = read_json('servers_regtest.json', {}) @@ -143,6 +146,7 @@ class BitcoinRegtest(BitcoinTestnet): class BitcoinSimnet(BitcoinTestnet): + NET_NAME = "simnet" WIF_PREFIX = 0x64 ADDRTYPE_P2PKH = 0x3f ADDRTYPE_P2SH = 0x7b @@ -153,9 +157,22 @@ class BitcoinSimnet(BitcoinTestnet): LN_DNS_SEEDS = [] +class BitcoinSignet(BitcoinTestnet): + + NET_NAME = "signet" + GENESIS = "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6" + DEFAULT_SERVERS = read_json('servers_signet.json', {}) + CHECKPOINTS = [] + LN_DNS_SEEDS = [] + + # don't import net directly, import the module instead (so that net is singleton) net = BitcoinMainnet +def set_signet(): + global net + net = BitcoinSignet + def set_simnet(): global net net = BitcoinSimnet @@ -168,7 +185,6 @@ def set_testnet(): global net net = BitcoinTestnet - def set_regtest(): global net net = BitcoinRegtest diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 7a607caab..ac39a4884 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -540,7 +540,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): self.setGeometry(100, 100, 840, 400) def watching_only_changed(self): - name = "Electrum Testnet" if constants.net.TESTNET else "Electrum" + name = "Electrum" + if constants.net.TESTNET: + name += " " + constants.net.NET_NAME.capitalize() title = '%s %s - %s' % (name, ELECTRUM_VERSION, self.wallet.basename()) extra = [self.wallet.db.get('wallet_type', '?')] diff --git a/electrum/lnaddr.py b/electrum/lnaddr.py index 3d2549b63..b9c944122 100644 --- a/electrum/lnaddr.py +++ b/electrum/lnaddr.py @@ -178,6 +178,9 @@ def pull_tagged(stream): return (CHARSET[tag], stream.read(length * 5), stream) def lnencode(addr: 'LnAddr', privkey) -> str: + # see https://github.com/lightningnetwork/lightning-rfc/pull/844 + if constants.net.NET_NAME == "signet": + addr.currency += "s" if addr.amount: amount = addr.currency + shorten_amount(addr.amount) else: @@ -366,6 +369,9 @@ class SerializableKey: def lndecode(invoice: str, *, verbose=False, expected_hrp=None) -> LnAddr: if expected_hrp is None: expected_hrp = constants.net.SEGWIT_HRP + # see https://github.com/lightningnetwork/lightning-rfc/pull/844 + if constants.net.NET_NAME == "signet": + expected_hrp += "s" decoded_bech32 = bech32_decode(invoice, ignore_long_length=True) hrp = decoded_bech32.hrp data = decoded_bech32.data diff --git a/electrum/servers_signet.json b/electrum/servers_signet.json new file mode 100644 index 000000000..134e2682a --- /dev/null +++ b/electrum/servers_signet.json @@ -0,0 +1,14 @@ +{ + "127.0.0.1": { + "pruning": "-", + "s": "51002", + "t": "51001", + "version": "1.2" + }, + "signet-electrumx.wakiyamap.dev": { + "pruning": "-", + "s": "50002", + "t": "50001", + "version": "1.4" + } +} diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 3ab248da7..96e313096 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -128,6 +128,9 @@ class SimpleConfig(Logger): elif self.get('simnet'): path = os.path.join(path, 'simnet') make_dir(path, allow_symlink=False) + elif self.get('signet'): + path = os.path.join(path, 'signet') + make_dir(path, allow_symlink=False) self.logger.info(f"electrum directory {path}") return path diff --git a/electrum/trampoline.py b/electrum/trampoline.py index 07eed3ce8..f49f6fbda 100644 --- a/electrum/trampoline.py +++ b/electrum/trampoline.py @@ -63,11 +63,17 @@ TRAMPOLINE_NODES_TESTNET = { 'endurance': LNPeerAddr(host='34.250.234.192', port=9735, pubkey=bytes.fromhex('03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134')), } +TRAMPOLINE_NODES_SIGNET = { + 'wakiyamap.dev': LNPeerAddr(host='signet-electrumx.wakiyamap.dev', port=9735, pubkey=bytes.fromhex('02dadf6c28f3284d591cd2a4189d1530c1ff82c07059ebea150a33ab76e7364b4a')), +} + def hardcoded_trampoline_nodes(): - if constants.net in (constants.BitcoinMainnet,): + if constants.net.NET_NAME == "mainnet": return TRAMPOLINE_NODES_MAINNET - if constants.net in (constants.BitcoinTestnet,): + if constants.net.NET_NAME == "testnet": return TRAMPOLINE_NODES_TESTNET + if constants.net.NET_NAME == "signet": + return TRAMPOLINE_NODES_SIGNET return {} def trampolines_by_id(): diff --git a/electrum/util.py b/electrum/util.py index 8fb9ca0d6..263b1003c 100644 --- a/electrum/util.py +++ b/electrum/util.py @@ -804,12 +804,29 @@ testnet_block_explorers = { {'tx': 'tx/', 'addr': 'address/'}), } +signet_block_explorers = { + 'bc-2.jp': ('https://explorer.bc-2.jp/', + {'tx': 'tx/', 'addr': 'address/'}), + 'mempool.space': ('https://mempool.space/signet/', + {'tx': 'tx/', 'addr': 'address/'}), + 'bitcoinexplorer.org': ('https://signet.bitcoinexplorer.org/', + {'tx': 'tx/', 'addr': 'address/'}), + 'wakiyamap.dev': ('https://signet-explorer.wakiyamap.dev/', + {'tx': 'tx/', 'addr': 'address/'}), + 'system default': ('blockchain:/', + {'tx': 'tx/', 'addr': 'address/'}), +} + _block_explorer_default_api_loc = {'tx': 'tx/', 'addr': 'address/'} def block_explorer_info(): from . import constants - return mainnet_block_explorers if not constants.net.TESTNET else testnet_block_explorers + if constants.net.NET_NAME == "testnet": + return testnet_block_explorers + elif constants.net.NET_NAME == "signet": + return signet_block_explorers + return mainnet_block_explorers def block_explorer(config: 'SimpleConfig') -> Optional[str]: diff --git a/run_electrum b/run_electrum index c44650a3a..a00c7a1f6 100755 --- a/run_electrum +++ b/run_electrum @@ -366,6 +366,8 @@ def main(): constants.set_regtest() elif config.get('simnet'): constants.set_simnet() + elif config.get('signet'): + constants.set_signet() cmdname = config.get('cmd')