constants: add BitcoinPurple (BTCP) and BitcoinPurpleTestnet network classes

Add per-chain PoW fields to AbstractNet (DIFFICULTY_ADJUSTMENT_INTERVAL,
POW_TARGET_TIMESPAN, MAX_TARGET, MAX_ADJUSTMENT_FACTOR, POW_GENESIS_BITS)
with Bitcoin defaults so existing chains are unaffected.

Add BitcoinPurple and BitcoinPurpleTestnet as independent AbstractNet subclasses
with BTCP-specific parameters:
- 120-block retarget interval, 7200-second target timespan
- powLimit 0x1e0fffff, genesis nBits 0x1e0ffff0 (POW_GENESIS_BITS)
- P2PKH prefix 56 (0x38), P2SH 55 (0x37), WIF 0xb7, bech32 HRP "btcp"/"tbtcp"
- SLIP-0132 HD key headers identical to Bitcoin mainnet/testnet respectively
- ElectrumX default ports 50001/50002 (mainnet) and 60001/60002 (testnet)

Add chain data directories:
- electrum/chains/bitcoinpurple/{servers,checkpoints,fallback_lnnodes}.json
- electrum/chains/bitcoinpurple_testnet/{servers,checkpoints,fallback_lnnodes}.json
servers.json is populated with 5 known BTCP ElectrumX nodes (TCP 51001, SSL 51002)
This commit is contained in:
2026-04-29 10:07:37 +02:00
parent bd5ac019ce
commit e0d04af154
7 changed files with 122 additions and 0 deletions
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
{}
@@ -0,0 +1,32 @@
{
"173.212.224.67": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.4.2"
},
"144.91.120.225": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.4.2"
},
"66.94.115.80": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.4.2"
},
"89.117.149.130": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.4.2"
},
"84.247.169.248": {
"pruning": "-",
"s": "51002",
"t": "51001",
"version": "1.4.2"
}
}
@@ -0,0 +1 @@
[]
@@ -0,0 +1 @@
{}
@@ -0,0 +1 @@
{}
+85
View File
@@ -81,6 +81,16 @@ class AbstractNet:
XPUB_HEADERS: Mapping[str, int] XPUB_HEADERS: Mapping[str, int]
XPUB_HEADERS_INV: Mapping[int, str] XPUB_HEADERS_INV: Mapping[int, str]
# PoW difficulty parameters (Bitcoin defaults; override per chain as needed)
DIFFICULTY_ADJUSTMENT_INTERVAL: int = 2016 # blocks per retarget window
POW_TARGET_TIMESPAN: int = 14 * 24 * 60 * 60 # target seconds per window
MAX_TARGET: int = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff # compact 0x1d00ffff
MAX_ADJUSTMENT_FACTOR: int = 4
# When genesis nBits != target_to_bits(MAX_TARGET), set this to the genesis
# nBits value so get_target(-1) returns the correct initial difficulty.
# None means "derive from MAX_TARGET" (correct for Bitcoin where they match).
POW_GENESIS_BITS: Optional[int] = None
@classmethod @classmethod
def max_checkpoint(cls) -> int: def max_checkpoint(cls) -> int:
return max(0, len(cls.CHECKPOINTS) * 2016 - 1) return max(0, len(cls.CHECKPOINTS) * 2016 - 1)
@@ -259,6 +269,81 @@ class BitcoinMutinynet(BitcoinTestnet):
LN_DNS_SEEDS = [] LN_DNS_SEEDS = []
class BitcoinPurple(AbstractNet):
NET_NAME = "bitcoinpurple"
TESTNET = False
WIF_PREFIX = 0xb7
ADDRTYPE_P2PKH = 56
ADDRTYPE_P2SH = 55
SEGWIT_HRP = "btcp"
BOLT11_HRP = SEGWIT_HRP
GENESIS = "000003823fbf82ea4906cbe214617ce7a70a5da29c19ecb1d65618bcf04ec015"
DEFAULT_PORTS = {'t': '50001', 's': '50002'}
BLOCK_HEIGHT_FIRST_LIGHTNING_CHANNELS = 0
XPRV_HEADERS = {
'standard': 0x0488ade4, # xprv
'p2wpkh-p2sh': 0x049d7878, # yprv
'p2wsh-p2sh': 0x0295b005, # Yprv
'p2wpkh': 0x04b2430c, # zprv
'p2wsh': 0x02aa7a99, # Zprv
}
XPRV_HEADERS_INV = inv_dict(XPRV_HEADERS)
XPUB_HEADERS = {
'standard': 0x0488b21e, # xpub
'p2wpkh-p2sh': 0x049d7cb2, # ypub
'p2wsh-p2sh': 0x0295b43f, # Ypub
'p2wpkh': 0x04b24746, # zpub
'p2wsh': 0x02aa7ed3, # Zpub
}
XPUB_HEADERS_INV = inv_dict(XPUB_HEADERS)
# Provisional BIP44 coin type (not SLIP-0044 registered; matches BTCP P2P port)
BIP44_COIN_TYPE = 13496
LN_REALM_BYTE = 0
LN_DNS_SEEDS = []
# BTCP retargets every 120 blocks with a 7200-second target timespan
DIFFICULTY_ADJUSTMENT_INTERVAL = 120
POW_TARGET_TIMESPAN = 7200 # 120 * 60 seconds
# powLimit: absolute upper bound for any target (compact 0x1e0fffff)
MAX_TARGET = 0x00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
MAX_ADJUSTMENT_FACTOR = 4
# Genesis nBits is 0x1e0ffff0, which is stricter than powLimit (0x1e0fffff).
# Period-0 blocks must carry this exact bits value, so we record it here.
POW_GENESIS_BITS = 0x1e0ffff0
class BitcoinPurpleTestnet(BitcoinPurple):
NET_NAME = "bitcoinpurple_testnet"
TESTNET = True
SEGWIT_HRP = "tbtcp"
BOLT11_HRP = SEGWIT_HRP
GENESIS = "000002fdc3921c1ad368816fcc587f499698d42b42ab5a5d94ee67882ef9d998"
DEFAULT_PORTS = {'t': '60001', 's': '60002'}
BIP44_COIN_TYPE = 1
LN_REALM_BYTE = 1
XPRV_HEADERS = {
'standard': 0x04358394, # tprv
'p2wpkh-p2sh': 0x044a4e28, # uprv
'p2wsh-p2sh': 0x024285b5, # Uprv
'p2wpkh': 0x045f18bc, # vprv
'p2wsh': 0x02575048, # Vprv
}
XPRV_HEADERS_INV = inv_dict(XPRV_HEADERS)
XPUB_HEADERS = {
'standard': 0x043587cf, # tpub
'p2wpkh-p2sh': 0x044a5262, # upub
'p2wsh-p2sh': 0x024289ef, # Upub
'p2wpkh': 0x045f1cf6, # vpub
'p2wsh': 0x02575483, # Vpub
}
XPUB_HEADERS_INV = inv_dict(XPUB_HEADERS)
NETS_LIST = tuple(all_subclasses(AbstractNet)) # type: Sequence[Type[AbstractNet]] NETS_LIST = tuple(all_subclasses(AbstractNet)) # type: Sequence[Type[AbstractNet]]
NETS_LIST = tuple(sorted(NETS_LIST, key=lambda x: x.NET_NAME)) NETS_LIST = tuple(sorted(NETS_LIST, key=lambda x: x.NET_NAME))