#!/usr/bin/env python3 # Copyright (c) 2026 The Limenka developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Blukecoin (bitcoin-blake2b) node detection and gossip. A blukecoin node keeps the parent chain's P2P identity (magic, port, genesis) but hashes block headers with blake2b, so a header it transmits fails SHA256d proof of work while claiming a valid mainnet-range difficulty. This test connects a crafted peer that sends exactly such a header, verifies the node tags it (getpeerinfo blukecoin=true), records it in the runtime database (getblukecoinpeers) and gossips the address to a second node via the BLUKECOIN message. """ import hashlib from test_framework.address import byte_to_base58 from test_framework.descriptors import descsum_create from test_framework.key import ECKey from test_framework.messages import CBlockHeader, msg_headers from test_framework.p2p import P2PInterface from test_framework.test_framework import LimenkaTestFramework from test_framework.util import p2p_port ACTIVATION_FAR = 1999999999 GENESIS_TIME = 1231006505 # A header with the mainnet powLimit difficulty whose SHA256d hash does # not meet the target - the blake2b-chain signature. Any random header at # this difficulty fails SHA256d PoW with overwhelming probability. def blake2b_style_header(): h = CBlockHeader() h.nVersion = 0x20000000 h.nTime = 1500000000 h.nBits = 0x1d00ffff h.nNonce = 1 return h class BlukecoinInterface(P2PInterface): def __init__(self): super().__init__() self.blukecoin_seen = False def on_blukecoin(self, message): self.blukecoin_seen = True class ForkBlukecoinTest(LimenkaTestFramework): def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 2 self.chain = 'limenka' self.extra_args = [[ '-forkactivationtime=%d' % ACTIVATION_FAR, '-forkdelaysteps=1024', '-forkmineondemand', '-forkstandalone', '-fallbackfee=0.0002', '-addresstype=bech32', ]] * self.num_nodes self.rpc_timeout = 240 def skip_test_if_missing_module(self): self.skip_if_no_wallet() def add_options(self, parser): self.add_wallet_options(parser, descriptors=True, legacy=False) def init_wallet(self, *, node): wallet_name = self.default_wallet_name if self.wallet_names is None else self.wallet_names[node] if node < len(self.wallet_names) else False if wallet_name is not False: n = self.nodes[node] if wallet_name is not None and node == 0: n.createwallet(wallet_name=wallet_name, descriptors=True, load_on_startup=True) seed = hashlib.sha256(b'fork-blukecoin-funding').digest() key = ECKey() key.set(seed, compressed=True) priv = key.get_bytes() wif = byte_to_base58(priv + b'\x01', 128) desc = descsum_create(f"wpkh({wif})") import_res = n.importdescriptors([{ "desc": desc, "timestamp": GENESIS_TIME + 600, "active": False, "internal": False, }]) assert all(r['success'] for r in import_res) def run_test(self): node_a = self.nodes[0] node_b = self.nodes[1] # A peer that transmits blake2b-style headers (valid difficulty, # SHA256d hash fails) connects to node A. blukecoin_peer = node_a.add_p2p_connection(BlukecoinInterface()) # Send the offending header. blukecoin_peer.send_message(msg_headers([blake2b_style_header()])) # Node A must tag the peer as blukecoin and record it in the DB. self.wait_until(lambda: any( p.get('blukecoin') for p in node_a.getpeerinfo())) self.wait_until(lambda: len(node_a.getblukecoinpeers()) >= 1) detected = node_a.getblukecoinpeers() self.log.info('Node A detected blukecoin peers: %s' % detected) assert len(detected) >= 1 assert any(p.get('blukecoin') for p in node_a.getpeerinfo()) # Connect the second fork node so the detection can be gossiped. node_a.addnode(f'127.0.0.1:{p2p_port(1)}', 'onetry') self.wait_until(lambda: len(node_a.getblukecoinpeers()) >= 1) # The address must be gossiped to node B via the BLUKECOIN message. self.wait_until(lambda: len(node_b.getblukecoinpeers()) >= 1) self.log.info('Node B learned blukecoin peers: %s' % node_b.getblukecoinpeers()) assert len(node_b.getblukecoinpeers()) >= 1 if __name__ == '__main__': ForkBlukecoinTest(__file__).main()